summaryrefslogtreecommitdiff
path: root/libs/cpp-httplib/test
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrikboy@gmail.com>2025-09-27 18:38:35 +0200
committerAldrik Ramaekers <aldrikboy@gmail.com>2025-09-27 18:38:35 +0200
commitd8c4d84dc75300c6d4d8b0adceafa33741960b92 (patch)
tree00e2dfcc5c836d62fccff76c862e6ec3b0a74db8 /libs/cpp-httplib/test
parentfa088bb60692ba02d30d39affa9a31d9e2b688e2 (diff)
added http lib, working on AI invoice importing
Diffstat (limited to 'libs/cpp-httplib/test')
-rw-r--r--libs/cpp-httplib/test/CMakeLists.txt121
-rw-r--r--libs/cpp-httplib/test/Makefile132
-rw-r--r--libs/cpp-httplib/test/ca-bundle.crt3401
-rw-r--r--libs/cpp-httplib/test/fuzzing/CMakeLists.txt10
-rw-r--r--libs/cpp-httplib/test/fuzzing/Makefile27
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/11
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/25
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/3bin0 -> 54 bytes
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5042094968537088bin0 -> 516575 bytes
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5372331946541056bin0 -> 1041826 bytes
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5386708825800704bin0 -> 787294 bytes
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5667822731132928bin0 -> 317 bytes
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5886572146327552bin0 -> 974479 bytes
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5942767436562432bin0 -> 395 bytes
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-6007379124158464bin0 -> 452123 bytes
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-65087066725416967
-rw-r--r--libs/cpp-httplib/test/fuzzing/corpus/issue126419
-rw-r--r--libs/cpp-httplib/test/fuzzing/server_fuzzer.cc100
-rw-r--r--libs/cpp-httplib/test/fuzzing/server_fuzzer.dict224
-rw-r--r--libs/cpp-httplib/test/fuzzing/standalone_fuzz_target_runner.cpp35
-rw-r--r--libs/cpp-httplib/test/gen-certs.sh18
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-assertion-result.h237
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-death-test.h345
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-matchers.h956
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-message.h218
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-param-test.h510
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-printers.h1048
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-spi.h248
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-test-part.h190
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest-typed-test.h331
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest.h2297
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest_pred_impl.h279
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/gtest_prod.h60
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/custom/README.md44
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest-port.h37
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest-printers.h42
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest.h37
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-death-test-internal.h306
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-filepath.h210
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-internal.h1570
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-param-util.h956
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-port-arch.h116
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-port.h2413
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-string.h177
-rw-r--r--libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-type-util.h186
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-all.cc49
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-assertion-result.cc77
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-death-test.cc1620
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-filepath.cc367
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-internal-inl.h1212
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-matchers.cc98
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-port.cc1394
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-printers.cc553
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-test-part.cc105
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest-typed-test.cc104
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest.cc6795
-rw-r--r--libs/cpp-httplib/test/gtest/src/gtest_main.cc53
-rw-r--r--libs/cpp-httplib/test/image.jpgbin0 -> 33653 bytes
-rw-r--r--libs/cpp-httplib/test/include_httplib.cc5
-rw-r--r--libs/cpp-httplib/test/include_windows_h.cc6
-rw-r--r--libs/cpp-httplib/test/make-shared-library.sh28
-rw-r--r--libs/cpp-httplib/test/meson.build146
-rw-r--r--libs/cpp-httplib/test/proxy/Dockerfile13
-rw-r--r--libs/cpp-httplib/test/proxy/basic_passwd1
-rw-r--r--libs/cpp-httplib/test/proxy/basic_squid.conf81
-rw-r--r--libs/cpp-httplib/test/proxy/digest_passwd1
-rw-r--r--libs/cpp-httplib/test/proxy/digest_squid.conf81
-rw-r--r--libs/cpp-httplib/test/proxy/docker-compose.yml20
-rw-r--r--libs/cpp-httplib/test/test.cc10830
-rw-r--r--libs/cpp-httplib/test/test.conf21
-rw-r--r--libs/cpp-httplib/test/test.rootCA.conf18
-rw-r--r--libs/cpp-httplib/test/test.sln28
-rw-r--r--libs/cpp-httplib/test/test.vcxproj180
-rw-r--r--libs/cpp-httplib/test/test_proxy.cc297
-rw-r--r--libs/cpp-httplib/test/www/dir/1MB.txt8192
-rw-r--r--libs/cpp-httplib/test/www/dir/index.html8
-rw-r--r--libs/cpp-httplib/test/www/dir/meson.build8
-rw-r--r--libs/cpp-httplib/test/www/dir/test.abcde1
-rw-r--r--libs/cpp-httplib/test/www/dir/test.html1
-rw-r--r--libs/cpp-httplib/test/www/empty_file0
-rw-r--r--libs/cpp-httplib/test/www/file1
-rw-r--r--libs/cpp-httplib/test/www/meson.build8
-rw-r--r--libs/cpp-httplib/test/www/日本語Dir/meson.build4
-rw-r--r--libs/cpp-httplib/test/www/日本語Dir/日本語File.txt1
-rw-r--r--libs/cpp-httplib/test/www2/dir/index.html8
-rw-r--r--libs/cpp-httplib/test/www2/dir/meson.build6
-rw-r--r--libs/cpp-httplib/test/www2/dir/test.html1
-rw-r--r--libs/cpp-httplib/test/www3/dir/index.html8
-rw-r--r--libs/cpp-httplib/test/www3/dir/meson.build6
-rw-r--r--libs/cpp-httplib/test/www3/dir/test.html1
90 files changed, 49350 insertions, 0 deletions
diff --git a/libs/cpp-httplib/test/CMakeLists.txt b/libs/cpp-httplib/test/CMakeLists.txt
new file mode 100644
index 0000000..d4e684c
--- /dev/null
+++ b/libs/cpp-httplib/test/CMakeLists.txt
@@ -0,0 +1,121 @@
+find_package(GTest)
+
+if(GTest_FOUND)
+ if(NOT TARGET GTest::gtest_main AND TARGET GTest::Main)
+ # CMake <3.20
+ add_library(GTest::gtest_main INTERFACE IMPORTED)
+ target_link_libraries(GTest::gtest_main INTERFACE GTest::Main)
+ endif()
+else()
+ if(POLICY CMP0135)
+ cmake_policy(SET CMP0135 NEW)
+ endif()
+
+ include(FetchContent)
+
+ set(BUILD_GMOCK OFF)
+ set(INSTALL_GTEST OFF)
+ set(gtest_force_shared_crt ON)
+
+ FetchContent_Declare(
+ gtest
+ URL https://github.com/google/googletest/archive/main.tar.gz
+ )
+ FetchContent_MakeAvailable(gtest)
+endif()
+
+find_package(CURL REQUIRED)
+
+add_executable(httplib-test test.cc include_httplib.cc $<$<BOOL:${WIN32}>:include_windows_h.cc>)
+target_compile_options(httplib-test PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8;/bigobj>")
+target_link_libraries(httplib-test PRIVATE httplib GTest::gtest_main CURL::libcurl)
+gtest_discover_tests(httplib-test)
+
+file(
+ COPY www www2 www3 ca-bundle.crt image.jpg
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+if(HTTPLIB_IS_USING_OPENSSL)
+ if (OPENSSL_VERSION VERSION_LESS "3.2.0")
+ set(OPENSSL_X509_FLAG "-x509")
+ else()
+ set(OPENSSL_X509_FLAG "-x509v1")
+ endif()
+ find_program(OPENSSL_COMMAND
+ NAMES openssl
+ PATHS ${OPENSSL_INCLUDE_DIR}/../bin
+ REQUIRED
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} genrsa 2048
+ OUTPUT_FILE key.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} req -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key.pem
+ COMMAND ${OPENSSL_COMMAND} x509 -days 3650 -req -signkey key.pem
+ OUTPUT_FILE cert.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} req ${OPENSSL_X509_FLAG} -new -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} genrsa 2048
+ OUTPUT_FILE rootCA.key.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} req ${OPENSSL_X509_FLAG} -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.rootCA.conf -key rootCA.key.pem -days 1024
+ OUTPUT_FILE rootCA.cert.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} genrsa 2048
+ OUTPUT_FILE client.key.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} req -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key client.key.pem
+ COMMAND ${OPENSSL_COMMAND} x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial
+ OUTPUT_FILE client.cert.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} genrsa -passout pass:test123! 2048
+ OUTPUT_FILE key_encrypted.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} req -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key_encrypted.pem
+ COMMAND ${OPENSSL_COMMAND} x509 -days 3650 -req -signkey key_encrypted.pem
+ OUTPUT_FILE cert_encrypted.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} genrsa -aes256 -passout pass:test012! 2048
+ OUTPUT_FILE client_encrypted.key.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(
+ COMMAND ${OPENSSL_COMMAND} req -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key client_encrypted.key.pem -passin pass:test012!
+ COMMAND ${OPENSSL_COMMAND} x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial
+ OUTPUT_FILE client_encrypted.cert.pem
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+endif()
+
+add_subdirectory(fuzzing)
diff --git a/libs/cpp-httplib/test/Makefile b/libs/cpp-httplib/test/Makefile
new file mode 100644
index 0000000..900cb56
--- /dev/null
+++ b/libs/cpp-httplib/test/Makefile
@@ -0,0 +1,132 @@
+CXX = clang++
+CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion -Wshadow $(EXTRA_CXXFLAGS) -DCPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
+
+PREFIX ?= $(shell brew --prefix)
+
+OPENSSL_DIR = $(PREFIX)/opt/openssl@3
+OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
+
+ifneq ($(OS), Windows_NT)
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S), Darwin)
+ OPENSSL_SUPPORT += -DCPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN -framework Security
+ endif
+endif
+
+ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
+
+BROTLI_DIR = $(PREFIX)/opt/brotli
+BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
+
+ZSTD_DIR = $(PREFIX)/opt/zstd
+ZSTD_SUPPORT = -DCPPHTTPLIB_ZSTD_SUPPORT -I$(ZSTD_DIR)/include -L$(ZSTD_DIR)/lib -lzstd
+
+LIBS = -lpthread -lcurl
+ifneq ($(OS), Windows_NT)
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S), Darwin)
+ LIBS += -framework CoreFoundation -framework CFNetwork
+ endif
+ ifneq ($(UNAME_S), Darwin)
+ LIBS += -lanl
+ endif
+endif
+
+TEST_ARGS = gtest/src/gtest-all.cc gtest/src/gtest_main.cc -Igtest -Igtest/include $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) $(ZSTD_SUPPORT) $(LIBS)
+
+# By default, use standalone_fuzz_target_runner.
+# This runner does no fuzzing, but simply executes the inputs
+# provided via parameters.
+# Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a"
+# to link the fuzzer(s) against a real fuzzing engine.
+# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
+LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
+
+CLANG_FORMAT = clang-format
+REALPATH = $(shell which grealpath 2>/dev/null || which realpath 2>/dev/null)
+STYLE_CHECK_FILES = $(filter-out httplib.h httplib.cc, \
+ $(wildcard example/*.h example/*.cc fuzzing/*.h fuzzing/*.cc *.h *.cc ../httplib.h))
+
+all : test test_split
+ ./test
+
+proxy : test_proxy
+ @echo "Starting proxy server..."
+ cd proxy && \
+ docker compose up -d
+ @echo "Waiting for proxy to be ready..."
+ @until nc -z localhost 3128 && nc -z localhost 3129; do sleep 1; done
+ @echo "Proxy servers are ready, waiting additional 5 seconds for full startup..."
+ @sleep 5
+ @echo "Checking proxy server status..."
+ @cd proxy && docker compose ps
+ @echo "Checking proxy server logs..."
+ @cd proxy && docker compose logs --tail=20
+ @echo "Running proxy tests..."
+ ./test_proxy; \
+ exit_code=$$?; \
+ echo "Stopping proxy server..."; \
+ cd proxy && docker compose down; \
+ exit $$exit_code
+
+test : test.cc include_httplib.cc ../httplib.h Makefile cert.pem
+ $(CXX) -o $@ -I.. $(CXXFLAGS) test.cc include_httplib.cc $(TEST_ARGS)
+ @file $@
+
+# Note: The intention of test_split is to verify that it works to compile and
+# link the split httplib.h, so there is normally no need to execute it.
+test_split : test.cc ../httplib.h httplib.cc Makefile cert.pem
+ $(CXX) -o $@ $(CXXFLAGS) test.cc httplib.cc $(TEST_ARGS)
+
+check_abi:
+ @./check-shared-library-abi-compatibility.sh
+
+.PHONY: style_check
+style_check: $(STYLE_CHECK_FILES)
+ @for file in $(STYLE_CHECK_FILES); do \
+ $(CLANG_FORMAT) $$file > $$file.formatted; \
+ if ! diff -u $$file $$file.formatted; then \
+ file2=$$($(REALPATH) --relative-to=.. $$file); \
+ printf "\n%*s\n" 80 | tr ' ' '#'; \
+ printf "##%*s##\n" 76; \
+ printf "## %-70s ##\n" "$$file2 not properly formatted. Please run clang-format."; \
+ printf "##%*s##\n" 76; \
+ printf "%*s\n\n" 80 | tr ' ' '#'; \
+ failed=1; \
+ fi; \
+ rm -f $$file.formatted; \
+ done; \
+ if [ -n "$$failed" ]; then \
+ echo "Style check failed for one or more files. See above for details."; \
+ false; \
+ else \
+ echo "All files are properly formatted."; \
+ fi
+
+test_proxy : test_proxy.cc ../httplib.h Makefile cert.pem
+ $(CXX) -o $@ -I.. $(CXXFLAGS) test_proxy.cc $(TEST_ARGS)
+
+# Runs server_fuzzer.cc based on value of $(LIB_FUZZING_ENGINE).
+# Usage: make fuzz_test LIB_FUZZING_ENGINE=/path/to/libFuzzer
+fuzz_test: server_fuzzer
+ ./server_fuzzer fuzzing/corpus/*
+
+# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
+server_fuzzer : fuzzing/server_fuzzer.cc ../httplib.h standalone_fuzz_target_runner.o
+ $(CXX) -o $@ -I.. $(CXXFLAGS) $< $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) $(LIB_FUZZING_ENGINE) $(ZSTD_SUPPORT) $(LIBS)
+ @file $@
+
+# Standalone fuzz runner, which just reads inputs from fuzzing/corpus/ dir and
+# feeds it to server_fuzzer.
+standalone_fuzz_target_runner.o : fuzzing/standalone_fuzz_target_runner.cpp
+ $(CXX) -o $@ -I.. $(CXXFLAGS) -c $<
+
+httplib.cc : ../httplib.h
+ python3 ../split.py -o .
+
+cert.pem:
+ ./gen-certs.sh
+
+clean:
+ rm -rf test test_split test_proxy server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc _build* *.dSYM
+
diff --git a/libs/cpp-httplib/test/ca-bundle.crt b/libs/cpp-httplib/test/ca-bundle.crt
new file mode 100644
index 0000000..7d61eb5
--- /dev/null
+++ b/libs/cpp-httplib/test/ca-bundle.crt
@@ -0,0 +1,3401 @@
+##
+## Bundle of CA Root Certificates
+##
+## Certificate data from Mozilla as of: Tue Jan 22 14:14:40 2019 GMT
+##
+## This is a bundle of X.509 certificates of public Certificate Authorities
+## (CA). These were automatically extracted from Mozilla's root certificates
+## file (certdata.txt). This file can be found in the mozilla source tree:
+## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
+##
+## It contains the certificates in PEM format and therefore
+## can be directly used with curl / libcurl / php_curl, or with
+## an Apache+mod_ssl webserver for SSL client authentication.
+## Just configure this file as the SSLCACertificateFile.
+##
+## Conversion done with mk-ca-bundle.pl version 1.27.
+## SHA256: 18372117493b5b7ec006c31d966143fc95a9464a2b5f8d5188e23c5557b2292d
+##
+
+
+GlobalSign Root CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
+GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
+b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
+BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
+VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
+DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
+THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
+Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
+c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
+gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
+AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
+Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
+j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
+hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
+X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
+ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
+s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
+S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
+TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
+ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
+YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
+BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
+9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
+01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
+9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1
+EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc
+cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw
+EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj
+055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
+j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0
+xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
+t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+Entrust.net Premium 2048 Secure Server CA
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
+ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
+bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
+NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
+d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
+ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
+Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
+hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
+nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
+VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
+KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
+T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
+J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
+nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
+-----END CERTIFICATE-----
+
+Baltimore CyberTrust Root
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
+ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
+ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
+SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
+dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
+uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
+UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
+G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
+XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
+l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
+VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
+BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
+cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
+hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
+Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
+RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+AddTrust External Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD
+VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw
+NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU
+cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg
+Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821
++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw
+Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo
+aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy
+2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7
+7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL
+VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk
+VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
+j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355
+e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
+G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
+BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
+b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
+A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
+MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
+MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
+Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
+dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
+A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
+Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
+j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
+rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
+MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
+hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
+Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
+v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
+W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
+tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+
+GeoTrust Global CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
+MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
+BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
+8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
+T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
+vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
+DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
+zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
+d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
+mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
+XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
+Mw==
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
+MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
+Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
+JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
+RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
+7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
+8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
+qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
+Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
+Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
+KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
+ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
+XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
+hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
+qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
+oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
+xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
+KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
+DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
+xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
+p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
+P/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA 2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
+MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
+SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
+DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
+j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
+JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
+QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
+WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
+20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
+ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
+SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
+8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
+BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
+4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
+A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
+Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
+pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
+FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
+gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
+X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+Comodo AAA Services root
+========================
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
+MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
+c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
+BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
+C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
+i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
+Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
+Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
+Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
+BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
+cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
+LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
+7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
+8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
+12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+QuoVadis Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
+ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
+MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
+cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
+EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
+J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
+F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
+YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
+AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
+PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
+ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
+MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
+YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
+ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
+Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
+BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
+FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
+tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
+fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
+LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
+gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
+5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
+5nrQNiOKSnQ2+Q==
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx
+ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6
+XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk
+lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB
+lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy
+lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt
+66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn
+wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh
+D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy
+BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie
+J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud
+DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
+a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv
+Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3
+UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm
+VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK
++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW
+IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1
+WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X
+f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II
+4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8
+VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 3
+==================
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
+OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
+DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
+KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
+DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
+BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
+p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
+nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
+MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
+Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
+uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
+BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
+YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
+BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
+VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
+ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
+AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
+qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
+hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
+POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
+Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
+8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
+bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
+g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
+vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
+qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+
+Security Communication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
+8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
+DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
+5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
+DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
+JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
+0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
+mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
+s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
+6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
+FL39vmwLAw==
+-----END CERTIFICATE-----
+
+Sonera Class 2 Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
+U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
+NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
+IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
+/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
+dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
+f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
+tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
+nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
+XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
+0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
+cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
+Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
+EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
+llpwrN9M
+-----END CERTIFICATE-----
+
+XRamp Global CA Root
+====================
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
+BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
+dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
+HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
+U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
+IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
+foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
+zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
+AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
+xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
+oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
+AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
+/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
+nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
+8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+Go Daddy Class 2 CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
+VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
+A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
+RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
+ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
+2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
+qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
+YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
+vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
+BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
+atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
+MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
+PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
+I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
+Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
+vZ8=
+-----END CERTIFICATE-----
+
+Starfield Class 2 CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
+U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
+MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
+A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
+SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
+bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
+JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
+epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
+F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
+MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
+hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
+bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
+afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
+PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
+KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
+QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+Taiwan GRCA
+===========
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG
+EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X
+DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv
+dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN
+w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5
+BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O
+1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO
+htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov
+J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7
+Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t
+B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB
+O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8
+lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV
+HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2
+09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj
+Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2
+Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU
+D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz
+DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk
+Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk
+7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ
+CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy
++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
+MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
+9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
+UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
+/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
+oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
+GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
+66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
+hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
+EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
+SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
+8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+DigiCert Global Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
+MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
+TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
+BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
+4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
+7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
+o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
+8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
+BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
+EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
+tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
+UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+DigiCert High Assurance EV Root CA
+==================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
+KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
+MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
+MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
+Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
+Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
+OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
+MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
+NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
+h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
+Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
+JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
+V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
+myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
+mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
+-----END CERTIFICATE-----
+
+Certplus Class 2 Primary CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE
+BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN
+OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy
+dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR
+5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ
+Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO
+YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e
+e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME
+CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ
+YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t
+L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD
+P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R
+TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+
+7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW
+//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
+
+DST Root CA X3
+==============
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
+ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
+DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
+cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
+rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
+UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
+xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
+utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
+MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
+dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
+GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
+RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
+fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+
+SwissSign Gold CA - G2
+======================
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw
+EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN
+MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp
+c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq
+t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C
+jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg
+vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF
+ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR
+AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend
+jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO
+peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR
+7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi
+GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
+OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm
+5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr
+44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf
+Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m
+Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp
+mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk
+vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf
+KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br
+NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
+viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
+
+SwissSign Silver CA - G2
+========================
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT
+BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X
+DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3
+aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644
+N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm
++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH
+6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu
+MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h
+qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5
+FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs
+ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc
+celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X
+CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
+tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P
+4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F
+kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L
+3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx
+/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa
+DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP
+e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu
+WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ
+DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub
+DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
+CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
+cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
+b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
+nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
+RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
+tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
+hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
+Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
+NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
+Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
+1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+
+thawte Primary Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
+MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
+SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
+KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
+FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
+oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
+1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
+q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
+aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
+afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
+AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
+uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
+jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
+z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G5
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
+biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
+dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
+j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
+Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
+Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
+fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
+Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
+SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
+KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
+Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
+ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+SecureTrust CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
+dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
+BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
+OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
+DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
+GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
+01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
+ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
+aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
+SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
+mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
+nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+
+Secure Global CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
+bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
+MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
+Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
+YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
+bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
+8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
+HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
+0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
+oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
+MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
+CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
+3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+
+COMODO Certification Authority
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
+MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
+T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
+xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
+4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
+1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
+rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
+AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
+OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
+IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
+-----END CERTIFICATE-----
+
+Network Solutions Certificate Authority
+=======================================
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
+EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
+IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
+MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
+jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
+aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
+crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
+/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
+AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
+bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
+A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
+4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
+GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
+ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+
+COMODO ECC Certification Authority
+==================================
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
+GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
+4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
+wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
+FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
+U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GA CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE
+BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG
+A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH
+bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD
+VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw
+IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5
+IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9
+Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg
+Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD
+d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ
+/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R
+LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm
+MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4
++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY
+okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
+-----END CERTIFICATE-----
+
+Certigna
+========
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
+EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
+MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
+Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
+XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
+GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
+ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
+DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
+Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
+tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
+BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
+SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
+hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
+PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
+1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
+-----END CERTIFICATE-----
+
+Deutsche Telekom Root CA 2
+==========================
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT
+RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG
+A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5
+MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G
+A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS
+b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5
+bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI
+KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY
+AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK
+Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV
+jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV
+HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr
+E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy
+zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8
+rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G
+dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
+Cm26OWMohpLzGITY+9HPBVZkVw==
+-----END CERTIFICATE-----
+
+Cybertrust Global Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
+ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
+MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
+ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
+0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
+AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
+89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
+8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
+MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
+A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
+lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
+5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
+hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
+X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
+WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+-----END CERTIFICATE-----
+
+ePKI Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
+EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
+MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
+MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
+IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
+lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
+qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
+12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
+WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
+lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
+vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
+Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
+MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
+1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
+KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
+xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
+NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
+GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
+xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
+gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
+sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
+BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
+-----END CERTIFICATE-----
+
+certSIGN ROOT CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
+VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
+Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
+CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
+JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
+rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
+ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
+0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
+AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
+AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
+SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
+x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
+vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
+TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G3
+=============================================
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
+NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
+YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
+LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
+K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
+c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
+IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
+dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
+2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
+cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
+Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
+t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G2
+===========================
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
+VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
+IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
+Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
+MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
+b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
+IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
+LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
+8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
+mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
+G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
+rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
+ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
+VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
+A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
+P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
+7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
+vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
+KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
+A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
+8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
+er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G2
+=============================================
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
+OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
+b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
+BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
+KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
+EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
+ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
+npaqBA+K
+-----END CERTIFICATE-----
+
+VeriSign Universal Root Certification Authority
+===============================================
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
+IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
+1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
+MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
+9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
+AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
+tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
+CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
+a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
+Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
+Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
+P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
+wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
+mJO37M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G4
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
+VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
+b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
+ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
+cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
+b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
+Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
+rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
+HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
+Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
+A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
+AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+
+NetLock Arany (Class Gold) Főtanúsítvány
+========================================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
+A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
+dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
+cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
+MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
+ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
+c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
+0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
+/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
+H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
+fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
+neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
+qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
+YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
+NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
+dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA - G2
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC
+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ
+5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn
+vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj
+CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil
+e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR
+OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI
+CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65
+48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi
+trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737
+qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB
+AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC
+ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA
+A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz
++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj
+f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN
+kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk
+CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF
+URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb
+CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h
+oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV
+IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm
+66+KAQ==
+-----END CERTIFICATE-----
+
+Hongkong Post Root CA 1
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
+DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
+NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
+IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
+ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
+auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
+qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
+V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
+HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
+h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
+l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
+IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
+T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
+c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
+-----END CERTIFICATE-----
+
+SecureSign RootCA11
+===================
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
+SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
+b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
+KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
+cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
+TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
+wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
+g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
+O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
+bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
+t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
+OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
+bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
+Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
+y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
+lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
+MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
+c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
+dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
+BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
+U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
+fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
+0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
+pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
+1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
+AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
+QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
+FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
+lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
+I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
+yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
+LXpUq3DDfSJlgnCW
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R3
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
+iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
+0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
+rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
+OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
+xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
+lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
+EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
+bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
+YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
+kpeDMdmztcpHWD9f
+-----END CERTIFICATE-----
+
+Autoridad de Certificacion Firmaprofesional CIF A62634068
+=========================================================
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
+BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
+QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
+NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
+Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
+B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
+7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
+ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
+plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
+MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
+LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
+bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
+vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
+EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
+DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
+bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
+ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
+51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
+R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
+T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
+Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
+osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
+crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
+saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
+KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
+6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+-----END CERTIFICATE-----
+
+Izenpe.com
+==========
+-----BEGIN CERTIFICATE-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
+EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
+MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
+QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
+03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
+ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
+PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
+OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
+F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
+0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
+leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
+AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
+SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
+NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
+BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
+Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
+kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
+hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
+g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
+aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
+nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
+ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
+Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
+WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
+-----END CERTIFICATE-----
+
+Chambers of Commerce Root - 2008
+================================
+-----BEGIN CERTIFICATE-----
+MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
+Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
+ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
+EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
+cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
+XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
+h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
+ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
+NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
+D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
+lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
+0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
+ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
+EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
+G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
+BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
+bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
+bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
+CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
+AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
+wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
+3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
+RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
+M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
+YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
+9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
+zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
+nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
+OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
+-----END CERTIFICATE-----
+
+Global Chambersign Root - 2008
+==============================
+-----BEGIN CERTIFICATE-----
+MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
+NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
+Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
+QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
+aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
+VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
+XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
+ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
+/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
+TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
+H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
+Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
+HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
+wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
+AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
+BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
+BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
+aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
+aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
+1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
+dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
+/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
+ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
+dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
+9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
+foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
+qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
+P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
+c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
+09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
+-----END CERTIFICATE-----
+
+Go Daddy Root Certificate Authority - G2
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
+MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
+A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
+9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
+fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
+NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
+BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
+vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
+5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
+N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
+-----END CERTIFICATE-----
+
+Starfield Root Certificate Authority - G2
+=========================================
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
+eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
+DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
+VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
+W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
+bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
+N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
+ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
+JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
+TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
+4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
+F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
+c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+
+Starfield Services Root Certificate Authority - G2
+==================================================
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
+IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
+dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
+h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
+hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
+LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
+rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
+SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
+E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
+xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
+YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
+-----END CERTIFICATE-----
+
+AffirmTrust Commercial
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
+MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
+DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
+C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
+BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
+MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
+HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
+hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
+qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
+0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
+sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+
+AffirmTrust Networking
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
+MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
+Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
+dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
+/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
+h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
+HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
+UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
+12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
+WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
+/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+
+AffirmTrust Premium
+===================
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
+OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
+dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
+BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
+5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
+GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
+p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
+S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
+6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
+/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
+MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
+6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
+L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
+BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
+IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
+g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
+zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+
+AffirmTrust Premium ECC
+=======================
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
+BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
+MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
+cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
+N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
+BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
+BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
+57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
+eQ==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
+ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
+MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
+ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
+l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
+J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
+fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
+cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
+Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
+DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
+jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
+mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
+Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+
+TWCA Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
+VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
+EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
+IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
+QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
+oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
+4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
+y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
+9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
+mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
+QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
+T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
+Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
+-----END CERTIFICATE-----
+
+Security Communication RootCA2
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
+SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
+aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
+3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
+spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
+EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
+QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
+u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
+3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
+tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
+mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+
+EC-ACC
+======
+-----BEGIN CERTIFICATE-----
+MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
+BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
+ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
+VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
+CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
+BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
+MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
+SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
+Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
+cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
+w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
+ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
+HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
+E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
+0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
+VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
+Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
+dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
+lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
+Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
+l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
+E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
+5EI=
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2011
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
+O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
+aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
+AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
+IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
+1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
+71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
+8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
+3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
+MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
+b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
+XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
+TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
+/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
+7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
+-----END CERTIFICATE-----
+
+Actalis Authentication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
+BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
+AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
+MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
+IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
+IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
+wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
+by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
+zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
+YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
+oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
+EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
+hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
+EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
+jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
+iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
+WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
+JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
+K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
+Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
+4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
+2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
+lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
+OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
+vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
+-----END CERTIFICATE-----
+
+Trustis FPS Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
+EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
+IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
+BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
+RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
+H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
+cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
+o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
+AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
+BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
+GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
+yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
+8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
+l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
+iB6XzCGcKQENZetX2fNXlrtIzYE=
+-----END CERTIFICATE-----
+
+Buypass Class 2 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
+DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
+g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
+9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
+/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
+CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
+awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
+zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
+Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
+Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
+M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
+osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
+aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
+DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
+LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
+oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
+wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
+CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
+rJgWVqA=
+-----END CERTIFICATE-----
+
+Buypass Class 3 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
+DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
+sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
+5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
+7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
+ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
+2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
+/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
+RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
+Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
+j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
+uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
+Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
+ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
+KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
+6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
+UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
+eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
+Cp/HuZc=
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 3
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
+MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
+9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
+NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
+iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
+0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
+AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
+fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
+ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
+P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
+-----END CERTIFICATE-----
+
+EE Certification Centre Root CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
+EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy
+dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw
+MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB
+UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy
+ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM
+TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2
+rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw
+93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN
+P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ
+MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF
+BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj
+xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM
+lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU
+3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM
+dcGWxZ0=
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
+Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
+LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
+ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
+BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
+KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
+p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
+AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
+4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
+eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
+MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
+PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
+OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
+2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
+o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
+dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
+X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 EV 2009
+=================================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
+egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
+zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
+7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
+sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
+11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
+cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
+ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
+MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
+b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
+c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
+PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
+nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
+ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
+NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
+w9y4AyHqnxbxLFS1
+-----END CERTIFICATE-----
+
+CA Disig Root R2
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
+w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
+xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
+A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
+GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
+g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
+5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
+koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
+Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
+Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
+Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
+tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
+sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
+dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
+1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
+mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
+utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
+sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
+UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
+7+ZtsH8tZ/3zbBt1RqPlShfppNcL
+-----END CERTIFICATE-----
+
+ACCVRAIZ1
+=========
+-----BEGIN CERTIFICATE-----
+MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
+SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
+MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
+UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
+jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
+RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
+aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
+0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
+WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
+8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
+5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
+9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
+Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
+Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
+Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
+VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
+Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
+QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
+AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
+YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
+AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
+IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
+aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
+dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
+MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
+hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
+R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
+YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
+nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
+TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
+sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
+I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
+Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
+3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
+EfbRD0tVNEYqi4Y7
+-----END CERTIFICATE-----
+
+TWCA Global Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
+CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
+QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
+EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
+Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
+nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
+r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
+Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
+tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
+KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
+sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
+yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
+kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
+zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
+cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
+LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
+8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
+/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
+lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
+A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
+i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
+EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
+zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
+-----END CERTIFICATE-----
+
+TeliaSonera Root CA v1
+======================
+-----BEGIN CERTIFICATE-----
+MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
+CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
+MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
+VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
+6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
+3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
+B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
+Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
+oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
+F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
+oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
+gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
+TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
+AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
+DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
+zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
+0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
+pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
+G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
+c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
+JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
+qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
+Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
+WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
+-----END CERTIFICATE-----
+
+E-Tugra Certification Authority
+===============================
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w
+DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls
+ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
+ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw
+NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx
+QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl
+cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD
+DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd
+hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K
+CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g
+ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ
+BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0
+E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz
+rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq
+jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
+rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5
+dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB
+/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK
+kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO
+XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807
+VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo
+a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc
+dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV
+KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT
+Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0
+8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G
+C7TbO6Orb1wdtn7os4I07QZcJA==
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 2
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
+MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
+SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
+vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
+2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
+WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
+YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
+r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
+vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
+3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
+9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
+-----END CERTIFICATE-----
+
+Atos TrustedRoot 2011
+=====================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
+cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
+MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
+A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
+hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
+54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
+HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
+z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
+l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
+bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
+k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
+TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
+61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
+3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 1 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE
+PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm
+PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6
+Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN
+ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l
+g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV
+7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX
+9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f
+iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg
+t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI
+hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
+MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3
+GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct
+Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP
++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh
+3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa
+wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6
+O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0
+FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV
+hMJKzRwuJIczYOXD
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 2 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh
+ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY
+NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t
+oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o
+MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l
+V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo
+L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ
+sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD
+6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh
+lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI
+hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
+AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K
+pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9
+x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz
+dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X
+U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw
+mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD
+zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN
+JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr
+O3jtZsSOeWmD3n+M
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 3 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286
+IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL
+Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe
+6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3
+I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U
+VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7
+5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi
+Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM
+dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt
+rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI
+hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
+KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS
+t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ
+TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du
+DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib
+Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD
+hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX
+0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW
+dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2
+PpxxVJkES/1Y+Zj0
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root G2
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
+MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
+35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
+bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
+VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
+YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
+lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
+w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
+0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
+d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
+hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
+jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
+IhNzbM8m9Yop5w==
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
+VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
+MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
+RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
+KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
+UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
+YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
+1vUhZscv6pZjamVFkpUBtA==
+-----END CERTIFICATE-----
+
+DigiCert Global Root G2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
+MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
+kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
+3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
+BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
+UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
+5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
+F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
+WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
+QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
+iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----
+
+DigiCert Global Root G3
+=======================
+-----BEGIN CERTIFICATE-----
+MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
+VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
+MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
+aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
+AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
+YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
+Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
+3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
+VOKa5Vt8sycX
+-----END CERTIFICATE-----
+
+DigiCert Trusted Root G4
+========================
+-----BEGIN CERTIFICATE-----
+MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
+HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
+MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
+pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
+k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
+vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
+QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
+MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
+mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
+f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
+dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
+oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
+DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
+ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
+ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
+yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
+7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
+ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
+5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
+/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
+5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
+G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
+82Z+
+-----END CERTIFICATE-----
+
+COMODO RSA Certification Authority
+==================================
+-----BEGIN CERTIFICATE-----
+MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE
+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC
+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn
+dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ
+FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+
+5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG
+x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX
+2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL
+OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3
+sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C
+GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5
+WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
+FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt
+rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+
+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg
+tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW
+sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp
+pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA
+zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq
+ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52
+7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I
+LaZRfyHBNVOFBkpdn627G190
+-----END CERTIFICATE-----
+
+USERTrust RSA Certification Authority
+=====================================
+-----BEGIN CERTIFICATE-----
+MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE
+BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
+ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE
+BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
+ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz
+0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j
+Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn
+RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O
++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq
+/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE
+Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM
+lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8
+yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
+eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
+BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW
+FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ
+7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ
+Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM
+8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi
+FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi
+yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c
+J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw
+sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx
+Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
+-----END CERTIFICATE-----
+
+USERTrust ECC Certification Authority
+=====================================
+-----BEGIN CERTIFICATE-----
+MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
+0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
+nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
+HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
+HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
+9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
+-----END CERTIFICATE-----
+
+GlobalSign ECC Root CA - R4
+===========================
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl
+OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P
+AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV
+MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF
+JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=
+-----END CERTIFICATE-----
+
+GlobalSign ECC Root CA - R5
+===========================
+-----BEGIN CERTIFICATE-----
+MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
+SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
+h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
+BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
+uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
+yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA - G3
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC
+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y
+olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t
+x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy
+EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K
+Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur
+mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5
+1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp
+07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo
+FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE
+41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB
+AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu
+yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
+U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq
+KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1
+v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA
+8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b
+8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r
+mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq
+1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI
+JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV
+tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=
+-----END CERTIFICATE-----
+
+Staat der Nederlanden EV Root CA
+================================
+-----BEGIN CERTIFICATE-----
+MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M
+MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl
+cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk
+SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW
+O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r
+0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8
+Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV
+XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr
+08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV
+0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd
+74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx
+fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa
+ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
+eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu
+c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq
+5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN
+b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN
+f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi
+5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4
+WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK
+DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy
+eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==
+-----END CERTIFICATE-----
+
+IdenTrust Commercial Root CA 1
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
+EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS
+b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES
+MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB
+IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld
+hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/
+mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi
+1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C
+XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl
+3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy
+NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV
+WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg
+xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix
+uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI
+hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
+6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg
+ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt
+ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV
+YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX
+feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro
+kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe
+2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz
+Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R
+cGzM7vRX+Bi6hG6H
+-----END CERTIFICATE-----
+
+IdenTrust Public Sector Root CA 1
+=================================
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
+EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv
+ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV
+UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS
+b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy
+P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6
+Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI
+rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf
+qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS
+mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn
+ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh
+LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v
+iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL
+4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B
+Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw
+DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
+t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A
+mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt
+GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt
+m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx
+NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4
+Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI
+ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC
+ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ
+3Wl9af0AVqW3rLatt8o+Ae+c
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority - G2
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
+BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
+bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
+b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
+HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
+DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
+OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
+/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
+HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
+s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
+TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
+AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
+0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
+iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
+Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
+nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
+e4pIb4tF9g==
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority - EC1
+==========================================
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
+YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
+ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
+FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
+LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
+dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
+IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
+AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
+9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
+vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
+kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
+-----END CERTIFICATE-----
+
+CFCA EV ROOT
+============
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE
+CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB
+IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw
+MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD
+DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV
+BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD
+7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN
+uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW
+ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7
+xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f
+py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K
+gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol
+hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ
+tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf
+BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
+ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q
+ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua
+4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG
+E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX
+BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn
+aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy
+PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX
+kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C
+ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
+-----END CERTIFICATE-----
+
+Certinomis - Root CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg
+LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx
+EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD
+ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos
+P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo
+d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap
+z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00
+8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x
+RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE
+6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t
+FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV
+PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH
+i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj
+YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I
+6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF
+AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV
+WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw
+Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX
+lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ
+y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9
+Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng
+DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi
+I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM
+cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr
+hkIGuUE=
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GB CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
+EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
+MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
+b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
+scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
+rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
+9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
+Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
+GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
+hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
+dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
+VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
+HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
+Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
+-----END CERTIFICATE-----
+
+SZAFIR ROOT CA2
+===============
+-----BEGIN CERTIFICATE-----
+MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
+A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
+BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
+BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
+VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
+qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
+DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
+2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
+ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
+ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
+AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
+AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
+O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
+oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
+4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA 2
+===========================
+-----BEGIN CERTIFICATE-----
+MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
+BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
+bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
+ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
+TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
+IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
+7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
+CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
+Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
+uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
+GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
+9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
+Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
+hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
+BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
+hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
+Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
+L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
+clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
+pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
+w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
+J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
+ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
+is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
+zAYspsbiDrW5viSP
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2015
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
+BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
+aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
+YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
+MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
+QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
+BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
+MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
+bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
+iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
+6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
+FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
+i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
+GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
+fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
+iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
+Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
+hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
+D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
+d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
+d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
+82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
+davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
+Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
+J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
+JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
+p/UsQu0yrbYhnr68
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions ECC RootCA 2015
+===========================================================
+-----BEGIN CERTIFICATE-----
+MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
+aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
+cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
+aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
+MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
+IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
+VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
+Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
+dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
+Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
+BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
+GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
+dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
+-----END CERTIFICATE-----
+
+ISRG Root X1
+============
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE
+BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD
+EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG
+EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT
+DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r
+Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1
+3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K
+b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN
+Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ
+4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf
+1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu
+hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH
+usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r
+OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G
+A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY
+9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
+ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV
+0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt
+hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw
+TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx
+e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA
+JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD
+YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n
+JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ
+m+kXQ99b21/+jh5Xos1AnX5iItreGCc=
+-----END CERTIFICATE-----
+
+AC RAIZ FNMT-RCM
+================
+-----BEGIN CERTIFICATE-----
+MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT
+AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw
+MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD
+TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf
+qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr
+btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL
+j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou
+08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw
+WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT
+tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ
+47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC
+ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa
+i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o
+dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
+nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s
+D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ
+j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT
+Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW
++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7
+Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d
+8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm
+5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG
+rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
+-----END CERTIFICATE-----
+
+Amazon Root CA 1
+================
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD
+VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1
+MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
+bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH
+FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ
+gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t
+dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce
+VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3
+DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM
+CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy
+8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa
+2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2
+xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5
+-----END CERTIFICATE-----
+
+Amazon Root CA 2
+================
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD
+VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1
+MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
+bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4
+kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp
+N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9
+AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd
+fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx
+kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS
+btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0
+Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN
+c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+
+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw
+DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA
+A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE
+YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW
+xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ
+gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW
+aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV
+Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3
+KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi
+JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=
+-----END CERTIFICATE-----
+
+Amazon Root CA 3
+================
+-----BEGIN CERTIFICATE-----
+MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG
+EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy
+NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
+MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB
+f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr
+Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43
+rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc
+eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==
+-----END CERTIFICATE-----
+
+Amazon Root CA 4
+================
+-----BEGIN CERTIFICATE-----
+MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG
+EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy
+NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
+MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN
+/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri
+83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA
+MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1
+AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==
+-----END CERTIFICATE-----
+
+LuxTrust Global Root 2
+======================
+-----BEGIN CERTIFICATE-----
+MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQELBQAwRjELMAkG
+A1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNVBAMMFkx1eFRydXN0IEdsb2Jh
+bCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUwMzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEW
+MBQGA1UECgwNTHV4VHJ1c3QgUy5BLjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCC
+AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wm
+Kb3FibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTemhfY7RBi2
+xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1EMShduxq3sVs35a0VkBC
+wGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsnXpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm
+1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkm
+FRseTJIpgp7VkoGSQXAZ96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niF
+wpN6cj5mj5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4gDEa/
+a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+8kPREd8vZS9kzl8U
+ubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2jX5t/Lax5Gw5CMZdjpPuKadUiDTSQ
+MC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmHhFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB
+/zBCBgNVHSAEOzA5MDcGByuBKwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5
+Lmx1eHRydXN0Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT
++Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQELBQADggIBAGoZ
+FO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9BzZAcg4atmpZ1gDlaCDdLnIN
+H2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTOjFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW
+7MM3LGVYvlcAGvI1+ut7MV3CwRI9loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIu
+ZY+kt9J/Z93I055cqqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWA
+VWe+2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/JEAdemrR
+TxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKrezrnK+T+Tb/mjuuqlPpmt
+/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQfLSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc
+7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31I
+iyBMz2TWuJdGsE7RKlY6oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr
+-----END CERTIFICATE-----
+
+TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT
+D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr
+IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g
+TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp
+ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD
+VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt
+c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth
+bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11
+IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8
+6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc
+wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0
+3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9
+WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU
+ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
+AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc
+lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R
+e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j
+q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
+-----END CERTIFICATE-----
+
+GDCA TrustAUTH R5 ROOT
+======================
+-----BEGIN CERTIFICATE-----
+MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw
+BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD
+DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow
+YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
+IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs
+AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p
+OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr
+pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ
+9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ
+xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM
+R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ
+D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4
+oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx
+9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
+p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9
+H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35
+6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd
++PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ
+HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD
+F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ
+8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv
+/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT
+aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
+-----END CERTIFICATE-----
+
+TrustCor RootCert CA-1
+======================
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP
+MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig
+U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp
+dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx
+MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu
+YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe
+VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy
+dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq
+jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4
+pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0
+JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h
+gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw
+/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j
+BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5
+mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf
+ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C
+qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P
+3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk=
+-----END CERTIFICATE-----
+
+TrustCor RootCert CA-2
+======================
+-----BEGIN CERTIFICATE-----
+MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w
+DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT
+eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0
+eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy
+MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h
+bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
+cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0
+IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb
+ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk
+RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1
+oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb
+XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1
+/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q
+jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP
+eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg
+rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh
+8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU
+2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h
+Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp
+kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv
+2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3
+S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw
+PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv
+DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU
+RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE
+xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX
+RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ
+-----END CERTIFICATE-----
+
+TrustCor ECA-1
+==============
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP
+MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig
+U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp
+dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw
+N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5
+MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y
+IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR
+MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23
+xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc
+p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+
+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj
+YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL
+f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
+AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u
+/ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F
+hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs
+J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC
+jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g==
+-----END CERTIFICATE-----
+
+SSL.com Root Certification Authority RSA
+========================================
+-----BEGIN CERTIFICATE-----
+MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM
+BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x
+MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw
+MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
+EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM
+LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C
+Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8
+P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge
+oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp
+k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z
+fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ
+gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2
+UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8
+1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s
+bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
+HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr
+dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf
+ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl
+u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq
+erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj
+MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ
+vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI
+Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y
+wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI
+WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k=
+-----END CERTIFICATE-----
+
+SSL.com Root Certification Authority ECC
+========================================
+-----BEGIN CERTIFICATE-----
+MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV
+BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv
+BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy
+MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
+BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
+bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA
+BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+
+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR
+hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT
+jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW
+e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z
+5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
+-----END CERTIFICATE-----
+
+SSL.com EV Root Certification Authority RSA R2
+==============================================
+-----BEGIN CERTIFICATE-----
+MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w
+DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u
+MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
+MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI
+DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD
+VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh
+hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w
+cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO
+Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+
+B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh
+CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim
+9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto
+RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm
+JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48
++qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
+HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp
+qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1
+++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx
+Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G
+guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz
+OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7
+CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq
+lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR
+rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1
+hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX
+9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
+-----END CERTIFICATE-----
+
+SSL.com EV Root Certification Authority ECC
+===========================================
+-----BEGIN CERTIFICATE-----
+MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV
+BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy
+BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw
+MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
+EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM
+LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy
+3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O
+BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe
+5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ
+N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm
+m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R6
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX
+R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
+b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i
+YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs
+U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss
+grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE
+3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF
+vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM
+PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+
+azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O
+WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy
+CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP
+0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN
+b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV
+HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
+nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0
+lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY
+BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym
+Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr
+3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1
+0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T
+uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK
+oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t
+JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GC CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD
+SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo
+MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa
+Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL
+ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh
+bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr
+VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab
+NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
+BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E
+AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk
+AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
+-----END CERTIFICATE-----
+
+GTS Root R1
+===========
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG
+EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv
+b3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG
+A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx
+9vaMf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7r
+aKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnW
+r4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqM
+LnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly
+4cpk9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr
+06zqkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
+wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om
+3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNu
+JLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEM
+BQADggIBADiWCu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
+d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6ZXPYfcX3v73sv
+fuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZRgyFmxhE+885H7pwoHyXa/6xm
+ld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9b
+gsiG1eGZbYwE8na6SfZu6W0eX6DvJ4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq
+4BjFbkerQUIpm/ZgDdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWEr
+tXvM+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyyF62ARPBo
+pY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9SQ98POyDGCBDTtWTurQ0
+sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdwsE3PYJ/HQcu51OyLemGhmW/HGY0dVHLql
+CFF1pkgl
+-----END CERTIFICATE-----
+
+GTS Root R2
+===========
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG
+EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv
+b3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG
+A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTuk
+k3LvCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo
+7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWI
+m8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5Gm
+dFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbu
+ak7MkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscsz
+cTJGr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW
+Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73Vululycsl
+aVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy
+5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEM
+BQADggIBALZp8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
+vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiTz9D2PGcDFWEJ
++YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiApJiS4wGWAqoC7o87xdFtCjMw
+c3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvbpxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3Da
+WsYDQvTtN6LwG1BUSw7YhN4ZKJmBR64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5r
+n/WkhLx3+WuXrD5RRaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56Gtmwfu
+Nmsk0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC5AwiWVIQ
+7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiFizoHCBy69Y9Vmhh1fuXs
+gWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLnyOd/xCxgXS/Dr55FBcOEArf9LAhST4Ld
+o/DUhgkC
+-----END CERTIFICATE-----
+
+GTS Root R3
+===========
+-----BEGIN CERTIFICATE-----
+MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV
+UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
+UjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
+ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUU
+Rout736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24Cej
+QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP
+0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFukfCPAlaUs3L6JbyO5o91lAFJekazInXJ0
+glMLfalAvWhgxeG4VDvBNhcl2MG9AjEAnjWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOa
+KaqW04MjyaR7YbPMAuhd
+-----END CERTIFICATE-----
+
+GTS Root R4
+===========
+-----BEGIN CERTIFICATE-----
+MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV
+UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
+UjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
+ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa
+6zzuhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqj
+QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV
+2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0CMRw3J5QdCHojXohw0+WbhXRIjVhLfoI
+N+4Zba3bssx9BzT1YBkstTTZbyACMANxsbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11x
+zPKwTdb+mciUqXWi4w==
+-----END CERTIFICATE-----
+
+UCA Global G2 Root
+==================
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG
+EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x
+NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU
+cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT
+oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV
+8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS
+h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o
+LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/
+R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe
+KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa
+4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc
+OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97
+8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo
+5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
+1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A
+Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9
+yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX
+c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo
+jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk
+bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x
+ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn
+RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A==
+-----END CERTIFICATE-----
+
+UCA Extended Validation Root
+============================
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG
+EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u
+IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G
+A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs
+iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF
+Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu
+eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR
+59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH
+0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR
+el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv
+B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth
+WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS
+NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS
+3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL
+BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
+ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM
+aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4
+dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb
++7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW
+F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi
+GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc
+GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi
+djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr
+dhh2n1ax
+-----END CERTIFICATE-----
+
+Certigna Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE
+BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ
+MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda
+MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz
+MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX
+stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz
+KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8
+JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16
+XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq
+4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej
+wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ
+lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI
+jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/
+/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
+1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy
+dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h
+LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl
+cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt
+OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP
+TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq
+7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3
+4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd
+8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS
+6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY
+tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS
+aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde
+E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
+-----END CERTIFICATE-----
diff --git a/libs/cpp-httplib/test/fuzzing/CMakeLists.txt b/libs/cpp-httplib/test/fuzzing/CMakeLists.txt
new file mode 100644
index 0000000..7e416c7
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/CMakeLists.txt
@@ -0,0 +1,10 @@
+file(GLOB HTTPLIB_CORPUS corpus/*)
+add_executable(httplib-test-fuzz
+ server_fuzzer.cc
+ standalone_fuzz_target_runner.cpp
+)
+target_link_libraries(httplib-test-fuzz PRIVATE httplib)
+add_test(
+ NAME httplib-test-fuzz
+ COMMAND httplib-test-fuzz ${HTTPLIB_CORPUS}
+)
diff --git a/libs/cpp-httplib/test/fuzzing/Makefile b/libs/cpp-httplib/test/fuzzing/Makefile
new file mode 100644
index 0000000..b08ecd0
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/Makefile
@@ -0,0 +1,27 @@
+
+#CXX = clang++
+# Do not add default sanitizer flags here as OSS-fuzz adds its own sanitizer flags.
+CXXFLAGS += -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I../.. -I. -Wall -Wextra -Wtype-limits -Wconversion
+
+OPENSSL_DIR = /usr/local/opt/openssl@1.1
+
+# Using full path to libssl and libcrypto to avoid accidentally picking openssl libs brought in by msan.
+OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -I$(OPENSSL_DIR)/lib /usr/local/lib/libssl.a /usr/local/lib/libcrypto.a
+
+ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
+
+BROTLI_DIR = /usr/local/opt/brotli
+# BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
+
+# Runs all the tests and also fuzz tests against seed corpus.
+all : server_fuzzer
+ ./server_fuzzer corpus/*
+
+# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
+server_fuzzer : server_fuzzer.cc ../../httplib.h
+# $(CXX) $(CXXFLAGS) -o $@ $< -Wl,-Bstatic $(OPENSSL_SUPPORT) -Wl,-Bdynamic -ldl $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
+ $(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
+ zip -q -r server_fuzzer_seed_corpus.zip corpus
+
+clean:
+ rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/1 b/libs/cpp-httplib/test/fuzzing/corpus/1
new file mode 100644
index 0000000..2b9fcc4
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/1
@@ -0,0 +1 @@
+PUT /search/sample?a=12 HTTP/1.1 \ No newline at end of file
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/2 b/libs/cpp-httplib/test/fuzzing/corpus/2
new file mode 100644
index 0000000..bdb9bcc
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/2
@@ -0,0 +1,5 @@
+GET /hello.htm HTTP/1.1
+User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
+Accept-Language: en-us
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive \ No newline at end of file
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/3 b/libs/cpp-httplib/test/fuzzing/corpus/3
new file mode 100644
index 0000000..878944f
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/3
Binary files differ
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5042094968537088 b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5042094968537088
new file mode 100644
index 0000000..0325729
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5042094968537088
Binary files differ
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5372331946541056 b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5372331946541056
new file mode 100644
index 0000000..6fca86b
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5372331946541056
Binary files differ
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5386708825800704 b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5386708825800704
new file mode 100644
index 0000000..1f1e4ae
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5386708825800704
Binary files differ
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5667822731132928 b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5667822731132928
new file mode 100644
index 0000000..b21d1ce
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5667822731132928
Binary files differ
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5886572146327552 b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5886572146327552
new file mode 100644
index 0000000..797165c
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5886572146327552
Binary files differ
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5942767436562432 b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5942767436562432
new file mode 100644
index 0000000..a2fedd5
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-5942767436562432
Binary files differ
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-6007379124158464 b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-6007379124158464
new file mode 100644
index 0000000..4c4c57e
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-6007379124158464
Binary files differ
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-6508706672541696 b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-6508706672541696
new file mode 100644
index 0000000..6f89836
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/clusterfuzz-testcase-minimized-server_fuzzer-6508706672541696
@@ -0,0 +1,7 @@
+PUT { HTTP/1.0
+Content-Type:multipart/form-databoundary=m
+Range:bytes=-
+
+--m
+C
+c PUT ?&+&:&<&&I&`&a&&s&&&2&&&@&!& ‮ ‌ PUT ?&+&:&<&&I&`&a&&s&&&2&&&@&!& PUT ?&+&:&<&&I&`&a&&s&&&2&&&@&!& X-Forwarded-Host ‮ ‌ X-Forwarded-Host ‮ ‌ PUT ?&+&:&<&&I&`&a&&s&&&2&&&@&!& PUT ?&+&:&<&&I&`&a&&s&&&2&&&@&!& X-Forwarded-Host ‮ ‌ 2 +/v+ \ No newline at end of file
diff --git a/libs/cpp-httplib/test/fuzzing/corpus/issue1264 b/libs/cpp-httplib/test/fuzzing/corpus/issue1264
new file mode 100644
index 0000000..fd53db5
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/corpus/issue1264
@@ -0,0 +1,19 @@
+POST /fform%u008anom%u08ag HTTP/1.0
+Don
+Rcn ,Co
+Cofffffffffffffffffffffffntemt
+
+
+
+
+
+Content-Length:dent:applica;tion/x-wsw-form%`00368aogrlencod368angrlencoded
+JJ`
+o
+
+8
+
+8
+92H
+Content-Encoding:PUT { HTTP/1.0
+Content-Type:Range:bytes=- multipart/ \ No newline at end of file
diff --git a/libs/cpp-httplib/test/fuzzing/server_fuzzer.cc b/libs/cpp-httplib/test/fuzzing/server_fuzzer.cc
new file mode 100644
index 0000000..a0f7c0e
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/server_fuzzer.cc
@@ -0,0 +1,100 @@
+#include <cstdint>
+
+#include <httplib.h>
+
+class FuzzedStream : public httplib::Stream {
+public:
+ FuzzedStream(const uint8_t *data, size_t size)
+ : data_(data), size_(size), read_pos_(0) {}
+
+ ssize_t read(char *ptr, size_t size) override {
+ if (size + read_pos_ > size_) { size = size_ - read_pos_; }
+ memcpy(ptr, data_ + read_pos_, size);
+ read_pos_ += size;
+ return static_cast<ssize_t>(size);
+ }
+
+ ssize_t write(const char *ptr, size_t size) override {
+ response_.append(ptr, size);
+ return static_cast<int>(size);
+ }
+
+ ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); }
+
+ ssize_t write(const std::string &s) { return write(s.data(), s.size()); }
+
+ bool is_readable() const override { return true; }
+
+ bool wait_readable() const override { return true; }
+
+ bool wait_writable() const override { return true; }
+
+ void get_remote_ip_and_port(std::string &ip, int &port) const override {
+ ip = "127.0.0.1";
+ port = 8080;
+ }
+
+ void get_local_ip_and_port(std::string &ip, int &port) const override {
+ ip = "127.0.0.1";
+ port = 8080;
+ }
+
+ socket_t socket() const override { return 0; }
+
+ time_t duration() const override { return 0; };
+
+private:
+ const uint8_t *data_;
+ size_t size_;
+ size_t read_pos_;
+ std::string response_;
+};
+
+class FuzzableServer : public httplib::Server {
+public:
+ void ProcessFuzzedRequest(FuzzedStream &stream) {
+ bool connection_close = false;
+ process_request(stream,
+ /*remote_addr=*/"",
+ /*remote_port =*/0,
+ /*local_addr=*/"",
+ /*local_port =*/0,
+ /*last_connection=*/false, connection_close, nullptr);
+ }
+};
+
+static FuzzableServer g_server;
+
+extern "C" int LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) {
+ g_server.Get(R"(.*)",
+ [&](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.set_content("response content", "text/plain");
+ });
+ g_server.Post(R"(.*)",
+ [&](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.set_content("response content", "text/plain");
+ });
+ g_server.Put(R"(.*)",
+ [&](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.set_content("response content", "text/plain");
+ });
+ g_server.Patch(R"(.*)",
+ [&](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.set_content("response content", "text/plain");
+ });
+ g_server.Delete(
+ R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.set_content("response content", "text/plain");
+ });
+ g_server.Options(
+ R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.set_content("response content", "text/plain");
+ });
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ FuzzedStream stream{data, size};
+ g_server.ProcessFuzzedRequest(stream);
+ return 0;
+}
diff --git a/libs/cpp-httplib/test/fuzzing/server_fuzzer.dict b/libs/cpp-httplib/test/fuzzing/server_fuzzer.dict
new file mode 100644
index 0000000..47283dc
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/server_fuzzer.dict
@@ -0,0 +1,224 @@
+# Sources: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
+
+# misc
+"HTTP/1.1"
+
+# verbs
+"CONNECT"
+"DELETE"
+"GET"
+"HEAD"
+"OPTIONS"
+"PATCH"
+"POST"
+"PUT"
+"TRACE"
+
+
+# Webdav/caldav verbs
+"ACL"
+"BASELINE-CONTROL"
+"BIND"
+"CHECKIN"
+"CHECKOUT"
+"COPY"
+"LABEL"
+"LINK"
+"LOCK"
+"MERGE"
+"MKACTIVITY"
+"MKCALENDAR"
+"MKCOL"
+"MKREDIRECTREF"
+"MKWORKSPACE"
+"MOVE"
+"ORDERPATCH"
+"PRI"
+"PROPFIND"
+"PROPPATCH"
+"REBIND"
+"REPORT"
+"SEARCH"
+"UNBIND"
+"UNCHECKOUT"
+"UNLINK"
+"UNLOCK"
+"UPDATE"
+"UPDATEREDIRECTREF"
+"VERSION-CONTROL"
+
+
+# Fields
+"A-IM"
+"Accept"
+"Accept-Charset"
+"Accept-Datetime"
+"Accept-Encoding"
+"Accept-Language"
+"Accept-Patch"
+"Accept-Ranges"
+"Access-Control-Allow-Credentials"
+"Access-Control-Allow-Headers"
+"Access-Control-Allow-Methods"
+"Access-Control-Allow-Origin"
+"Access-Control-Expose-Headers"
+"Access-Control-Max-Age"
+"Access-Control-Request-Headers"
+"Access-Control-Request-Method"
+"Age"
+"Allow"
+"Alt-Svc"
+"Authorization"
+"Cache-Control"
+"Connection"
+"Connection:"
+"Content-Disposition"
+"Content-Encoding"
+"Content-Language"
+"Content-Length"
+"Content-Location"
+"Content-MD5"
+"Content-Range"
+"Content-Security-Policy"
+"Content-Type"
+"Cookie"
+"DNT"
+"Date"
+"Delta-Base"
+"ETag"
+"Expect"
+"Expires"
+"Forwarded"
+"From"
+"Front-End-Https"
+"HTTP2-Settings"
+"Host"
+"IM"
+"If-Match"
+"If-Modified-Since"
+"If-None-Match"
+"If-Range"
+"If-Unmodified-Since"
+"Last-Modified"
+"Link"
+"Location"
+"Max-Forwards"
+"Origin"
+"P3P"
+"Pragma"
+"Proxy-Authenticate"
+"Proxy-Authorization"
+"Proxy-Connection"
+"Public-Key-Pins"
+"Range"
+"Referer"
+"Refresh"
+"Retry-After"
+"Save-Data"
+"Server"
+"Set-Cookie"
+"Status"
+"Strict-Transport-Security"
+"TE"
+"Timing-Allow-Origin"
+"Tk"
+"Trailer"
+"Transfer-Encoding"
+"Upgrade"
+"Upgrade-Insecure-Requests"
+"User-Agent"
+"Vary"
+"Via"
+"WWW-Authenticate"
+"Warning"
+"X-ATT-DeviceId"
+"X-Content-Duration"
+"X-Content-Security-Policy"
+"X-Content-Type-Options"
+"X-Correlation-ID"
+"X-Csrf-Token"
+"X-Forwarded-For"
+"X-Forwarded-Host"
+"X-Forwarded-Proto"
+"X-Frame-Options"
+"X-Http-Method-Override"
+"X-Powered-By"
+"X-Request-ID"
+"X-Requested-With"
+"X-UA-Compatible"
+"X-UIDH"
+"X-Wap-Profile"
+"X-WebKit-CSP"
+"X-XSS-Protection"
+
+# Source: string and character literals in httplib.h
+" "
+"&"
+", "
+"-"
+"--"
+"."
+".."
+":"
+"="
+" = = "
+"0123456789abcdef"
+"%02X"
+"%0A"
+"\\x0a\\x0d"
+"%0D"
+"%20"
+"%27"
+"%2B"
+"%2C"
+"%3A"
+"%3B"
+"application/javascript"
+"application/json"
+"application/pdf"
+"application/xhtml+xml"
+"application/xml"
+"application/x-www-form-urlencoded"
+"Bad Request"
+"boundary="
+"bytes="
+"chunked"
+"close"
+"CONNECT"
+"css"
+"Forbidden"
+"Found"
+"gif"
+"gzip"
+"html"
+"ico"
+"image/gif"
+"image/jpg"
+"image/png"
+"image/svg+xml"
+"image/x-icon"
+"index.html"
+"Internal Server Error"
+"jpeg"
+"js"
+"json"
+"Location"
+"Moved Permanently"
+"multipart/form-data"
+"Not Found"
+"Not Modified"
+"OK"
+"pdf"
+"png"
+"Range"
+"REMOTE_ADDR"
+"See Other"
+"svg"
+"text/"
+"text/css"
+"text/html"
+"text/plain"
+"txt"
+"Unsupported Media Type"
+"xhtml"
+"xml" \ No newline at end of file
diff --git a/libs/cpp-httplib/test/fuzzing/standalone_fuzz_target_runner.cpp b/libs/cpp-httplib/test/fuzzing/standalone_fuzz_target_runner.cpp
new file mode 100644
index 0000000..e8bd5ed
--- /dev/null
+++ b/libs/cpp-httplib/test/fuzzing/standalone_fuzz_target_runner.cpp
@@ -0,0 +1,35 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+// Licensed under the Apache License, Version 2.0 (the "License");
+
+// This runner does not do any fuzzing, but allows us to run the fuzz target
+// on the test corpus or on a single file,
+// e.g. the one that comes from a bug report.
+
+#include <cstdint>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+// Forward declare the "fuzz target" interface.
+// We deliberately keep this interface simple and header-free.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+// It reads all files passed as parameters and feeds their contents
+// one by one into the fuzz target (LLVMFuzzerTestOneInput).
+int main(int argc, char **argv) {
+ for (int i = 1; i < argc; i++) {
+ std::ifstream in(argv[i]);
+ in.seekg(0, in.end);
+ size_t length = static_cast<size_t>(in.tellg());
+ in.seekg(0, in.beg);
+ std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
+ // Allocate exactly length bytes so that we reliably catch buffer overflows.
+ std::vector<char> bytes(length);
+ in.read(bytes.data(), static_cast<std::streamsize>(bytes.size()));
+ LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
+ bytes.size());
+ std::cout << "Execution successful" << std::endl;
+ }
+ std::cout << "Execution finished" << std::endl;
+ return 0;
+}
diff --git a/libs/cpp-httplib/test/gen-certs.sh b/libs/cpp-httplib/test/gen-certs.sh
new file mode 100644
index 0000000..ee2a2cf
--- /dev/null
+++ b/libs/cpp-httplib/test/gen-certs.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+if [[ $(openssl version) =~ 3\.[2-9]\.[0-9]+ ]]; then
+ OPENSSL_X509_FLAG='-x509v1'
+else
+ OPENSSL_X509_FLAG='-x509'
+fi
+
+openssl genrsa 2048 > key.pem
+openssl req -new -batch -config test.conf -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
+openssl req -x509 -config test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
+openssl genrsa 2048 > rootCA.key.pem
+openssl req $OPENSSL_X509_FLAG -new -batch -config test.rootCA.conf -key rootCA.key.pem -days 1024 > rootCA.cert.pem
+openssl genrsa 2048 > client.key.pem
+openssl req -new -batch -config test.conf -key client.key.pem | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client.cert.pem
+openssl genrsa -passout pass:test123! 2048 > key_encrypted.pem
+openssl req -new -batch -config test.conf -key key_encrypted.pem | openssl x509 -days 3650 -req -signkey key_encrypted.pem > cert_encrypted.pem
+openssl genrsa -aes256 -passout pass:test012! 2048 > client_encrypted.key.pem
+openssl req -new -batch -config test.conf -key client_encrypted.key.pem -passin pass:test012! | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client_encrypted.cert.pem
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-assertion-result.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-assertion-result.h
new file mode 100644
index 0000000..addbb59
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-assertion-result.h
@@ -0,0 +1,237 @@
+// 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This file implements the AssertionResult type.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_ASSERTION_RESULT_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_ASSERTION_RESULT_H_
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-port.h"
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+namespace testing {
+
+// 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);
+
+// C4800 is a level 3 warning in Visual Studio 2015 and earlier.
+// This warning is not emitted in Visual Studio 2017.
+// This warning is off by default starting in Visual Studio 2019 but can be
+// enabled with command-line options.
+#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920)
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */)
+#endif
+
+ // Used in the EXPECT_TRUE/FALSE(bool_expression).
+ //
+ // T must be contextually convertible to bool.
+ //
+ // The second parameter prevents this overload from being considered if
+ // the argument is implicitly convertible to AssertionResult. In that case
+ // we want AssertionResult's copy constructor to be used.
+ template <typename T>
+ explicit AssertionResult(
+ const T& success,
+ typename std::enable_if<
+ !std::is_convertible<T, AssertionResult>::value>::type*
+ /*enabler*/
+ = nullptr)
+ : success_(success) {}
+
+#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920)
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
+
+ // Assignment operator.
+ AssertionResult& operator=(AssertionResult other) {
+ swap(other);
+ return *this;
+ }
+
+ // Returns true if and only if 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() != nullptr ? message_->c_str() : "";
+ }
+ // Deprecated; please use message() instead.
+ const char* failure_message() const { return message(); }
+
+ // Streams a custom failure message into this object.
+ template <typename T>
+ 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() == nullptr) message_.reset(new ::std::string);
+ message_->append(a_message.GetString().c_str());
+ }
+
+ // Swap the contents of this AssertionResult with other.
+ void swap(AssertionResult& other);
+
+ // 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.
+ std::unique_ptr< ::std::string> message_;
+};
+
+// 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);
+
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_ASSERTION_RESULT_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-death-test.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-death-test.h
new file mode 100644
index 0000000..84e5a5b
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-death-test.h
@@ -0,0 +1,345 @@
+// 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.
+
+// The Google C++ Testing and Mocking 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.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+#include "gtest/internal/gtest-death-test-internal.h"
+
+// 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);
+
+namespace testing {
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal {
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process. Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests. IMPORTANT: This is an internal utility. Using it may break the
+// implementation of death tests. User code MUST NOT use it.
+GTEST_API_ bool InDeathTestChild();
+
+} // namespace internal
+
+// 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!");
+//
+// The final parameter to each of these macros is a matcher applied to any data
+// the sub-process wrote to stderr. For compatibility with existing tests, a
+// bare string is interpreted as a regular expression matcher.
+//
+// On the regular expressions used in death tests:
+//
+// On POSIX-compliant systems (*nix), we use the <regex.h> library,
+// which uses the POSIX extended regex syntax.
+//
+// On other platforms (e.g. Windows or Mac), 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.
+//
+
+// Asserts that a given `statement` causes the program to exit, with an
+// integer exit status that satisfies `predicate`, and emitting error output
+// that matches `matcher`.
+#define ASSERT_EXIT(statement, predicate, matcher) \
+ GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_FATAL_FAILURE_)
+
+// Like `ASSERT_EXIT`, but continues on to successive tests in the
+// test suite, if any:
+#define EXPECT_EXIT(statement, predicate, matcher) \
+ GTEST_DEATH_TEST_(statement, predicate, matcher, 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 `matcher`.
+#define ASSERT_DEATH(statement, matcher) \
+ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)
+
+// Like `ASSERT_DEATH`, but continues on to successive tests in the
+// test suite, if any:
+#define EXPECT_DEATH(statement, matcher) \
+ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)
+
+// 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);
+ ExitedWithCode(const ExitedWithCode&) = default;
+ void operator=(const ExitedWithCode& other) = delete;
+ bool operator()(int exit_status) const;
+
+ private:
+ const int exit_code_;
+};
+
+#if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+// 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(TestSuite, 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) \
+ GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+ GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+#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
+
+// 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
+// if and only if 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. It is exposed publicly so that systems
+// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST
+// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and
+// ASSERT_DEATH_IF_SUPPORTED.
+//
+// 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 if and only if 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()
+
+// 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 // GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-matchers.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-matchers.h
new file mode 100644
index 0000000..bffa00c
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-matchers.h
@@ -0,0 +1,956 @@
+// 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This file implements just enough of the matcher interface to allow
+// EXPECT_DEATH and friends to accept a matcher argument.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+
+#include <atomic>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "gtest/gtest-printers.h"
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
+
+// MSVC warning C5046 is new as of VS2017 version 15.8.
+#if defined(_MSC_VER) && _MSC_VER >= 1915
+#define GTEST_MAYBE_5046_ 5046
+#else
+#define GTEST_MAYBE_5046_
+#endif
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(
+ 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by
+ clients of class B */
+ /* Symbol involving type with internal linkage not defined */)
+
+namespace testing {
+
+// To implement a matcher Foo for type T, define:
+// 1. a class FooMatcherMatcher that implements the matcher interface:
+// using is_gtest_matcher = void;
+// bool MatchAndExplain(const T&, std::ostream*);
+// (MatchResultListener* can also be used instead of std::ostream*)
+// void DescribeTo(std::ostream*);
+// void DescribeNegationTo(std::ostream*);
+//
+// 2. a factory function that creates a Matcher<T> object from a
+// FooMatcherMatcher.
+
+class MatchResultListener {
+ public:
+ // Creates a listener object with the given underlying ostream. The
+ // listener does not own the ostream, and does not dereference it
+ // in the constructor or destructor.
+ explicit MatchResultListener(::std::ostream* os) : stream_(os) {}
+ virtual ~MatchResultListener() = 0; // Makes this class abstract.
+
+ // Streams x to the underlying ostream; does nothing if the ostream
+ // is NULL.
+ template <typename T>
+ MatchResultListener& operator<<(const T& x) {
+ if (stream_ != nullptr) *stream_ << x;
+ return *this;
+ }
+
+ // Returns the underlying ostream.
+ ::std::ostream* stream() { return stream_; }
+
+ // Returns true if and only if the listener is interested in an explanation
+ // of the match result. A matcher's MatchAndExplain() method can use
+ // this information to avoid generating the explanation when no one
+ // intends to hear it.
+ bool IsInterested() const { return stream_ != nullptr; }
+
+ private:
+ ::std::ostream* const stream_;
+
+ MatchResultListener(const MatchResultListener&) = delete;
+ MatchResultListener& operator=(const MatchResultListener&) = delete;
+};
+
+inline MatchResultListener::~MatchResultListener() {}
+
+// An instance of a subclass of this knows how to describe itself as a
+// matcher.
+class GTEST_API_ MatcherDescriberInterface {
+ public:
+ virtual ~MatcherDescriberInterface() {}
+
+ // Describes this matcher to an ostream. The function should print
+ // a verb phrase that describes the property a value matching this
+ // matcher should have. The subject of the verb phrase is the value
+ // being matched. For example, the DescribeTo() method of the Gt(7)
+ // matcher prints "is greater than 7".
+ virtual void DescribeTo(::std::ostream* os) const = 0;
+
+ // Describes the negation of this matcher to an ostream. For
+ // example, if the description of this matcher is "is greater than
+ // 7", the negated description could be "is not greater than 7".
+ // You are not required to override this when implementing
+ // MatcherInterface, but it is highly advised so that your matcher
+ // can produce good error messages.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "not (";
+ DescribeTo(os);
+ *os << ")";
+ }
+};
+
+// The implementation of a matcher.
+template <typename T>
+class MatcherInterface : public MatcherDescriberInterface {
+ public:
+ // Returns true if and only if the matcher matches x; also explains the
+ // match result to 'listener' if necessary (see the next paragraph), in
+ // the form of a non-restrictive relative clause ("which ...",
+ // "whose ...", etc) that describes x. For example, the
+ // MatchAndExplain() method of the Pointee(...) matcher should
+ // generate an explanation like "which points to ...".
+ //
+ // Implementations of MatchAndExplain() should add an explanation of
+ // the match result *if and only if* they can provide additional
+ // information that's not already present (or not obvious) in the
+ // print-out of x and the matcher's description. Whether the match
+ // succeeds is not a factor in deciding whether an explanation is
+ // needed, as sometimes the caller needs to print a failure message
+ // when the match succeeds (e.g. when the matcher is used inside
+ // Not()).
+ //
+ // For example, a "has at least 10 elements" matcher should explain
+ // what the actual element count is, regardless of the match result,
+ // as it is useful information to the reader; on the other hand, an
+ // "is empty" matcher probably only needs to explain what the actual
+ // size is when the match fails, as it's redundant to say that the
+ // size is 0 when the value is already known to be empty.
+ //
+ // You should override this method when defining a new matcher.
+ //
+ // It's the responsibility of the caller (Google Test) to guarantee
+ // that 'listener' is not NULL. This helps to simplify a matcher's
+ // implementation when it doesn't care about the performance, as it
+ // can talk to 'listener' without checking its validity first.
+ // However, in order to implement dummy listeners efficiently,
+ // listener->stream() may be NULL.
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0;
+
+ // Inherits these methods from MatcherDescriberInterface:
+ // virtual void DescribeTo(::std::ostream* os) const = 0;
+ // virtual void DescribeNegationTo(::std::ostream* os) const;
+};
+
+namespace internal {
+
+struct AnyEq {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const {
+ return a == b;
+ }
+};
+struct AnyNe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const {
+ return a != b;
+ }
+};
+struct AnyLt {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const {
+ return a < b;
+ }
+};
+struct AnyGt {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const {
+ return a > b;
+ }
+};
+struct AnyLe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const {
+ return a <= b;
+ }
+};
+struct AnyGe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const {
+ return a >= b;
+ }
+};
+
+// A match result listener that ignores the explanation.
+class DummyMatchResultListener : public MatchResultListener {
+ public:
+ DummyMatchResultListener() : MatchResultListener(nullptr) {}
+
+ private:
+ DummyMatchResultListener(const DummyMatchResultListener&) = delete;
+ DummyMatchResultListener& operator=(const DummyMatchResultListener&) = delete;
+};
+
+// A match result listener that forwards the explanation to a given
+// ostream. The difference between this and MatchResultListener is
+// that the former is concrete.
+class StreamMatchResultListener : public MatchResultListener {
+ public:
+ explicit StreamMatchResultListener(::std::ostream* os)
+ : MatchResultListener(os) {}
+
+ private:
+ StreamMatchResultListener(const StreamMatchResultListener&) = delete;
+ StreamMatchResultListener& operator=(const StreamMatchResultListener&) =
+ delete;
+};
+
+struct SharedPayloadBase {
+ std::atomic<int> ref{1};
+ void Ref() { ref.fetch_add(1, std::memory_order_relaxed); }
+ bool Unref() { return ref.fetch_sub(1, std::memory_order_acq_rel) == 1; }
+};
+
+template <typename T>
+struct SharedPayload : SharedPayloadBase {
+ explicit SharedPayload(const T& v) : value(v) {}
+ explicit SharedPayload(T&& v) : value(std::move(v)) {}
+
+ static void Destroy(SharedPayloadBase* shared) {
+ delete static_cast<SharedPayload*>(shared);
+ }
+
+ T value;
+};
+
+// An internal class for implementing Matcher<T>, which will derive
+// from it. We put functionalities common to all Matcher<T>
+// specializations here to avoid code duplication.
+template <typename T>
+class MatcherBase : private MatcherDescriberInterface {
+ public:
+ // Returns true if and only if the matcher matches x; also explains the
+ // match result to 'listener'.
+ bool MatchAndExplain(const T& x, MatchResultListener* listener) const {
+ GTEST_CHECK_(vtable_ != nullptr);
+ return vtable_->match_and_explain(*this, x, listener);
+ }
+
+ // Returns true if and only if this matcher matches x.
+ bool Matches(const T& x) const {
+ DummyMatchResultListener dummy;
+ return MatchAndExplain(x, &dummy);
+ }
+
+ // Describes this matcher to an ostream.
+ void DescribeTo(::std::ostream* os) const final {
+ GTEST_CHECK_(vtable_ != nullptr);
+ vtable_->describe(*this, os, false);
+ }
+
+ // Describes the negation of this matcher to an ostream.
+ void DescribeNegationTo(::std::ostream* os) const final {
+ GTEST_CHECK_(vtable_ != nullptr);
+ vtable_->describe(*this, os, true);
+ }
+
+ // Explains why x matches, or doesn't match, the matcher.
+ void ExplainMatchResultTo(const T& x, ::std::ostream* os) const {
+ StreamMatchResultListener listener(os);
+ MatchAndExplain(x, &listener);
+ }
+
+ // Returns the describer for this matcher object; retains ownership
+ // of the describer, which is only guaranteed to be alive when
+ // this matcher object is alive.
+ const MatcherDescriberInterface* GetDescriber() const {
+ if (vtable_ == nullptr) return nullptr;
+ return vtable_->get_describer(*this);
+ }
+
+ protected:
+ MatcherBase() : vtable_(nullptr), buffer_() {}
+
+ // Constructs a matcher from its implementation.
+ template <typename U>
+ explicit MatcherBase(const MatcherInterface<U>* impl)
+ : vtable_(nullptr), buffer_() {
+ Init(impl);
+ }
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ MatcherBase(M&& m) : vtable_(nullptr), buffer_() { // NOLINT
+ Init(std::forward<M>(m));
+ }
+
+ MatcherBase(const MatcherBase& other)
+ : vtable_(other.vtable_), buffer_(other.buffer_) {
+ if (IsShared()) buffer_.shared->Ref();
+ }
+
+ MatcherBase& operator=(const MatcherBase& other) {
+ if (this == &other) return *this;
+ Destroy();
+ vtable_ = other.vtable_;
+ buffer_ = other.buffer_;
+ if (IsShared()) buffer_.shared->Ref();
+ return *this;
+ }
+
+ MatcherBase(MatcherBase&& other)
+ : vtable_(other.vtable_), buffer_(other.buffer_) {
+ other.vtable_ = nullptr;
+ }
+
+ MatcherBase& operator=(MatcherBase&& other) {
+ if (this == &other) return *this;
+ Destroy();
+ vtable_ = other.vtable_;
+ buffer_ = other.buffer_;
+ other.vtable_ = nullptr;
+ return *this;
+ }
+
+ ~MatcherBase() override { Destroy(); }
+
+ private:
+ struct VTable {
+ bool (*match_and_explain)(const MatcherBase&, const T&,
+ MatchResultListener*);
+ void (*describe)(const MatcherBase&, std::ostream*, bool negation);
+ // Returns the captured object if it implements the interface, otherwise
+ // returns the MatcherBase itself.
+ const MatcherDescriberInterface* (*get_describer)(const MatcherBase&);
+ // Called on shared instances when the reference count reaches 0.
+ void (*shared_destroy)(SharedPayloadBase*);
+ };
+
+ bool IsShared() const {
+ return vtable_ != nullptr && vtable_->shared_destroy != nullptr;
+ }
+
+ // If the implementation uses a listener, call that.
+ template <typename P>
+ static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
+ MatchResultListener* listener)
+ -> decltype(P::Get(m).MatchAndExplain(value, listener->stream())) {
+ return P::Get(m).MatchAndExplain(value, listener->stream());
+ }
+
+ template <typename P>
+ static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
+ MatchResultListener* listener)
+ -> decltype(P::Get(m).MatchAndExplain(value, listener)) {
+ return P::Get(m).MatchAndExplain(value, listener);
+ }
+
+ template <typename P>
+ static void DescribeImpl(const MatcherBase& m, std::ostream* os,
+ bool negation) {
+ if (negation) {
+ P::Get(m).DescribeNegationTo(os);
+ } else {
+ P::Get(m).DescribeTo(os);
+ }
+ }
+
+ template <typename P>
+ static const MatcherDescriberInterface* GetDescriberImpl(
+ const MatcherBase& m) {
+ // If the impl is a MatcherDescriberInterface, then return it.
+ // Otherwise use MatcherBase itself.
+ // This allows us to implement the GetDescriber() function without support
+ // from the impl, but some users really want to get their impl back when
+ // they call GetDescriber().
+ // We use std::get on a tuple as a workaround of not having `if constexpr`.
+ return std::get<(
+ std::is_convertible<decltype(&P::Get(m)),
+ const MatcherDescriberInterface*>::value
+ ? 1
+ : 0)>(std::make_tuple(&m, &P::Get(m)));
+ }
+
+ template <typename P>
+ const VTable* GetVTable() {
+ static constexpr VTable kVTable = {&MatchAndExplainImpl<P>,
+ &DescribeImpl<P>, &GetDescriberImpl<P>,
+ P::shared_destroy};
+ return &kVTable;
+ }
+
+ union Buffer {
+ // Add some types to give Buffer some common alignment/size use cases.
+ void* ptr;
+ double d;
+ int64_t i;
+ // And add one for the out-of-line cases.
+ SharedPayloadBase* shared;
+ };
+
+ void Destroy() {
+ if (IsShared() && buffer_.shared->Unref()) {
+ vtable_->shared_destroy(buffer_.shared);
+ }
+ }
+
+ template <typename M>
+ static constexpr bool IsInlined() {
+ return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) &&
+ std::is_trivially_copy_constructible<M>::value &&
+ std::is_trivially_destructible<M>::value;
+ }
+
+ template <typename M, bool = MatcherBase::IsInlined<M>()>
+ struct ValuePolicy {
+ static const M& Get(const MatcherBase& m) {
+ // When inlined along with Init, need to be explicit to avoid violating
+ // strict aliasing rules.
+ const M* ptr =
+ static_cast<const M*>(static_cast<const void*>(&m.buffer_));
+ return *ptr;
+ }
+ static void Init(MatcherBase& m, M impl) {
+ ::new (static_cast<void*>(&m.buffer_)) M(impl);
+ }
+ static constexpr auto shared_destroy = nullptr;
+ };
+
+ template <typename M>
+ struct ValuePolicy<M, false> {
+ using Shared = SharedPayload<M>;
+ static const M& Get(const MatcherBase& m) {
+ return static_cast<Shared*>(m.buffer_.shared)->value;
+ }
+ template <typename Arg>
+ static void Init(MatcherBase& m, Arg&& arg) {
+ m.buffer_.shared = new Shared(std::forward<Arg>(arg));
+ }
+ static constexpr auto shared_destroy = &Shared::Destroy;
+ };
+
+ template <typename U, bool B>
+ struct ValuePolicy<const MatcherInterface<U>*, B> {
+ using M = const MatcherInterface<U>;
+ using Shared = SharedPayload<std::unique_ptr<M>>;
+ static const M& Get(const MatcherBase& m) {
+ return *static_cast<Shared*>(m.buffer_.shared)->value;
+ }
+ static void Init(MatcherBase& m, M* impl) {
+ m.buffer_.shared = new Shared(std::unique_ptr<M>(impl));
+ }
+
+ static constexpr auto shared_destroy = &Shared::Destroy;
+ };
+
+ template <typename M>
+ void Init(M&& m) {
+ using MM = typename std::decay<M>::type;
+ using Policy = ValuePolicy<MM>;
+ vtable_ = GetVTable<Policy>();
+ Policy::Init(*this, std::forward<M>(m));
+ }
+
+ const VTable* vtable_;
+ Buffer buffer_;
+};
+
+} // namespace internal
+
+// A Matcher<T> is a copyable and IMMUTABLE (except by assignment)
+// object that can check whether a value of type T matches. The
+// implementation of Matcher<T> is just a std::shared_ptr to const
+// MatcherInterface<T>. Don't inherit from Matcher!
+template <typename T>
+class Matcher : public internal::MatcherBase<T> {
+ public:
+ // Constructs a null matcher. Needed for storing Matcher objects in STL
+ // containers. A default-constructed matcher is not yet initialized. You
+ // cannot use it until a valid value has been assigned to it.
+ explicit Matcher() {} // NOLINT
+
+ // Constructs a matcher from its implementation.
+ explicit Matcher(const MatcherInterface<const T&>* impl)
+ : internal::MatcherBase<T>(impl) {}
+
+ template <typename U>
+ explicit Matcher(
+ const MatcherInterface<U>* impl,
+ typename std::enable_if<!std::is_same<U, const U&>::value>::type* =
+ nullptr)
+ : internal::MatcherBase<T>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) : internal::MatcherBase<T>(std::forward<M>(m)) {} // NOLINT
+
+ // Implicit constructor here allows people to write
+ // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes
+ Matcher(T value); // NOLINT
+};
+
+// The following two specializations allow the user to write str
+// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string
+// matcher is expected.
+template <>
+class GTEST_API_ Matcher<const std::string&>
+ : public internal::MatcherBase<const std::string&> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const std::string&>* impl)
+ : internal::MatcherBase<const std::string&>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) // NOLINT
+ : internal::MatcherBase<const std::string&>(std::forward<M>(m)) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+};
+
+template <>
+class GTEST_API_ Matcher<std::string>
+ : public internal::MatcherBase<std::string> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const std::string&>* impl)
+ : internal::MatcherBase<std::string>(impl) {}
+ explicit Matcher(const MatcherInterface<std::string>* impl)
+ : internal::MatcherBase<std::string>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) // NOLINT
+ : internal::MatcherBase<std::string>(std::forward<M>(m)) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+};
+
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+// The following two specializations allow the user to write str
+// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view
+// matcher is expected.
+template <>
+class GTEST_API_ Matcher<const internal::StringView&>
+ : public internal::MatcherBase<const internal::StringView&> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
+ : internal::MatcherBase<const internal::StringView&>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) // NOLINT
+ : internal::MatcherBase<const internal::StringView&>(std::forward<M>(m)) {
+ }
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+
+ // Allows the user to pass absl::string_views or std::string_views directly.
+ Matcher(internal::StringView s); // NOLINT
+};
+
+template <>
+class GTEST_API_ Matcher<internal::StringView>
+ : public internal::MatcherBase<internal::StringView> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
+ : internal::MatcherBase<internal::StringView>(impl) {}
+ explicit Matcher(const MatcherInterface<internal::StringView>* impl)
+ : internal::MatcherBase<internal::StringView>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) // NOLINT
+ : internal::MatcherBase<internal::StringView>(std::forward<M>(m)) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+
+ // Allows the user to pass absl::string_views or std::string_views directly.
+ Matcher(internal::StringView s); // NOLINT
+};
+#endif // GTEST_INTERNAL_HAS_STRING_VIEW
+
+// Prints a matcher in a human-readable format.
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const Matcher<T>& matcher) {
+ matcher.DescribeTo(&os);
+ return os;
+}
+
+// The PolymorphicMatcher class template makes it easy to implement a
+// polymorphic matcher (i.e. a matcher that can match values of more
+// than one type, e.g. Eq(n) and NotNull()).
+//
+// To define a polymorphic matcher, a user should provide an Impl
+// class that has a DescribeTo() method and a DescribeNegationTo()
+// method, and define a member function (or member function template)
+//
+// bool MatchAndExplain(const Value& value,
+// MatchResultListener* listener) const;
+//
+// See the definition of NotNull() for a complete example.
+template <class Impl>
+class PolymorphicMatcher {
+ public:
+ explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {}
+
+ // Returns a mutable reference to the underlying matcher
+ // implementation object.
+ Impl& mutable_impl() { return impl_; }
+
+ // Returns an immutable reference to the underlying matcher
+ // implementation object.
+ const Impl& impl() const { return impl_; }
+
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new MonomorphicImpl<const T&>(impl_));
+ }
+
+ private:
+ template <typename T>
+ class MonomorphicImpl : public MatcherInterface<T> {
+ public:
+ explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
+
+ void DescribeTo(::std::ostream* os) const override { impl_.DescribeTo(os); }
+
+ void DescribeNegationTo(::std::ostream* os) const override {
+ impl_.DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(T x, MatchResultListener* listener) const override {
+ return impl_.MatchAndExplain(x, listener);
+ }
+
+ private:
+ const Impl impl_;
+ };
+
+ Impl impl_;
+};
+
+// Creates a matcher from its implementation.
+// DEPRECATED: Especially in the generic code, prefer:
+// Matcher<T>(new MyMatcherImpl<const T&>(...));
+//
+// MakeMatcher may create a Matcher that accepts its argument by value, which
+// leads to unnecessary copies & lack of support for non-copyable types.
+template <typename T>
+inline Matcher<T> MakeMatcher(const MatcherInterface<T>* impl) {
+ return Matcher<T>(impl);
+}
+
+// Creates a polymorphic matcher from its implementation. This is
+// easier to use than the PolymorphicMatcher<Impl> constructor as it
+// doesn't require you to explicitly write the template argument, e.g.
+//
+// MakePolymorphicMatcher(foo);
+// vs
+// PolymorphicMatcher<TypeOfFoo>(foo);
+template <class Impl>
+inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) {
+ return PolymorphicMatcher<Impl>(impl);
+}
+
+namespace internal {
+// Implements a matcher that compares a given value with a
+// pre-supplied value using one of the ==, <=, <, etc, operators. The
+// two values being compared don't have to have the same type.
+//
+// The matcher defined here is polymorphic (for example, Eq(5) can be
+// used to match an int, a short, a double, etc). Therefore we use
+// a template type conversion operator in the implementation.
+//
+// The following template definition assumes that the Rhs parameter is
+// a "bare" type (i.e. neither 'const T' nor 'T&').
+template <typename D, typename Rhs, typename Op>
+class ComparisonBase {
+ public:
+ explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {}
+
+ using is_gtest_matcher = void;
+
+ template <typename Lhs>
+ bool MatchAndExplain(const Lhs& lhs, std::ostream*) const {
+ return Op()(lhs, Unwrap(rhs_));
+ }
+ void DescribeTo(std::ostream* os) const {
+ *os << D::Desc() << " ";
+ UniversalPrint(Unwrap(rhs_), os);
+ }
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << D::NegatedDesc() << " ";
+ UniversalPrint(Unwrap(rhs_), os);
+ }
+
+ private:
+ template <typename T>
+ static const T& Unwrap(const T& v) {
+ return v;
+ }
+ template <typename T>
+ static const T& Unwrap(std::reference_wrapper<T> v) {
+ return v;
+ }
+
+ Rhs rhs_;
+};
+
+template <typename Rhs>
+class EqMatcher : public ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq> {
+ public:
+ explicit EqMatcher(const Rhs& rhs)
+ : ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq>(rhs) {}
+ static const char* Desc() { return "is equal to"; }
+ static const char* NegatedDesc() { return "isn't equal to"; }
+};
+template <typename Rhs>
+class NeMatcher : public ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe> {
+ public:
+ explicit NeMatcher(const Rhs& rhs)
+ : ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe>(rhs) {}
+ static const char* Desc() { return "isn't equal to"; }
+ static const char* NegatedDesc() { return "is equal to"; }
+};
+template <typename Rhs>
+class LtMatcher : public ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt> {
+ public:
+ explicit LtMatcher(const Rhs& rhs)
+ : ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt>(rhs) {}
+ static const char* Desc() { return "is <"; }
+ static const char* NegatedDesc() { return "isn't <"; }
+};
+template <typename Rhs>
+class GtMatcher : public ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt> {
+ public:
+ explicit GtMatcher(const Rhs& rhs)
+ : ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt>(rhs) {}
+ static const char* Desc() { return "is >"; }
+ static const char* NegatedDesc() { return "isn't >"; }
+};
+template <typename Rhs>
+class LeMatcher : public ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe> {
+ public:
+ explicit LeMatcher(const Rhs& rhs)
+ : ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe>(rhs) {}
+ static const char* Desc() { return "is <="; }
+ static const char* NegatedDesc() { return "isn't <="; }
+};
+template <typename Rhs>
+class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> {
+ public:
+ explicit GeMatcher(const Rhs& rhs)
+ : ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe>(rhs) {}
+ static const char* Desc() { return "is >="; }
+ static const char* NegatedDesc() { return "isn't >="; }
+};
+
+template <typename T, typename = typename std::enable_if<
+ std::is_constructible<std::string, T>::value>::type>
+using StringLike = T;
+
+// Implements polymorphic matchers MatchesRegex(regex) and
+// ContainsRegex(regex), which can be used as a Matcher<T> as long as
+// T can be converted to a string.
+class MatchesRegexMatcher {
+ public:
+ MatchesRegexMatcher(const RE* regex, bool full_match)
+ : regex_(regex), full_match_(full_match) {}
+
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+ bool MatchAndExplain(const internal::StringView& s,
+ MatchResultListener* listener) const {
+ return MatchAndExplain(std::string(s), listener);
+ }
+#endif // GTEST_INTERNAL_HAS_STRING_VIEW
+
+ // Accepts pointer types, particularly:
+ // const char*
+ // char*
+ // const wchar_t*
+ // wchar_t*
+ template <typename CharType>
+ bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
+ return s != nullptr && MatchAndExplain(std::string(s), listener);
+ }
+
+ // Matches anything that can convert to std::string.
+ //
+ // This is a template, not just a plain function with const std::string&,
+ // because absl::string_view has some interfering non-explicit constructors.
+ template <class MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType& s,
+ MatchResultListener* /* listener */) const {
+ const std::string& s2(s);
+ return full_match_ ? RE::FullMatch(s2, *regex_)
+ : RE::PartialMatch(s2, *regex_);
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << (full_match_ ? "matches" : "contains") << " regular expression ";
+ UniversalPrinter<std::string>::Print(regex_->pattern(), os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't " << (full_match_ ? "match" : "contain")
+ << " regular expression ";
+ UniversalPrinter<std::string>::Print(regex_->pattern(), os);
+ }
+
+ private:
+ const std::shared_ptr<const RE> regex_;
+ const bool full_match_;
+};
+} // namespace internal
+
+// Matches a string that fully matches regular expression 'regex'.
+// The matcher takes ownership of 'regex'.
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+ const internal::RE* regex) {
+ return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
+}
+template <typename T = std::string>
+PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+ const internal::StringLike<T>& regex) {
+ return MatchesRegex(new internal::RE(std::string(regex)));
+}
+
+// Matches a string that contains regular expression 'regex'.
+// The matcher takes ownership of 'regex'.
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+ const internal::RE* regex) {
+ return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
+}
+template <typename T = std::string>
+PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+ const internal::StringLike<T>& regex) {
+ return ContainsRegex(new internal::RE(std::string(regex)));
+}
+
+// Creates a polymorphic matcher that matches anything equal to x.
+// Note: if the parameter of Eq() were declared as const T&, Eq("foo")
+// wouldn't compile.
+template <typename T>
+inline internal::EqMatcher<T> Eq(T x) {
+ return internal::EqMatcher<T>(x);
+}
+
+// Constructs a Matcher<T> from a 'value' of type T. The constructed
+// matcher matches any value that's equal to 'value'.
+template <typename T>
+Matcher<T>::Matcher(T value) {
+ *this = Eq(value);
+}
+
+// Creates a monomorphic matcher that matches anything with type Lhs
+// and equal to rhs. A user may need to use this instead of Eq(...)
+// in order to resolve an overloading ambiguity.
+//
+// TypedEq<T>(x) is just a convenient short-hand for Matcher<T>(Eq(x))
+// or Matcher<T>(x), but more readable than the latter.
+//
+// We could define similar monomorphic matchers for other comparison
+// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do
+// it yet as those are used much less than Eq() in practice. A user
+// can always write Matcher<T>(Lt(5)) to be explicit about the type,
+// for example.
+template <typename Lhs, typename Rhs>
+inline Matcher<Lhs> TypedEq(const Rhs& rhs) {
+ return Eq(rhs);
+}
+
+// Creates a polymorphic matcher that matches anything >= x.
+template <typename Rhs>
+inline internal::GeMatcher<Rhs> Ge(Rhs x) {
+ return internal::GeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything > x.
+template <typename Rhs>
+inline internal::GtMatcher<Rhs> Gt(Rhs x) {
+ return internal::GtMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything <= x.
+template <typename Rhs>
+inline internal::LeMatcher<Rhs> Le(Rhs x) {
+ return internal::LeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything < x.
+template <typename Rhs>
+inline internal::LtMatcher<Rhs> Lt(Rhs x) {
+ return internal::LtMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything != x.
+template <typename Rhs>
+inline internal::NeMatcher<Rhs> Ne(Rhs x) {
+ return internal::NeMatcher<Rhs>(x);
+}
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-message.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-message.h
new file mode 100644
index 0000000..6c8bf90
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-message.h
@@ -0,0 +1,218 @@
+// 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.
+
+// The Google C++ Testing and Mocking 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!
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <limits>
+#include <memory>
+#include <sstream>
+
+#include "gtest/internal/gtest-port.h"
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// Ensures that there is at least one operator<< in the global namespace.
+// See Message& operator<<(...) below for why.
+void operator<<(const testing::internal::Secret&, int);
+
+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.
+ Message();
+
+ // 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;
+ }
+
+ // Streams a non-pointer value to this object.
+ template <typename T>
+ inline Message& operator<<(const T& val) {
+ // Some libraries overload << for STL containers. These
+ // overloads are defined in the global namespace instead of ::std.
+ //
+ // 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. With this using declaration,
+ // overloads of << defined in the global namespace and those
+ // visible via Koenig lookup are both exposed in this function.
+ using ::operator<<;
+ *ss_ << 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 <typename T>
+ inline Message& operator<<(T* const& pointer) { // NOLINT
+ if (pointer == nullptr) {
+ *ss_ << "(null)";
+ } else {
+ *ss_ << pointer;
+ }
+ return *this;
+ }
+
+ // 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);
+ Message& operator<<(wchar_t* 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
+
+ // Gets the text streamed to this object so far as an std::string.
+ // Each '\0' character in the buffer is replaced with "\\0".
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ std::string GetString() const;
+
+ private:
+ // We'll hold the text streamed to this object here.
+ const std::unique_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 internal {
+
+// Converts a streamable value to an std::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".
+template <typename T>
+std::string StreamableToString(const T& streamable) {
+ return (Message() << streamable).GetString();
+}
+
+} // namespace internal
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-param-test.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-param-test.h
new file mode 100644
index 0000000..b55119a
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-param-test.h
@@ -0,0 +1,510 @@
+// 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.
+
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing and Mocking Framework (Google Test)
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GOOGLETEST_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<T> (see below for
+// another inheritance scheme that's sometimes useful in more complicated
+// class hierarchies), where the type of your parameter values.
+// TestWithParam<T> 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<const char*> {
+ // 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<T> class:
+ EXPECT_TRUE(foo.Blah(GetParam()));
+ ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+ ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_SUITE_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 suite
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_SUITE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more than once) the first argument to the
+// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the
+// actual test suite 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_SUITE_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_SUITE_P will instantiate all tests
+// in the given test suite, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_SUITE_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<T>, where T is the type of the parameter
+// values. Inheriting from TestWithParam<T> satisfies that requirement because
+// TestWithParam<T> 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<int> {
+ // 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
+
+#include <iterator>
+#include <utility>
+
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test suite 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 suite FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_SUITE_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 <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+ return internal::ParamGenerator<T>(
+ new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> 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 suite StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings));
+//
+// This instantiates tests from test suite 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_SUITE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+// ::std::list<char> list;
+// list.push_back('a');
+// list.push_back('b');
+// return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_SUITE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename std::iterator_traits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end) {
+ typedef typename std::iterator_traits<ForwardIterator>::value_type ParamType;
+ return internal::ParamGenerator<ParamType>(
+ new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+ return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> 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 suite BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_SUITE_P(NumSequence,
+// BarTest,
+// Values("one", "two", "three"));
+//
+// This instantiates tests from test suite BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+//
+template <typename... T>
+internal::ValueArray<T...> Values(T... v) {
+ return internal::ValueArray<T...>(std::move(v)...);
+}
+
+// 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 suite FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+// virtual void SetUp() {
+// external_flag = GetParam();
+// }
+// }
+// INSTANTIATE_TEST_SUITE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() { return Values(false, true); }
+
+// 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
+// std::tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Example:
+//
+// This will instantiate tests in test suite 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<std::tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_SUITE_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<std::tuple<bool, bool> > {
+// virtual void SetUp() {
+// // Assigns external_flag_1 and external_flag_2 values from the tuple.
+// std::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_SUITE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+template <typename... Generator>
+internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
+ return internal::CartesianProductHolder<Generator...>(g...);
+}
+
+#define TEST_P(test_suite_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ : public test_suite_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \
+ void TestBody() override; \
+ \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance() \
+ ->parameterized_test_registry() \
+ .GetTestSuitePatternHolder<test_suite_name>( \
+ GTEST_STRINGIFY_(test_suite_name), \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \
+ ->AddTestPattern( \
+ GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \
+ new ::testing::internal::TestMetaFactory<GTEST_TEST_CLASS_NAME_( \
+ test_suite_name, test_name)>(), \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__)); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ (const GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) &) = delete; \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) & operator=( \
+ const GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name) &) = delete; /* NOLINT */ \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody()
+
+// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify
+// generator and an optional function or functor that generates custom test name
+// suffixes based on the test parameters. Such a function or functor should
+// accept one argument of type testing::TestParamInfo<class ParamType>, and
+// return std::string.
+//
+// testing::PrintToStringParamName is a builtin test suffix generator that
+// returns the value of testing::PrintToString(GetParam()).
+//
+// Note: test names must be non-empty, unique, and may only contain ASCII
+// alphanumeric characters or underscore. Because PrintToString adds quotes
+// to std::string and C strings, it won't work for these types.
+
+#define GTEST_EXPAND_(arg) arg
+#define GTEST_GET_FIRST_(first, ...) first
+#define GTEST_GET_SECOND_(first, second, ...) second
+
+#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \
+ static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \
+ gtest_##prefix##test_suite_name##_EvalGenerator_() { \
+ return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \
+ } \
+ static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \
+ const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \
+ if (::testing::internal::AlwaysFalse()) { \
+ ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \
+ __VA_ARGS__, \
+ ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
+ DUMMY_PARAM_))); \
+ auto t = std::make_tuple(__VA_ARGS__); \
+ static_assert(std::tuple_size<decltype(t)>::value <= 2, \
+ "Too Many Args!"); \
+ } \
+ return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \
+ __VA_ARGS__, \
+ ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
+ DUMMY_PARAM_))))(info); \
+ } \
+ static int gtest_##prefix##test_suite_name##_dummy_ \
+ GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::UnitTest::GetInstance() \
+ ->parameterized_test_registry() \
+ .GetTestSuitePatternHolder<test_suite_name>( \
+ GTEST_STRINGIFY_(test_suite_name), \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \
+ ->AddTestSuiteInstantiation( \
+ GTEST_STRINGIFY_(prefix), \
+ &gtest_##prefix##test_suite_name##_EvalGenerator_, \
+ &gtest_##prefix##test_suite_name##_EvalGenerateName_, \
+ __FILE__, __LINE__)
+
+// Allow Marking a Parameterized test class as not needing to be instantiated.
+#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T) \
+ namespace gtest_do_not_use_outside_namespace_scope {} \
+ static const ::testing::internal::MarkAsIgnored gtest_allow_ignore_##T( \
+ GTEST_STRINGIFY_(T))
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define INSTANTIATE_TEST_CASE_P \
+ static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \
+ ""); \
+ INSTANTIATE_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-printers.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-printers.h
new file mode 100644
index 0000000..a91e8b8
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-printers.h
@@ -0,0 +1,1048 @@
+// 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.
+
+// Google Test - The Google C++ Testing and Mocking Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+// void ::testing::internal::UniversalPrinter<T>::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.
+//
+// However if T is an STL-style container then it is printed element-wise
+// unless foo::PrintTo(const T&, ostream*) is defined. Note that
+// operator<<() is ignored for container types.
+//
+// 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<string> 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.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+#include <functional>
+#include <memory>
+#include <ostream> // NOLINT
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+
+// Definitions in the internal* namespaces are subject to change without notice.
+// DO NOT USE THEM IN USER CODE!
+namespace internal {
+
+template <typename T>
+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.
+struct ContainerPrinter {
+ template <typename T,
+ typename = typename std::enable_if<
+ (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
+ !IsRecursiveContainer<T>::value>::type>
+ static void PrintValue(const T& container, std::ostream* os) {
+ const size_t kMaxCount = 32; // The maximum number of elements to print.
+ *os << '{';
+ size_t count = 0;
+ for (auto&& elem : container) {
+ if (count > 0) {
+ *os << ',';
+ if (count == kMaxCount) { // Enough has been printed.
+ *os << " ...";
+ break;
+ }
+ }
+ *os << ' ';
+ // We cannot call PrintTo(elem, os) here as PrintTo() doesn't
+ // handle `elem` being a native array.
+ internal::UniversalPrint(elem, os);
+ ++count;
+ }
+
+ 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.)
+struct FunctionPointerPrinter {
+ template <typename T, typename = typename std::enable_if<
+ std::is_function<T>::value>::type>
+ static void PrintValue(T* p, ::std::ostream* os) {
+ if (p == nullptr) {
+ *os << "NULL";
+ } 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*.
+ *os << reinterpret_cast<const void*>(p);
+ }
+ }
+};
+
+struct PointerPrinter {
+ template <typename T>
+ static void PrintValue(T* p, ::std::ostream* os) {
+ if (p == nullptr) {
+ *os << "NULL";
+ } else {
+ // 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;
+ }
+ }
+};
+
+namespace internal_stream_operator_without_lexical_name_lookup {
+
+// The presence of an operator<< here will terminate lexical scope lookup
+// straight away (even though it cannot be a match because of its argument
+// types). Thus, the two operator<< calls in StreamPrinter will find only ADL
+// candidates.
+struct LookupBlocker {};
+void operator<<(LookupBlocker, LookupBlocker);
+
+struct StreamPrinter {
+ template <typename T,
+ // Don't accept member pointers here. We'd print them via implicit
+ // conversion to bool, which isn't useful.
+ typename = typename std::enable_if<
+ !std::is_member_pointer<T>::value>::type,
+ // Only accept types for which we can find a streaming operator via
+ // ADL (possibly involving implicit conversions).
+ typename = decltype(std::declval<std::ostream&>()
+ << std::declval<const T&>())>
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ // Call streaming operator found by ADL, possibly with implicit conversions
+ // of the arguments.
+ *os << value;
+ }
+};
+
+} // namespace internal_stream_operator_without_lexical_name_lookup
+
+struct ProtobufPrinter {
+ // 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.
+ static const size_t kProtobufOneLinerMaxLength = 50;
+
+ template <typename T,
+ typename = typename std::enable_if<
+ internal::HasDebugStringAndShortDebugString<T>::value>::type>
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ std::string pretty_str = value.ShortDebugString();
+ if (pretty_str.length() > kProtobufOneLinerMaxLength) {
+ pretty_str = "\n" + value.DebugString();
+ }
+ *os << ("<" + pretty_str + ">");
+ }
+};
+
+struct ConvertibleToIntegerPrinter {
+ // 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(internal::BiggestInt value, ::std::ostream* os) {
+ *os << value;
+ }
+};
+
+struct ConvertibleToStringViewPrinter {
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+ static void PrintValue(internal::StringView value, ::std::ostream* os) {
+ internal::UniversalPrint(value, os);
+ }
+#endif
+};
+
+// 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);
+struct RawBytesPrinter {
+ // SFINAE on `sizeof` to make sure we have a complete type.
+ template <typename T, size_t = sizeof(T)>
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ PrintBytesInObjectTo(
+ static_cast<const unsigned char*>(
+ // Load bearing cast to void* to support iOS
+ reinterpret_cast<const void*>(std::addressof(value))),
+ sizeof(value), os);
+ }
+};
+
+struct FallbackPrinter {
+ template <typename T>
+ static void PrintValue(const T&, ::std::ostream* os) {
+ *os << "(incomplete type)";
+ }
+};
+
+// Try every printer in order and return the first one that works.
+template <typename T, typename E, typename Printer, typename... Printers>
+struct FindFirstPrinter : FindFirstPrinter<T, E, Printers...> {};
+
+template <typename T, typename Printer, typename... Printers>
+struct FindFirstPrinter<
+ T, decltype(Printer::PrintValue(std::declval<const T&>(), nullptr)),
+ Printer, Printers...> {
+ using type = Printer;
+};
+
+// Select the best printer in the following order:
+// - Print containers (they have begin/end/etc).
+// - Print function pointers.
+// - Print object pointers.
+// - Use the stream operator, if available.
+// - Print protocol buffers.
+// - Print types convertible to BiggestInt.
+// - Print types convertible to StringView, if available.
+// - Fallback to printing the raw bytes of the object.
+template <typename T>
+void PrintWithFallback(const T& value, ::std::ostream* os) {
+ using Printer = typename FindFirstPrinter<
+ T, void, ContainerPrinter, FunctionPointerPrinter, PointerPrinter,
+ internal_stream_operator_without_lexical_name_lookup::StreamPrinter,
+ ProtobufPrinter, ConvertibleToIntegerPrinter,
+ ConvertibleToStringViewPrinter, RawBytesPrinter, FallbackPrinter>::type;
+ Printer::PrintValue(value, os);
+}
+
+// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
+// value of type ToPrint that is an operand of a comparison assertion
+// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
+// the comparison, and is used to help determine the best way to
+// format the value. In particular, when the value is a C string
+// (char pointer) and the other operand is an STL string object, we
+// want to format the C string as a string, since we know it is
+// compared by value with the string object. If the value is a char
+// pointer but the other operand is not an STL string object, we don't
+// know whether the pointer is supposed to point to a NUL-terminated
+// string, and thus want to print it as a pointer to be safe.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// The default case.
+template <typename ToPrint, typename OtherOperand>
+class FormatForComparison {
+ public:
+ static ::std::string Format(const ToPrint& value) {
+ return ::testing::PrintToString(value);
+ }
+};
+
+// Array.
+template <typename ToPrint, size_t N, typename OtherOperand>
+class FormatForComparison<ToPrint[N], OtherOperand> {
+ public:
+ static ::std::string Format(const ToPrint* value) {
+ return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
+ }
+};
+
+// By default, print C string as pointers to be safe, as we don't know
+// whether they actually point to a NUL-terminated string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
+ template <typename OtherOperand> \
+ class FormatForComparison<CharType*, OtherOperand> { \
+ public: \
+ static ::std::string Format(CharType* value) { \
+ return ::testing::PrintToString(static_cast<const void*>(value)); \
+ } \
+ }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
+#ifdef __cpp_lib_char8_t
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char8_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char8_t);
+#endif
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char16_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char16_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char32_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char32_t);
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
+
+// If a C string is compared with an STL string object, we know it's meant
+// to point to a NUL-terminated string, and thus can print it as a string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
+ template <> \
+ class FormatForComparison<CharType*, OtherStringType> { \
+ public: \
+ static ::std::string Format(CharType* value) { \
+ return ::testing::PrintToString(value); \
+ } \
+ }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
+#ifdef __cpp_char8_t
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char8_t, ::std::u8string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char8_t, ::std::u8string);
+#endif
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char16_t, ::std::u16string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char16_t, ::std::u16string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char32_t, ::std::u32string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char32_t, ::std::u32string);
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
+#endif
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
+
+// 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* or void*, and print it as a C string when it is compared
+// against an std::string object, for example.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+std::string FormatForComparisonFailureMessage(const T1& value,
+ const T2& /* other_operand */) {
+ return FormatForComparison<T1, T2>::Format(value);
+}
+
+// UniversalPrinter<T>::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 <typename T>
+class UniversalPrinter;
+
+// Prints the given value using the << operator if it has one;
+// otherwise prints the bytes in it. This is what
+// UniversalPrinter<T>::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 <typename T>
+void PrintTo(const T& value, ::std::ostream* os) {
+ internal::PrintWithFallback(value, os);
+}
+
+// The following list of PrintTo() overloads tells
+// UniversalPrinter<T>::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<unsigned char>(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);
+
+GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os);
+inline void PrintTo(char16_t c, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<char32_t>(c), os);
+}
+#ifdef __cpp_char8_t
+inline void PrintTo(char8_t c, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<char32_t>(c), os);
+}
+#endif
+
+// gcc/clang __{u,}int128_t
+#if defined(__SIZEOF_INT128__)
+GTEST_API_ void PrintTo(__uint128_t v, ::std::ostream* os);
+GTEST_API_ void PrintTo(__int128_t v, ::std::ostream* os);
+#endif // __SIZEOF_INT128__
+
+// Overloads for C strings.
+GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
+inline void PrintTo(char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char*>(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_<const void*>(s), os);
+}
+inline void PrintTo(signed char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(unsigned char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+#ifdef __cpp_char8_t
+// Overloads for u8 strings.
+GTEST_API_ void PrintTo(const char8_t* s, ::std::ostream* os);
+inline void PrintTo(char8_t* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char8_t*>(s), os);
+}
+#endif
+// Overloads for u16 strings.
+GTEST_API_ void PrintTo(const char16_t* s, ::std::ostream* os);
+inline void PrintTo(char16_t* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char16_t*>(s), os);
+}
+// Overloads for u32 strings.
+GTEST_API_ void PrintTo(const char32_t* s, ::std::ostream* os);
+inline void PrintTo(char32_t* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char32_t*>(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_<const wchar_t*>(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 <typename T>
+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 ::std::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 ::std::u8string
+#ifdef __cpp_char8_t
+GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) {
+ PrintU8StringTo(s, os);
+}
+#endif
+
+// Overloads for ::std::u16string
+GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) {
+ PrintU16StringTo(s, os);
+}
+
+// Overloads for ::std::u32string
+GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) {
+ PrintU32StringTo(s, os);
+}
+
+// Overloads for ::std::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_INTERNAL_HAS_STRING_VIEW
+// Overload for internal::StringView.
+inline void PrintTo(internal::StringView sp, ::std::ostream* os) {
+ PrintTo(::std::string(sp), os);
+}
+#endif // GTEST_INTERNAL_HAS_STRING_VIEW
+
+inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; }
+
+#if GTEST_HAS_RTTI
+inline void PrintTo(const std::type_info& info, std::ostream* os) {
+ *os << internal::GetTypeName(info);
+}
+#endif // GTEST_HAS_RTTI
+
+template <typename T>
+void PrintTo(std::reference_wrapper<T> ref, ::std::ostream* os) {
+ UniversalPrinter<T&>::Print(ref.get(), os);
+}
+
+inline const void* VoidifyPointer(const void* p) { return p; }
+inline const void* VoidifyPointer(volatile const void* p) {
+ return const_cast<const void*>(p);
+}
+
+template <typename T, typename Ptr>
+void PrintSmartPointer(const Ptr& ptr, std::ostream* os, char) {
+ if (ptr == nullptr) {
+ *os << "(nullptr)";
+ } else {
+ // We can't print the value. Just print the pointer..
+ *os << "(" << (VoidifyPointer)(ptr.get()) << ")";
+ }
+}
+template <typename T, typename Ptr,
+ typename = typename std::enable_if<!std::is_void<T>::value &&
+ !std::is_array<T>::value>::type>
+void PrintSmartPointer(const Ptr& ptr, std::ostream* os, int) {
+ if (ptr == nullptr) {
+ *os << "(nullptr)";
+ } else {
+ *os << "(ptr = " << (VoidifyPointer)(ptr.get()) << ", value = ";
+ UniversalPrinter<T>::Print(*ptr, os);
+ *os << ")";
+ }
+}
+
+template <typename T, typename D>
+void PrintTo(const std::unique_ptr<T, D>& ptr, std::ostream* os) {
+ (PrintSmartPointer<T>)(ptr, os, 0);
+}
+
+template <typename T>
+void PrintTo(const std::shared_ptr<T>& ptr, std::ostream* os) {
+ (PrintSmartPointer<T>)(ptr, os, 0);
+}
+
+// Helper function for printing a tuple. T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T&, std::integral_constant<size_t, 0>,
+ ::std::ostream*) {}
+
+template <typename T, size_t I>
+void PrintTupleTo(const T& t, std::integral_constant<size_t, I>,
+ ::std::ostream* os) {
+ PrintTupleTo(t, std::integral_constant<size_t, I - 1>(), os);
+ GTEST_INTENTIONAL_CONST_COND_PUSH_()
+ if (I > 1) {
+ GTEST_INTENTIONAL_CONST_COND_POP_()
+ *os << ", ";
+ }
+ UniversalPrinter<typename std::tuple_element<I - 1, T>::type>::Print(
+ std::get<I - 1>(t), os);
+}
+
+template <typename... Types>
+void PrintTo(const ::std::tuple<Types...>& t, ::std::ostream* os) {
+ *os << "(";
+ PrintTupleTo(t, std::integral_constant<size_t, sizeof...(Types)>(), os);
+ *os << ")";
+}
+
+// Overload for std::pair.
+template <typename T1, typename T2>
+void PrintTo(const ::std::pair<T1, T2>& 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<T1>::Print(value.first, os);
+ *os << ", ";
+ UniversalPrinter<T2>::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 <typename T>
+class UniversalPrinter {
+ public:
+ // MSVC warns about adding const to a function type, so we want to
+ // disable the warning.
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
+
+ // 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);
+ }
+
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+};
+
+// Remove any const-qualifiers before passing a type to UniversalPrinter.
+template <typename T>
+class UniversalPrinter<const T> : public UniversalPrinter<T> {};
+
+#if GTEST_INTERNAL_HAS_ANY
+
+// Printer for std::any / absl::any
+
+template <>
+class UniversalPrinter<Any> {
+ public:
+ static void Print(const Any& value, ::std::ostream* os) {
+ if (value.has_value()) {
+ *os << "value of type " << GetTypeName(value);
+ } else {
+ *os << "no value";
+ }
+ }
+
+ private:
+ static std::string GetTypeName(const Any& value) {
+#if GTEST_HAS_RTTI
+ return internal::GetTypeName(value.type());
+#else
+ static_cast<void>(value); // possibly unused
+ return "<unknown_type>";
+#endif // GTEST_HAS_RTTI
+ }
+};
+
+#endif // GTEST_INTERNAL_HAS_ANY
+
+#if GTEST_INTERNAL_HAS_OPTIONAL
+
+// Printer for std::optional / absl::optional
+
+template <typename T>
+class UniversalPrinter<Optional<T>> {
+ public:
+ static void Print(const Optional<T>& value, ::std::ostream* os) {
+ *os << '(';
+ if (!value) {
+ *os << "nullopt";
+ } else {
+ UniversalPrint(*value, os);
+ }
+ *os << ')';
+ }
+};
+
+template <>
+class UniversalPrinter<decltype(Nullopt())> {
+ public:
+ static void Print(decltype(Nullopt()), ::std::ostream* os) {
+ *os << "(nullopt)";
+ }
+};
+
+#endif // GTEST_INTERNAL_HAS_OPTIONAL
+
+#if GTEST_INTERNAL_HAS_VARIANT
+
+// Printer for std::variant / absl::variant
+
+template <typename... T>
+class UniversalPrinter<Variant<T...>> {
+ public:
+ static void Print(const Variant<T...>& value, ::std::ostream* os) {
+ *os << '(';
+#if GTEST_HAS_ABSL
+ absl::visit(Visitor{os, value.index()}, value);
+#else
+ std::visit(Visitor{os, value.index()}, value);
+#endif // GTEST_HAS_ABSL
+ *os << ')';
+ }
+
+ private:
+ struct Visitor {
+ template <typename U>
+ void operator()(const U& u) const {
+ *os << "'" << GetTypeName<U>() << "(index = " << index
+ << ")' with value ";
+ UniversalPrint(u, os);
+ }
+ ::std::ostream* os;
+ std::size_t index;
+ };
+};
+
+#endif // GTEST_INTERNAL_HAS_VARIANT
+
+// UniversalPrintArray(begin, len, os) prints an array of 'len'
+// elements, starting at address 'begin'.
+template <typename T>
+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.
+ 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);
+
+#ifdef __cpp_char8_t
+// This overload prints a (const) char8_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char8_t* begin, size_t len,
+ ::std::ostream* os);
+#endif
+
+// This overload prints a (const) char16_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char16_t* begin, size_t len,
+ ::std::ostream* os);
+
+// This overload prints a (const) char32_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char32_t* begin, size_t len,
+ ::std::ostream* os);
+
+// This overload prints a (const) wchar_t array compactly.
+GTEST_API_ void UniversalPrintArray(const wchar_t* begin, size_t len,
+ ::std::ostream* os);
+
+// Implements printing an array type T[N].
+template <typename T, size_t N>
+class UniversalPrinter<T[N]> {
+ 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 <typename T>
+class UniversalPrinter<T&> {
+ public:
+ // MSVC warns about adding const to a function type, so we want to
+ // disable the warning.
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
+
+ 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<const void*>(&value) << " ";
+
+ // Then prints the value itself.
+ UniversalPrint(value, os);
+ }
+
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+};
+
+// 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 <typename T>
+class UniversalTersePrinter {
+ public:
+ static void Print(const T& value, ::std::ostream* os) {
+ UniversalPrint(value, os);
+ }
+};
+template <typename T>
+class UniversalTersePrinter<T&> {
+ public:
+ static void Print(const T& value, ::std::ostream* os) {
+ UniversalPrint(value, os);
+ }
+};
+template <typename T, size_t N>
+class UniversalTersePrinter<T[N]> {
+ public:
+ static void Print(const T (&value)[N], ::std::ostream* os) {
+ UniversalPrinter<T[N]>::Print(value, os);
+ }
+};
+template <>
+class UniversalTersePrinter<const char*> {
+ public:
+ static void Print(const char* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(std::string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char*> : public UniversalTersePrinter<const char*> {
+};
+
+#ifdef __cpp_char8_t
+template <>
+class UniversalTersePrinter<const char8_t*> {
+ public:
+ static void Print(const char8_t* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::u8string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char8_t*>
+ : public UniversalTersePrinter<const char8_t*> {};
+#endif
+
+template <>
+class UniversalTersePrinter<const char16_t*> {
+ public:
+ static void Print(const char16_t* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::u16string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char16_t*>
+ : public UniversalTersePrinter<const char16_t*> {};
+
+template <>
+class UniversalTersePrinter<const char32_t*> {
+ public:
+ static void Print(const char32_t* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::u32string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char32_t*>
+ : public UniversalTersePrinter<const char32_t*> {};
+
+#if GTEST_HAS_STD_WSTRING
+template <>
+class UniversalTersePrinter<const wchar_t*> {
+ public:
+ static void Print(const wchar_t* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::wstring(str), os);
+ }
+ }
+};
+#endif
+
+template <>
+class UniversalTersePrinter<wchar_t*> {
+ public:
+ static void Print(wchar_t* str, ::std::ostream* os) {
+ UniversalTersePrinter<const wchar_t*>::Print(str, os);
+ }
+};
+
+template <typename T>
+void UniversalTersePrint(const T& value, ::std::ostream* os) {
+ UniversalTersePrinter<T>::Print(value, 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 <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os) {
+ // A workarond for the bug in VC++ 7.1 that prevents us from instantiating
+ // UniversalPrinter with T directly.
+ typedef T T1;
+ UniversalPrinter<T1>::Print(value, os);
+}
+
+typedef ::std::vector<::std::string> Strings;
+
+// Tersely prints the first N fields of a tuple to a string vector,
+// one element for each field.
+template <typename Tuple>
+void TersePrintPrefixToStrings(const Tuple&, std::integral_constant<size_t, 0>,
+ Strings*) {}
+template <typename Tuple, size_t I>
+void TersePrintPrefixToStrings(const Tuple& t,
+ std::integral_constant<size_t, I>,
+ Strings* strings) {
+ TersePrintPrefixToStrings(t, std::integral_constant<size_t, I - 1>(),
+ strings);
+ ::std::stringstream ss;
+ UniversalTersePrint(std::get<I - 1>(t), &ss);
+ strings->push_back(ss.str());
+}
+
+// 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 <typename Tuple>
+Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
+ Strings result;
+ TersePrintPrefixToStrings(
+ value, std::integral_constant<size_t, std::tuple_size<Tuple>::value>(),
+ &result);
+ return result;
+}
+
+} // namespace internal
+
+template <typename T>
+::std::string PrintToString(const T& value) {
+ ::std::stringstream ss;
+ internal::UniversalTersePrinter<T>::Print(value, &ss);
+ return ss.str();
+}
+
+} // namespace testing
+
+// Include any custom printer added by the local installation.
+// We must include this header at the end to make sure it can use the
+// declarations from this file.
+#include "gtest/internal/custom/gtest-printers.h"
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-spi.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-spi.h
new file mode 100644
index 0000000..bec8c48
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-spi.h
@@ -0,0 +1,248 @@
+// 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.
+
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include "gtest/gtest.h"
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+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.
+ ~ScopedFakeTestPartResultReporter() override;
+
+ // Appends the TestPartResult object to the TestPartResultArray
+ // received in the constructor.
+ //
+ // This method is from the TestPartResultReporterInterface
+ // interface.
+ void ReportTestPartResult(const TestPartResult& result) override;
+
+ private:
+ void Init();
+
+ const InterceptMode intercept_mode_;
+ TestPartResultReporterInterface* old_reporter_;
+ TestPartResultArray* const result_;
+
+ ScopedFakeTestPartResultReporter(const ScopedFakeTestPartResultReporter&) =
+ delete;
+ ScopedFakeTestPartResultReporter& operator=(
+ const ScopedFakeTestPartResultReporter&) = delete;
+};
+
+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 std::string& substr);
+ ~SingleFailureChecker();
+
+ private:
+ const TestPartResultArray* const results_;
+ const TestPartResult::Type type_;
+ const std::string substr_;
+
+ SingleFailureChecker(const SingleFailureChecker&) = delete;
+ SingleFailureChecker& operator=(const SingleFailureChecker&) = delete;
+};
+
+} // namespace internal
+
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures (e.g. a failure from an ASSERT_EQ, but
+// not a non-fatal failure, as from EXPECT_EQ). 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( \
+ &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr)); \
+ { \
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, \
+ &gtest_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( \
+ &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr)); \
+ { \
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \
+ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
+ &gtest_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 (e.g. a failure from an EXPECT_EQ,
+// but not from an ASSERT_EQ). 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( \
+ &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr)); \
+ { \
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, \
+ &gtest_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( \
+ &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr)); \
+ { \
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \
+ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
+ &gtest_failures); \
+ if (::testing::internal::AlwaysTrue()) { \
+ statement; \
+ } \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-test-part.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-test-part.h
new file mode 100644
index 0000000..09cc8c3
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-test-part.h
@@ -0,0 +1,190 @@
+// 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.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <vector>
+
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+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.
+ kSkip // Skipped.
+ };
+
+ // 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 == nullptr ? "" : 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_.empty() ? nullptr : 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 if and only if the test part was skipped.
+ bool skipped() const { return type_ == kSkip; }
+
+ // Returns true if and only if the test part passed.
+ bool passed() const { return type_ == kSuccess; }
+
+ // Returns true if and only if the test part non-fatally failed.
+ bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
+
+ // Returns true if and only if the test part fatally failed.
+ bool fatally_failed() const { return type_ == kFatalFailure; }
+
+ // Returns true if and only if the test part failed.
+ bool failed() const { return fatally_failed() || nonfatally_failed(); }
+
+ private:
+ Type type_;
+
+ // Gets the summary of the failure message by omitting the stack
+ // trace in it.
+ static std::string ExtractSummary(const char* message);
+
+ // The name of the source file where the test part took place, or
+ // "" if the source file is unknown.
+ std::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_;
+ std::string summary_; // The test failure summary.
+ std::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<TestPartResult> array_;
+
+ TestPartResultArray(const TestPartResultArray&) = delete;
+ TestPartResultArray& operator=(const TestPartResultArray&) = delete;
+};
+
+// This interface knows how to report a test part result.
+class GTEST_API_ 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();
+ ~HasNewFatalFailureHelper() override;
+ void ReportTestPartResult(const TestPartResult& result) override;
+ bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+
+ private:
+ bool has_new_fatal_failure_;
+ TestPartResultReporterInterface* original_reporter_;
+
+ HasNewFatalFailureHelper(const HasNewFatalFailureHelper&) = delete;
+ HasNewFatalFailureHelper& operator=(const HasNewFatalFailureHelper&) = delete;
+};
+
+} // namespace internal
+
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest-typed-test.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest-typed-test.h
new file mode 100644
index 0000000..bd35a32
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest-typed-test.h
@@ -0,0 +1,331 @@
+// 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.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GOOGLETEST_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 <typename T>
+class FooTest : public testing::Test {
+ public:
+ ...
+ typedef std::list<T> List;
+ static T shared_;
+ T value_;
+};
+
+// Next, associate a list of types with the test suite, which will be
+// repeated for each type in the list. The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_SUITE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// TYPED_TEST_SUITE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test suite as you want.
+TYPED_TEST(FooTest, DoesBlah) {
+ // Inside a test, refer to the special name TypeParam to get the type
+ // parameter. Since we are inside a derived class template, C++ requires
+ // us 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) { ... }
+
+// TYPED_TEST_SUITE takes an optional third argument which allows to specify a
+// class that generates custom test name suffixes based on the type. This should
+// be a class which has a static template function GetName(int index) returning
+// a string for each type. The provided integer index equals the index of the
+// type in the provided type list. In many cases the index can be ignored.
+//
+// For example:
+// class MyTypeNames {
+// public:
+// template <typename T>
+// static std::string GetName(int) {
+// if (std::is_same<T, char>()) return "char";
+// if (std::is_same<T, int>()) return "int";
+// if (std::is_same<T, unsigned int>()) return "unsignedInt";
+// }
+// };
+// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames);
+
+#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 <typename T>
+class FooTest : public testing::Test {
+ ...
+};
+
+// Next, declare that you will define a type-parameterized test suite
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_SUITE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test suite 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 suite name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_SUITE_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 suite name. Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int);
+//
+// Similar to the optional argument of TYPED_TEST_SUITE above,
+// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to
+// generate custom names.
+// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames);
+
+#endif // 0
+
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
+#include "gtest/internal/gtest-type-util.h"
+
+// Implements typed tests.
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test suite.
+#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_
+
+// Expands to the name of the typedef for the NameGenerator, responsible for
+// creating the suffixes of the name.
+#define GTEST_NAME_GENERATOR_(TestSuiteName) \
+ gtest_type_params_##TestSuiteName##_NameGenerator
+
+#define TYPED_TEST_SUITE(CaseName, Types, ...) \
+ typedef ::testing::internal::GenerateTypeList<Types>::type \
+ GTEST_TYPE_PARAMS_(CaseName); \
+ typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
+ GTEST_NAME_GENERATOR_(CaseName)
+
+#define TYPED_TEST(CaseName, TestName) \
+ static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \
+ "test-name must not be empty"); \
+ template <typename gtest_TypeParam_> \
+ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+ : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ void TestBody() override; \
+ }; \
+ static 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("", \
+ ::testing::internal::CodeLocation( \
+ __FILE__, __LINE__), \
+ GTEST_STRINGIFY_(CaseName), \
+ GTEST_STRINGIFY_(TestName), 0, \
+ ::testing::internal::GenerateNames< \
+ GTEST_NAME_GENERATOR_(CaseName), \
+ GTEST_TYPE_PARAMS_(CaseName)>()); \
+ template <typename gtest_TypeParam_> \
+ void GTEST_TEST_CLASS_NAME_(CaseName, \
+ TestName)<gtest_TypeParam_>::TestBody()
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define TYPED_TEST_CASE \
+ static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \
+ TYPED_TEST_SUITE
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+// Implements type-parameterized tests.
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test suite are defined in. The exact
+// name of the namespace is subject to change without notice.
+#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_
+
+// 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 suite.
+#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \
+ gtest_typed_test_suite_p_state_##TestSuiteName##_
+
+// 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 suite.
+#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \
+ gtest_registered_test_names_##TestSuiteName##_
+
+// 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_SUITE_P(SuiteName) \
+ static ::testing::internal::TypedTestSuitePState \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName)
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define TYPED_TEST_CASE_P \
+ static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \
+ TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+#define TYPED_TEST_P(SuiteName, TestName) \
+ namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
+ template <typename gtest_TypeParam_> \
+ class TestName : public SuiteName<gtest_TypeParam_> { \
+ private: \
+ typedef SuiteName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ void TestBody() override; \
+ }; \
+ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \
+ __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \
+ GTEST_STRINGIFY_(TestName)); \
+ } \
+ template <typename gtest_TypeParam_> \
+ void GTEST_SUITE_NAMESPACE_( \
+ SuiteName)::TestName<gtest_TypeParam_>::TestBody()
+
+// Note: this won't work correctly if the trailing arguments are macros.
+#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \
+ namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
+ typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \
+ } \
+ static const char* const GTEST_REGISTERED_TEST_NAMES_( \
+ SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \
+ GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__)
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define REGISTER_TYPED_TEST_CASE_P \
+ static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \
+ ""); \
+ REGISTER_TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \
+ static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \
+ "test-suit-prefix must not be empty"); \
+ static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::internal::TypeParameterizedTestSuite< \
+ SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \
+ ::testing::internal::GenerateTypeList<Types>::type>:: \
+ Register(GTEST_STRINGIFY_(Prefix), \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__), \
+ &GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \
+ GTEST_STRINGIFY_(SuiteName), \
+ GTEST_REGISTERED_TEST_NAMES_(SuiteName), \
+ ::testing::internal::GenerateNames< \
+ ::testing::internal::NameGeneratorSelector< \
+ __VA_ARGS__>::type, \
+ ::testing::internal::GenerateTypeList<Types>::type>())
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define INSTANTIATE_TYPED_TEST_CASE_P \
+ static_assert( \
+ ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \
+ INSTANTIATE_TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest.h
new file mode 100644
index 0000000..d19a587
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest.h
@@ -0,0 +1,2297 @@
+// 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.
+
+// The Google C++ Testing and Mocking 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 GOOGLETEST_INCLUDE_GTEST_GTEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_H_
+
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <ostream>
+#include <type_traits>
+#include <vector>
+
+#include "gtest/gtest-assertion-result.h"
+#include "gtest/gtest-death-test.h"
+#include "gtest/gtest-matchers.h"
+#include "gtest/gtest-message.h"
+#include "gtest/gtest-param-test.h"
+#include "gtest/gtest-printers.h"
+#include "gtest/gtest-test-part.h"
+#include "gtest/gtest-typed-test.h"
+#include "gtest/gtest_pred_impl.h"
+#include "gtest/gtest_prod.h"
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// 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 controls whether the test runner should continue execution past
+// first failure.
+GTEST_DECLARE_bool_(fail_fast);
+
+// 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 controls whether Google Test installs a signal handler that dumps
+// debugging information when fatal signals are raised.
+GTEST_DECLARE_bool_(install_failure_signal_handler);
+
+// 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 only test failures.
+GTEST_DECLARE_bool_(brief);
+
+// This flags control whether Google Test prints the elapsed time for each
+// test.
+GTEST_DECLARE_bool_(print_time);
+
+// This flags control whether Google Test prints UTF8 characters as text.
+GTEST_DECLARE_bool_(print_utf8);
+
+// 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 Environments are recreated for each
+// repeat of the tests. The default value is true. If set to false the global
+// test Environment objects are only set up once, for the first iteration, and
+// only torn down once, for the last.
+GTEST_DECLARE_bool_(recreate_environments_when_repeating);
+
+// 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. For use with an external test framework.
+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);
+
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+GTEST_DECLARE_string_(flagfile);
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
+namespace testing {
+
+// Silence C4100 (unreferenced formal parameter) and 4805
+// unsafe mix of type 'const int' and type 'const bool'
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4805)
+#pragma warning(disable : 4100)
+#endif
+
+// 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 StreamingListenerTest;
+class TestResultAccessor;
+class TestEventListenersAccessor;
+class TestEventRepeater;
+class UnitTestRecordPropertyTestHelper;
+class WindowsDeathTest;
+class FuchsiaDeathTest;
+class UnitTestImpl* GetUnitTestImpl();
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const std::string& message);
+std::set<std::string>* GetIgnoredParameterizedTestSuites();
+
+} // 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 TestSuite;
+
+// Old API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+using TestCase = TestSuite;
+#endif
+class TestInfo;
+class UnitTest;
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestSuites, and
+// each TestSuite 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 in a TEST_F. For example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// void SetUp() override { ... }
+// void TearDown() override { ... }
+// ...
+// };
+//
+// TEST_F(FooTest, Bar) { ... }
+// TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class GTEST_API_ Test {
+ public:
+ friend class TestInfo;
+
+ // 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 suite.
+ //
+ // Google Test will call Foo::SetUpTestSuite() before running the first
+ // test in test suite Foo. Hence a sub-class can define its own
+ // SetUpTestSuite() method to shadow the one defined in the super
+ // class.
+ static void SetUpTestSuite() {}
+
+ // Tears down the stuff shared by all tests in this test suite.
+ //
+ // Google Test will call Foo::TearDownTestSuite() after running the last
+ // test in test suite Foo. Hence a sub-class can define its own
+ // TearDownTestSuite() method to shadow the one defined in the super
+ // class.
+ static void TearDownTestSuite() {}
+
+ // Legacy API is deprecated but still available. Use SetUpTestSuite and
+ // TearDownTestSuite instead.
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ static void TearDownTestCase() {}
+ static void SetUpTestCase() {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Returns true if and only if the current test has a fatal failure.
+ static bool HasFatalFailure();
+
+ // Returns true if and only if the current test has a non-fatal failure.
+ static bool HasNonfatalFailure();
+
+ // Returns true if and only if the current test was skipped.
+ static bool IsSkipped();
+
+ // Returns true if and only if the current test has a (either fatal or
+ // non-fatal) failure.
+ static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
+
+ // Logs a property for the current test, test suite, or for the entire
+ // invocation of the test program when used outside of the context of a
+ // test suite. 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. Calls to RecordProperty made during
+ // lifespan of the test (from the moment its constructor starts to the
+ // moment its destructor finishes) will be output in XML as attributes of
+ // the <testcase> element. Properties recorded from fixture's
+ // SetUpTestSuite or TearDownTestSuite are logged as attributes of the
+ // corresponding <testsuite> element. Calls to RecordProperty made in the
+ // global context (before or after invocation of RUN_ALL_TESTS and from
+ // SetUp/TearDown method of Environment objects registered with Google
+ // Test) will be output as attributes of the <testsuites> element.
+ static void RecordProperty(const std::string& key, const std::string& value);
+ static void RecordProperty(const std::string& 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 if and only if the current test has the same fixture class
+ // as the first test in the current test suite.
+ 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; }
+
+ const std::unique_ptr<GTEST_FLAG_SAVER_> gtest_flag_saver_;
+
+ // Often a user misspells 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 void Setup() is declared in the user's
+ // test fixture.
+ //
+ // - This method is private, so it will be another compiler error
+ // if the method is called from the user's 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 nullptr; }
+
+ // We disallow copying Tests.
+ Test(const Test&) = delete;
+ Test& operator=(const Test&) = delete;
+};
+
+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 std::string& a_key, const std::string& 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 std::string& new_value) { value_ = new_value; }
+
+ private:
+ // The key supplied by the user.
+ std::string key_;
+ // The value supplied by the user.
+ std::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 if and only if the test passed (i.e. no test part failed).
+ bool Passed() const { return !Skipped() && !Failed(); }
+
+ // Returns true if and only if the test was skipped.
+ bool Skipped() const;
+
+ // Returns true if and only if the test failed.
+ bool Failed() const;
+
+ // Returns true if and only if the test fatally failed.
+ bool HasFatalFailure() const;
+
+ // Returns true if and only if the test has a non-fatal failure.
+ bool HasNonfatalFailure() const;
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Gets the time of the test case start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+ // 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& 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 TestSuite;
+ friend class UnitTest;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::ExecDeathTest;
+ friend class internal::TestResultAccessor;
+ friend class internal::UnitTestImpl;
+ friend class internal::WindowsDeathTest;
+ friend class internal::FuchsiaDeathTest;
+
+ // Gets the vector of TestPartResults.
+ const std::vector<TestPartResult>& test_part_results() const {
+ return test_part_results_;
+ }
+
+ // Gets the vector of TestProperties.
+ const std::vector<TestProperty>& test_properties() const {
+ return test_properties_;
+ }
+
+ // Sets the start time.
+ void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; }
+
+ // 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. xml_element specifies the element for which the property is being
+ // recorded and is used for validation.
+ void RecordProperty(const std::string& xml_element,
+ const TestProperty& test_property);
+
+ // Adds a failure if the key is a reserved attribute of Google Test
+ // testsuite tags. Returns true if the property is valid.
+ // FIXME: Validate attribute names are legal and human readable.
+ static bool ValidateTestProperty(const std::string& xml_element,
+ 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_properties_mutex_;
+
+ // The vector of TestPartResults
+ std::vector<TestPartResult> test_part_results_;
+ // The vector of TestProperties
+ std::vector<TestProperty> test_properties_;
+ // Running count of death tests.
+ int death_test_count_;
+ // The start time, in milliseconds since UNIX Epoch.
+ TimeInMillis start_timestamp_;
+ // The elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestResult.
+ TestResult(const TestResult&) = delete;
+ TestResult& operator=(const TestResult&) = delete;
+}; // class TestResult
+
+// A TestInfo object stores the following information about a test:
+//
+// Test suite 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 suite name.
+ const char* test_suite_name() const { return test_suite_name_.c_str(); }
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const char* test_case_name() const { return test_suite_name(); }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // 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() != nullptr) return type_param_->c_str();
+ return nullptr;
+ }
+
+ // 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() != nullptr) return value_param_->c_str();
+ return nullptr;
+ }
+
+ // Returns the file name where this test is defined.
+ const char* file() const { return location_.file.c_str(); }
+
+ // Returns the line where this test is defined.
+ int line() const { return location_.line; }
+
+ // Return true if this test should not be run because it's in another shard.
+ bool is_in_another_shard() const { return is_in_another_shard_; }
+
+ // 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 suite 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 true if and only if this test will appear in the XML report.
+ bool is_reportable() const {
+ // The XML report includes tests matching the filter, excluding those
+ // run in other shards.
+ return matches_filter_ && !is_in_another_shard_;
+ }
+
+ // 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 TestSuite;
+ friend class internal::UnitTestImpl;
+ friend class internal::StreamingListenerTest;
+ friend TestInfo* internal::MakeAndRegisterTestInfo(
+ const char* test_suite_name, const char* name, const char* type_param,
+ const char* value_param, internal::CodeLocation code_location,
+ internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc,
+ internal::TestFactoryBase* factory);
+
+ // Constructs a TestInfo object. The newly constructed instance assumes
+ // ownership of the factory object.
+ TestInfo(const std::string& test_suite_name, const std::string& name,
+ const char* a_type_param, // NULL if not a type-parameterized test
+ const char* a_value_param, // NULL if not a value-parameterized test
+ internal::CodeLocation a_code_location,
+ 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();
+
+ // Skip and records the test result for this object.
+ void Skip();
+
+ static void ClearTestResult(TestInfo* test_info) {
+ test_info->result_.Clear();
+ }
+
+ // These fields are immutable properties of the test.
+ const std::string test_suite_name_; // test suite 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 std::unique_ptr<const ::std::string> type_param_;
+ // Text representation of the value parameter, or NULL if this is not a
+ // value-parameterized test.
+ const std::unique_ptr<const ::std::string> value_param_;
+ internal::CodeLocation location_;
+ const internal::TypeId fixture_class_id_; // ID of the test fixture class
+ bool should_run_; // True if and only if this test should run
+ bool is_disabled_; // True if and only if this test is disabled
+ bool matches_filter_; // True if this test matches the
+ // user-specified filter.
+ bool is_in_another_shard_; // Will be run in another shard.
+ 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_;
+
+ TestInfo(const TestInfo&) = delete;
+ TestInfo& operator=(const TestInfo&) = delete;
+};
+
+// A test suite, which consists of a vector of TestInfos.
+//
+// TestSuite is not copyable.
+class GTEST_API_ TestSuite {
+ public:
+ // Creates a TestSuite with the given name.
+ //
+ // TestSuite does NOT have a default constructor. Always use this
+ // constructor to create a TestSuite object.
+ //
+ // Arguments:
+ //
+ // name: name of the test suite
+ // 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 suite
+ // tear_down_tc: pointer to the function that tears down the test suite
+ TestSuite(const char* name, const char* a_type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc);
+
+ // Destructor of TestSuite.
+ virtual ~TestSuite();
+
+ // Gets the name of the TestSuite.
+ 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 suite.
+ const char* type_param() const {
+ if (type_param_.get() != nullptr) return type_param_->c_str();
+ return nullptr;
+ }
+
+ // Returns true if any test in this test suite should run.
+ bool should_run() const { return should_run_; }
+
+ // Gets the number of successful tests in this test suite.
+ int successful_test_count() const;
+
+ // Gets the number of skipped tests in this test suite.
+ int skipped_test_count() const;
+
+ // Gets the number of failed tests in this test suite.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests in this test suite.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_test_count() const;
+
+ // Get the number of tests in this test suite that should run.
+ int test_to_run_count() const;
+
+ // Gets the number of all tests in this test suite.
+ int total_test_count() const;
+
+ // Returns true if and only if the test suite passed.
+ bool Passed() const { return !Failed(); }
+
+ // Returns true if and only if the test suite failed.
+ bool Failed() const {
+ return failed_test_count() > 0 || ad_hoc_test_result().Failed();
+ }
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Gets the time of the test suite start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+ // 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;
+
+ // Returns the TestResult that holds test properties recorded during
+ // execution of SetUpTestSuite and TearDownTestSuite.
+ const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }
+
+ private:
+ friend class Test;
+ friend class internal::UnitTestImpl;
+
+ // Gets the (mutable) vector of TestInfos in this TestSuite.
+ std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
+
+ // Gets the (immutable) vector of TestInfos in this TestSuite.
+ const std::vector<TestInfo*>& 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 suite. Will delete the TestInfo upon
+ // destruction of the TestSuite object.
+ void AddTestInfo(TestInfo* test_info);
+
+ // Clears the results of all tests in this test suite.
+ void ClearResult();
+
+ // Clears the results of all tests in the given test suite.
+ static void ClearTestSuiteResult(TestSuite* test_suite) {
+ test_suite->ClearResult();
+ }
+
+ // Runs every test in this TestSuite.
+ void Run();
+
+ // Skips the execution of tests under this TestSuite
+ void Skip();
+
+ // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed
+ // for catching exceptions thrown from SetUpTestSuite().
+ void RunSetUpTestSuite() {
+ if (set_up_tc_ != nullptr) {
+ (*set_up_tc_)();
+ }
+ }
+
+ // Runs TearDownTestSuite() for this TestSuite. This wrapper is
+ // needed for catching exceptions thrown from TearDownTestSuite().
+ void RunTearDownTestSuite() {
+ if (tear_down_tc_ != nullptr) {
+ (*tear_down_tc_)();
+ }
+ }
+
+ // Returns true if and only if test passed.
+ static bool TestPassed(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Passed();
+ }
+
+ // Returns true if and only if test skipped.
+ static bool TestSkipped(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Skipped();
+ }
+
+ // Returns true if and only if test failed.
+ static bool TestFailed(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Failed();
+ }
+
+ // Returns true if and only if the test is disabled and will be reported in
+ // the XML report.
+ static bool TestReportableDisabled(const TestInfo* test_info) {
+ return test_info->is_reportable() && test_info->is_disabled_;
+ }
+
+ // Returns true if and only if test is disabled.
+ static bool TestDisabled(const TestInfo* test_info) {
+ return test_info->is_disabled_;
+ }
+
+ // Returns true if and only if this test will appear in the XML report.
+ static bool TestReportable(const TestInfo* test_info) {
+ return test_info->is_reportable();
+ }
+
+ // 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 suite.
+ void ShuffleTests(internal::Random* random);
+
+ // Restores the test order to before the first shuffle.
+ void UnshuffleTests();
+
+ // Name of the test suite.
+ std::string name_;
+ // Name of the parameter type, or NULL if this is not a typed or a
+ // type-parameterized test.
+ const std::unique_ptr<const ::std::string> type_param_;
+ // The vector of TestInfos in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestInfo*> 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<int> test_indices_;
+ // Pointer to the function that sets up the test suite.
+ internal::SetUpTestSuiteFunc set_up_tc_;
+ // Pointer to the function that tears down the test suite.
+ internal::TearDownTestSuiteFunc tear_down_tc_;
+ // True if and only if any test in this test suite should run.
+ bool should_run_;
+ // The start time, in milliseconds since UNIX Epoch.
+ TimeInMillis start_timestamp_;
+ // Elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+ // Holds test properties recorded during execution of SetUpTestSuite and
+ // TearDownTestSuite.
+ TestResult ad_hoc_test_result_;
+
+ // We disallow copying TestSuites.
+ TestSuite(const TestSuite&) = delete;
+ TestSuite& operator=(const TestSuite&) = delete;
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment. You should subclass this to define your 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 nullptr; }
+};
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Exception which can be thrown from TestEventListener::OnTestPartResult.
+class GTEST_API_ AssertionException
+ : public internal::GoogleTestFailureException {
+ public:
+ explicit AssertionException(const TestPartResult& result)
+ : GoogleTestFailureException(result) {}
+};
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// 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 suite starts.
+ virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {}
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Fired before the test starts.
+ virtual void OnTestStart(const TestInfo& test_info) = 0;
+
+ // Fired when a test is disabled
+ virtual void OnTestDisabled(const TestInfo& /*test_info*/) {}
+
+ // Fired after a failed assertion or a SUCCEED() invocation.
+ // If you want to throw an exception from this function to skip to the next
+ // TEST, it must be AssertionException defined above, or inherited from it.
+ 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 suite ends.
+ virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // 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:
+ void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) override {}
+ void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {}
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestCase& /*test_case*/) override {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnTestStart(const TestInfo& /*test_info*/) override {}
+ void OnTestDisabled(const TestInfo& /*test_info*/) override {}
+ void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {}
+ void OnTestEnd(const TestInfo& /*test_info*/) override {}
+ void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& /*test_case*/) override {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int /*iteration*/) override {}
+ void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
+};
+
+// 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 TestSuite;
+ 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.
+ TestEventListeners(const TestEventListeners&) = delete;
+ TestEventListeners& operator=(const TestEventListeners&) = delete;
+};
+
+// A UnitTest consists of a vector of TestSuites.
+//
+// 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 TestSuite object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_);
+
+// Legacy API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_);
+#endif
+
+ // Returns the TestInfo object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestInfo* current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Returns the random seed used at the start of the current test run.
+ int random_seed() const;
+
+ // Returns the ParameterizedTestSuiteRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::ParameterizedTestSuiteRegistry& parameterized_test_registry()
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Gets the number of successful test suites.
+ int successful_test_suite_count() const;
+
+ // Gets the number of failed test suites.
+ int failed_test_suite_count() const;
+
+ // Gets the number of all test suites.
+ int total_test_suite_count() const;
+
+ // Gets the number of all test suites that contain at least one test
+ // that should run.
+ int test_suite_to_run_count() const;
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ int successful_test_case_count() const;
+ int failed_test_case_count() const;
+ int total_test_case_count() const;
+ int test_case_to_run_count() const;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of skipped tests.
+ int skipped_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_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 time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const;
+
+ // Returns true if and only if the unit test passed (i.e. all test suites
+ // passed).
+ bool Passed() const;
+
+ // Returns true if and only if the unit test failed (i.e. some test suite
+ // failed or something outside of all tests failed).
+ bool Failed() const;
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ const TestSuite* GetTestSuite(int i) const;
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const TestCase* GetTestCase(int i) const;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Returns the TestResult containing information on test failures and
+ // properties logged outside of individual test suites.
+ const TestResult& ad_hoc_test_result() 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 std::string& message,
+ const std::string& os_stack_trace)
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Adds a TestProperty to the current TestResult object when invoked from
+ // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked
+ // from SetUpTestSuite or TearDownTestSuite, or to the global property set
+ // when invoked elsewhere. If the result already contains a property with
+ // the same key, the value will be updated.
+ void RecordProperty(const std::string& key, const std::string& value);
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ TestSuite* GetMutableTestSuite(int i);
+
+ // Accessors for the implementation object.
+ internal::UnitTestImpl* impl() { return impl_; }
+ const internal::UnitTestImpl* impl() const { return impl_; }
+
+ // These classes and functions are friends as they need to access private
+ // members of UnitTest.
+ friend class ScopedTrace;
+ friend class Test;
+ friend class internal::AssertHelper;
+ friend class internal::StreamingListenerTest;
+ friend class internal::UnitTestRecordPropertyTestHelper;
+ friend Environment* AddGlobalTestEnvironment(Environment* env);
+ friend std::set<std::string>* internal::GetIgnoredParameterizedTestSuites();
+ friend internal::UnitTestImpl* internal::GetUnitTestImpl();
+ friend void internal::ReportFailureInUnknownLocation(
+ TestPartResult::Type result_type, const std::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)
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Pops a trace from the per-thread Google Test trace stack.
+ void PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // 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.
+ UnitTest(const UnitTest&) = delete;
+ UnitTest& operator=(const UnitTest&) = delete;
+};
+
+// 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);
+
+// This overloaded version can be used on Arduino/embedded platforms where
+// there is no argc/argv.
+GTEST_API_ void InitGoogleTest();
+
+namespace internal {
+
+// Separate the error generating code from the code path to reduce the stack
+// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers
+// when calling EXPECT_* in a tight loop.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQFailure(const char* lhs_expression,
+ const char* rhs_expression, const T1& lhs,
+ const T2& rhs) {
+ return EqFailure(lhs_expression, rhs_expression,
+ FormatForComparisonFailureMessage(lhs, rhs),
+ FormatForComparisonFailureMessage(rhs, lhs), false);
+}
+
+// This block of code defines operator==/!=
+// to block lexical scope lookup.
+// It prevents using invalid operator==/!= defined at namespace scope.
+struct faketype {};
+inline bool operator==(faketype, faketype) { return true; }
+inline bool operator!=(faketype, faketype) { return false; }
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* lhs_expression,
+ const char* rhs_expression, const T1& lhs,
+ const T2& rhs) {
+ if (lhs == rhs) {
+ return AssertionSuccess();
+ }
+
+ return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs);
+}
+
+class EqHelper {
+ public:
+ // This templatized version is for the general case.
+ template <
+ typename T1, typename T2,
+ // Disable this overload for cases where one argument is a pointer
+ // and the other is the null pointer constant.
+ typename std::enable_if<!std::is_integral<T1>::value ||
+ !std::is_pointer<T2>::value>::type* = nullptr>
+ static AssertionResult Compare(const char* lhs_expression,
+ const char* rhs_expression, const T1& lhs,
+ const T2& rhs) {
+ return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
+ }
+
+ // 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* lhs_expression,
+ const char* rhs_expression, BiggestInt lhs,
+ BiggestInt rhs) {
+ return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
+ }
+
+ template <typename T>
+ static AssertionResult Compare(
+ const char* lhs_expression, const char* rhs_expression,
+ // Handle cases where '0' is used as a null pointer literal.
+ std::nullptr_t /* lhs */, T* rhs) {
+ // We already know that 'lhs' is a null pointer.
+ return CmpHelperEQ(lhs_expression, rhs_expression, static_cast<T*>(nullptr),
+ rhs);
+ }
+};
+
+// Separate the error generating code from the code path to reduce the stack
+// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers
+// when calling EXPECT_OP in a tight loop.
+template <typename T1, typename T2>
+AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2,
+ const T1& val1, const T2& val2,
+ const char* op) {
+ return AssertionFailure()
+ << "Expected: (" << expr1 << ") " << op << " (" << expr2
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);
+}
+
+// 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.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+#define GTEST_IMPL_CMP_HELPER_(op_name, op) \
+ template <typename T1, typename T2> \
+ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ const T1& val1, const T2& val2) { \
+ if (val1 op val2) { \
+ return AssertionSuccess(); \
+ } else { \
+ return CmpHelperOpFailure(expr1, expr2, val1, val2, #op); \
+ } \
+ }
+
+// 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* s1_expression,
+ const char* s2_expression,
+ const char* s1, const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1, const char* s2);
+
+// 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* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1, const wchar_t* s2);
+
+// 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 <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ RawType lhs_value, RawType rhs_value) {
+ const FloatingPoint<RawType> lhs(lhs_value), rhs(rhs_value);
+
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ ::std::stringstream lhs_ss;
+ lhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << lhs_value;
+
+ ::std::stringstream rhs_ss;
+ rhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << rhs_value;
+
+ return EqFailure(lhs_expression, rhs_expression,
+ StringStreamToString(&lhs_ss), StringStreamToString(&rhs_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;
+ std::string const message;
+
+ private:
+ AssertHelperData(const AssertHelperData&) = delete;
+ AssertHelperData& operator=(const AssertHelperData&) = delete;
+ };
+
+ AssertHelperData* const data_;
+
+ AssertHelper(const AssertHelper&) = delete;
+ AssertHelper& operator=(const AssertHelper&) = delete;
+};
+
+} // namespace internal
+
+// 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<int> {
+// protected:
+// FooTest() {
+// // Can use GetParam() here.
+// }
+// ~FooTest() override {
+// // Can use GetParam() here.
+// }
+// void SetUp() override {
+// // Can use GetParam() here.
+// }
+// void TearDown override {
+// // Can use GetParam() here.
+// }
+// };
+// TEST_P(FooTest, DoesBar) {
+// // Can use GetParam() method here.
+// Foo foo;
+// ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class WithParamInterface {
+ public:
+ typedef T ParamType;
+ virtual ~WithParamInterface() {}
+
+ // The current parameter value. Is also available in the test fixture's
+ // constructor.
+ static const ParamType& GetParam() {
+ GTEST_CHECK_(parameter_ != nullptr)
+ << "GetParam() can only be called inside a value-parameterized test "
+ << "-- did you intend to write TEST_P instead of TEST_F?";
+ 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<T> and Test.
+ template <class TestClass>
+ friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* WithParamInterface<T>::parameter_ = nullptr;
+
+// Most value-parameterized classes can ignore the existence of
+// WithParamInterface, and can just inherit from ::testing::TestWithParam.
+
+template <typename T>
+class TestWithParam : public Test, public WithParamInterface<T> {};
+
+// Macros for indicating success/failure in test code.
+
+// Skips test in runtime.
+// Skipping test aborts current function.
+// Skipped tests are neither successful nor failed.
+#define GTEST_SKIP() GTEST_SKIP_("")
+
+// 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.
+
+// 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")
+
+// Like GTEST_FAIL(), but at the given source file location.
+#define GTEST_FAIL_AT(file, line) \
+ GTEST_MESSAGE_AT_(file, line, "Failed", \
+ ::testing::TestPartResult::kFatalFailure)
+
+// 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 GTEST_EXPECT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_NONFATAL_FAILURE_)
+#define GTEST_EXPECT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_NONFATAL_FAILURE_)
+#define GTEST_ASSERT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, GTEST_FATAL_FAILURE_)
+#define GTEST_ASSERT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_FATAL_FAILURE_)
+
+// Define these macros to 1 to omit the definition of the corresponding
+// EXPECT or ASSERT, which clashes with some users' own code.
+
+#if !GTEST_DONT_DEFINE_EXPECT_TRUE
+#define EXPECT_TRUE(condition) GTEST_EXPECT_TRUE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_EXPECT_FALSE
+#define EXPECT_FALSE(condition) GTEST_EXPECT_FALSE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_TRUE
+#define ASSERT_TRUE(condition) GTEST_ASSERT_TRUE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_FALSE
+#define ASSERT_FALSE(condition) GTEST_ASSERT_FALSE(condition)
+#endif
+
+// Macros for testing equalities and inequalities.
+//
+// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2
+// * {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(v1, v2) is preferred to
+// {ASSERT|EXPECT}_TRUE(v1 == v2), 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(Foo(), 5);
+// EXPECT_EQ(a_pointer, NULL);
+// ASSERT_LT(i, array_size);
+// ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
+#define EXPECT_NE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#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(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
+#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(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
+#define EXPECT_STRNE(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2)
+#define EXPECT_STRCASENE(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
+#define ASSERT_STRNE(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2)
+#define ASSERT_STRCASENE(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+// * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2):
+// Tests that two float values are almost equal.
+// * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2):
+// 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(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ val1, val2)
+
+#define EXPECT_DOUBLE_EQ(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ val1, val2)
+
+#define ASSERT_FLOAT_EQ(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ val1, val2)
+
+#define ASSERT_DOUBLE_EQ(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ val1, val2)
+
+#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 given source file path and line number,
+// and the given message) to be included in every test failure message generated
+// by code in the scope of the lifetime of an instance of this class. The effect
+// is undone with the destruction of the instance.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// Example:
+// testing::ScopedTrace trace("file.cc", 123, "message");
+//
+class GTEST_API_ ScopedTrace {
+ public:
+ // The c'tor pushes the given source file location and message onto
+ // a trace stack maintained by Google Test.
+
+ // Template version. Uses Message() to convert the values into strings.
+ // Slow, but flexible.
+ template <typename T>
+ ScopedTrace(const char* file, int line, const T& message) {
+ PushTrace(file, line, (Message() << message).GetString());
+ }
+
+ // Optimize for some known types.
+ ScopedTrace(const char* file, int line, const char* message) {
+ PushTrace(file, line, message ? message : "(null)");
+ }
+
+ ScopedTrace(const char* file, int line, const std::string& message) {
+ PushTrace(file, line, 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:
+ void PushTrace(const char* file, int line, std::string message);
+
+ ScopedTrace(const ScopedTrace&) = delete;
+ ScopedTrace& operator=(const ScopedTrace&) = delete;
+} 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.
+
+// 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.
+//
+// Assuming that each thread maintains its own stack of traces.
+// Therefore, a SCOPED_TRACE() would (correctly) only affect the
+// assertions in its own thread.
+#define SCOPED_TRACE(message) \
+ ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)( \
+ __FILE__, __LINE__, (message))
+
+// Compile-time assertion for type equality.
+// StaticAssertTypeEq<type1, type2>() compiles if and only if 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<T1, T2> by
+// defining objects of that type.
+//
+// CAVEAT:
+//
+// When used inside a method of a class template,
+// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
+// instantiated. For example, given:
+//
+// template <typename T> class Foo {
+// public:
+// void Bar() { testing::StaticAssertTypeEq<int, T>(); }
+// };
+//
+// the code:
+//
+// void Test1() { Foo<bool> foo; }
+//
+// will NOT generate a compiler error, as Foo<bool>::Bar() is never
+// actually instantiated. Instead, you need:
+//
+// void Test2() { Foo<bool> foo; foo.Bar(); }
+//
+// to cause a compiler error.
+template <typename T1, typename T2>
+constexpr bool StaticAssertTypeEq() noexcept {
+ static_assert(std::is_same<T1, T2>::value, "T1 and T2 are not the same type");
+ return true;
+}
+
+// Defines a test.
+//
+// The first parameter is the name of the test suite, and the second
+// parameter is the name of the test within the test suite.
+//
+// The convention is to end the test suite name with "Test". For
+// example, a test suite for the Foo class can be named FooTest.
+//
+// Test code should appear between braces after an invocation of
+// 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_suite_name, test_name) \
+ GTEST_TEST_(test_suite_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_suite_name, test_name) GTEST_TEST(test_suite_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 suite name. The second parameter is the
+// name of the test within the test suite.
+//
+// A test fixture class must be declared earlier. The user should put
+// the test code between braces after using this macro. Example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// void SetUp() override { b_.AddElement(3); }
+//
+// Foo a_;
+// Foo b_;
+// };
+//
+// TEST_F(FooTest, InitializesCorrectly) {
+// EXPECT_TRUE(a_.StatusIsOK());
+// }
+//
+// TEST_F(FooTest, ReturnsElementCountCorrectly) {
+// EXPECT_EQ(a_.size(), 0);
+// EXPECT_EQ(b_.size(), 1);
+// }
+#define GTEST_TEST_F(test_fixture, test_name) \
+ GTEST_TEST_(test_fixture, test_name, test_fixture, \
+ ::testing::internal::GetTypeId<test_fixture>())
+#if !GTEST_DONT_DEFINE_TEST_F
+#define TEST_F(test_fixture, test_name) GTEST_TEST_F(test_fixture, test_name)
+#endif
+
+// Returns a path to temporary directory.
+// Tries to determine an appropriate directory for the platform.
+GTEST_API_ std::string TempDir();
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// Dynamically registers a test with the framework.
+//
+// This is an advanced API only to be used when the `TEST` macros are
+// insufficient. The macros should be preferred when possible, as they avoid
+// most of the complexity of calling this function.
+//
+// The `factory` argument is a factory callable (move-constructible) object or
+// function pointer that creates a new instance of the Test object. It
+// handles ownership to the caller. The signature of the callable is
+// `Fixture*()`, where `Fixture` is the test fixture class for the test. All
+// tests registered with the same `test_suite_name` must return the same
+// fixture type. This is checked at runtime.
+//
+// The framework will infer the fixture class from the factory and will call
+// the `SetUpTestSuite` and `TearDownTestSuite` for it.
+//
+// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is
+// undefined.
+//
+// Use case example:
+//
+// class MyFixture : public ::testing::Test {
+// public:
+// // All of these optional, just like in regular macro usage.
+// static void SetUpTestSuite() { ... }
+// static void TearDownTestSuite() { ... }
+// void SetUp() override { ... }
+// void TearDown() override { ... }
+// };
+//
+// class MyTest : public MyFixture {
+// public:
+// explicit MyTest(int data) : data_(data) {}
+// void TestBody() override { ... }
+//
+// private:
+// int data_;
+// };
+//
+// void RegisterMyTests(const std::vector<int>& values) {
+// for (int v : values) {
+// ::testing::RegisterTest(
+// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr,
+// std::to_string(v).c_str(),
+// __FILE__, __LINE__,
+// // Important to use the fixture type as the return type here.
+// [=]() -> MyFixture* { return new MyTest(v); });
+// }
+// }
+// ...
+// int main(int argc, char** argv) {
+// ::testing::InitGoogleTest(&argc, argv);
+// std::vector<int> values_to_test = LoadValuesFromConfig();
+// RegisterMyTests(values_to_test);
+// ...
+// return RUN_ALL_TESTS();
+// }
+//
+template <int&... ExplicitParameterBarrier, typename Factory>
+TestInfo* RegisterTest(const char* test_suite_name, const char* test_name,
+ const char* type_param, const char* value_param,
+ const char* file, int line, Factory factory) {
+ using TestT = typename std::remove_pointer<decltype(factory())>::type;
+
+ class FactoryImpl : public internal::TestFactoryBase {
+ public:
+ explicit FactoryImpl(Factory f) : factory_(std::move(f)) {}
+ Test* CreateTest() override { return factory_(); }
+
+ private:
+ Factory factory_;
+ };
+
+ return internal::MakeAndRegisterTestInfo(
+ test_suite_name, test_name, type_param, value_param,
+ internal::CodeLocation(file, line), internal::GetTypeId<TestT>(),
+ internal::SuiteApiResolver<TestT>::GetSetUpCaseOrSuite(file, line),
+ internal::SuiteApiResolver<TestT>::GetTearDownCaseOrSuite(file, line),
+ new FactoryImpl{std::move(factory)});
+}
+
+} // namespace testing
+
+// Use this function 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().
+//
+// This function was formerly a macro; thus, it is in the global
+// namespace and has an all-caps name.
+int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;
+
+inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); }
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest_pred_impl.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest_pred_impl.h
new file mode 100644
index 0000000..47a24aa
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest_pred_impl.h
@@ -0,0 +1,279 @@
+// 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.
+//
+// Implements a family of generic predicate assertion macros.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+#include "gtest/gtest-assertion-result.h"
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+
+// 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 <typename Pred, typename T1>
+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 " << ::testing::PrintToString(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 <typename Pred, typename T1, typename T2>
+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 " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(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 <typename Pred, typename T1, typename T2, typename T3>
+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 " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(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 <typename Pred, typename T1, typename T2, typename T3, typename T4>
+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 " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n"
+ << e4 << " evaluates to " << ::testing::PrintToString(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 <typename Pred, typename T1, typename T2, typename T3, typename T4,
+ typename T5>
+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 " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n"
+ << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n"
+ << e5 << " evaluates to " << ::testing::PrintToString(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_)
+
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/gtest_prod.h b/libs/cpp-httplib/test/gtest/include/gtest/gtest_prod.h
new file mode 100644
index 0000000..1f37dc3
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/gtest_prod.h
@@ -0,0 +1,60 @@
+// 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.
+
+// Google C++ Testing and Mocking Framework definitions useful in production
+// code.
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GOOGLETEST_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 PrivateMethod();
+// FRIEND_TEST(MyClassTest, PrivateMethodWorks);
+// };
+//
+// class MyClassTest : public testing::Test {
+// // ...
+// };
+//
+// TEST_F(MyClassTest, PrivateMethodWorks) {
+// // Can call MyClass::PrivateMethod() here.
+// }
+//
+// Note: The test class must be in the same namespace as the class being tested.
+// For example, putting MyClassTest in an anonymous namespace will not work.
+
+#define FRIEND_TEST(test_case_name, test_name) \
+ friend class test_case_name##_##test_name##_Test
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/README.md b/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/README.md
new file mode 100644
index 0000000..cb49e2c
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/README.md
@@ -0,0 +1,44 @@
+# Customization Points
+
+The custom directory is an injection point for custom user configurations.
+
+## Header `gtest.h`
+
+### The following macros can be defined:
+
+* `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of
+ `OsStackTraceGetterInterface`.
+* `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See
+ `testing::TempDir` for semantics and signature.
+
+## Header `gtest-port.h`
+
+The following macros can be defined:
+
+### Logging:
+
+* `GTEST_LOG_(severity)`
+* `GTEST_CHECK_(condition)`
+* Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too.
+
+### Threading:
+
+* `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided.
+* `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal`
+ are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)`
+ and `GTEST_DEFINE_STATIC_MUTEX_(mutex)`
+* `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)`
+* `GTEST_LOCK_EXCLUDED_(locks)`
+
+### Underlying library support features
+
+* `GTEST_HAS_CXXABI_H_`
+
+### Exporting API symbols:
+
+* `GTEST_API_` - Specifier for exported symbols.
+
+## Header `gtest-printers.h`
+
+* See documentation at `gtest/gtest-printers.h` for details on how to define a
+ custom printer.
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest-port.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest-port.h
new file mode 100644
index 0000000..db02881
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest-port.h
@@ -0,0 +1,37 @@
+// Copyright 2015, 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.
+//
+// Injection point for custom user configurations. See README for details
+//
+// ** Custom implementation starts here **
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest-printers.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest-printers.h
new file mode 100644
index 0000000..b9495d8
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest-printers.h
@@ -0,0 +1,42 @@
+// Copyright 2015, 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 provides an injection point for custom printers in a local
+// installation of gTest.
+// It will be included from gtest-printers.h and the overrides in this file
+// will be visible to everyone.
+//
+// Injection point for custom user configurations. See README for details
+//
+// ** Custom implementation starts here **
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest.h
new file mode 100644
index 0000000..afaaf17
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/custom/gtest.h
@@ -0,0 +1,37 @@
+// Copyright 2015, 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.
+//
+// Injection point for custom user configurations. See README for details
+//
+// ** Custom implementation starts here **
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-death-test-internal.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-death-test-internal.h
new file mode 100644
index 0000000..45580ae
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-death-test-internal.h
@@ -0,0 +1,306 @@
+// 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests. They are subject to change without notice.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+#include <stdio.h>
+
+#include <memory>
+
+#include "gtest/gtest-matchers.h"
+#include "gtest/internal/gtest-internal.h"
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+namespace testing {
+namespace internal {
+
+// 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
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// 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, Matcher<const std::string&> matcher,
+ 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_;
+ ReturnSentinel(const ReturnSentinel&) = delete;
+ ReturnSentinel& operator=(const ReturnSentinel&) = delete;
+ } 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 std::string& message);
+
+ private:
+ // A string containing a description of the outcome of the last death test.
+ static std::string last_death_test_message_;
+
+ DeathTest(const DeathTest&) = delete;
+ DeathTest& operator=(const DeathTest&) = delete;
+};
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+// Factory interface for death tests. May be mocked out for testing.
+class DeathTestFactory {
+ public:
+ virtual ~DeathTestFactory() {}
+ virtual bool Create(const char* statement,
+ Matcher<const std::string&> matcher, const char* file,
+ int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+ bool Create(const char* statement, Matcher<const std::string&> matcher,
+ const char* file, int line, DeathTest** test) override;
+};
+
+// 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);
+
+// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads
+// and interpreted as a regex (rather than an Eq matcher) for legacy
+// compatibility.
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ ::testing::internal::RE regex) {
+ return ContainsRegex(regex.pattern());
+}
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(const char* regex) {
+ return ContainsRegex(regex);
+}
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ const ::std::string& regex) {
+ return ContainsRegex(regex);
+}
+
+// If a Matcher<const ::std::string&> is passed to EXPECT_DEATH (etc.), it's
+// used directly.
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ Matcher<const ::std::string&> matcher) {
+ return matcher;
+}
+
+// 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_or_matcher, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::DeathTest* gtest_dt; \
+ if (!::testing::internal::DeathTest::Create( \
+ #statement, \
+ ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \
+ __FILE__, __LINE__, &gtest_dt)) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ if (gtest_dt != nullptr) { \
+ std::unique_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; \
+ } \
+ } \
+ } \
+ } 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.
+
+// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
+// NDEBUG mode. In this case we need the statements to be executed and the macro
+// must accept a streamed message even though the message is never printed.
+// The regex object is not evaluated, but it is used to prevent "unused"
+// warnings and to avoid an expression that doesn't compile in debug mode.
+#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } else if (!::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \
+ } else \
+ ::testing::Message()
+
+// 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 std::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_);
+ }
+
+ const std::string& file() const { return file_; }
+ int line() const { return line_; }
+ int index() const { return index_; }
+ int write_fd() const { return write_fd_; }
+
+ private:
+ std::string file_;
+ int line_;
+ int index_;
+ int write_fd_;
+
+ InternalRunDeathTestFlag(const InternalRunDeathTestFlag&) = delete;
+ InternalRunDeathTestFlag& operator=(const InternalRunDeathTestFlag&) = delete;
+};
+
+// 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();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace internal
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-filepath.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-filepath.h
new file mode 100644
index 0000000..a2a60a9
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-filepath.h
@@ -0,0 +1,210 @@
+// 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.
+
+// 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 gtest/internal/gtest-internal.h.
+// Do not include this header file separately!
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+#include "gtest/internal/gtest-string.h"
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+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 std::string& pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ FilePath& operator=(const FilePath& rhs) {
+ Set(rhs);
+ return *this;
+ }
+
+ void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; }
+
+ const std::string& string() 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_<number>.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 if and only if the path is "".
+ bool IsEmpty() const { return pathname_.empty(); }
+
+ // 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 occurrence 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;
+
+ std::string pathname_;
+}; // class FilePath
+
+} // namespace internal
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-internal.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-internal.h
new file mode 100644
index 0000000..9b04e4c
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-internal.h
@@ -0,0 +1,1570 @@
+// 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test. They are subject to change without notice.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_OS_LINUX
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+#include <stdexcept>
+#endif
+
+#include <ctype.h>
+#include <float.h>
+#include <string.h>
+
+#include <cstdint>
+#include <iomanip>
+#include <limits>
+#include <map>
+#include <set>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-filepath.h"
+#include "gtest/internal/gtest-string.h"
+#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
+
+// Stringifies its argument.
+// Work around a bug in visual studio which doesn't accept code like this:
+//
+// #define GTEST_STRINGIFY_(name) #name
+// #define MACRO(a, b, c) ... GTEST_STRINGIFY_(a) ...
+// MACRO(, x, y)
+//
+// Complaining about the argument to GTEST_STRINGIFY_ being empty.
+// This is allowed by the spec.
+#define GTEST_STRINGIFY_HELPER_(name, ...) #name
+#define GTEST_STRINGIFY_(...) GTEST_STRINGIFY_HELPER_(__VA_ARGS__, )
+
+namespace proto2 {
+class MessageLite;
+}
+
+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 suites.
+
+template <typename T>
+::std::string PrintToString(const T& value);
+
+namespace internal {
+
+struct TraceInfo; // Information about a trace point.
+class TestInfoImpl; // Opaque implementation of TestInfo
+class UnitTestImpl; // Opaque implementation of UnitTest
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+GTEST_API_ extern const char kStackTraceMarker[];
+
+// An IgnoredValue object can be implicitly constructed from ANY value.
+class IgnoredValue {
+ struct Sink {};
+
+ public:
+ // This constructor template allows any value to be implicitly
+ // converted to IgnoredValue. The object has no data member and
+ // doesn't try to remember anything about the argument. We
+ // deliberately omit the 'explicit' keyword in order to allow the
+ // conversion to be implicit.
+ // Disable the conversion if T already has a magical conversion operator.
+ // Otherwise we get ambiguity.
+ template <typename T,
+ typename std::enable_if<!std::is_convertible<T, Sink>::value,
+ int>::type = 0>
+ IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit)
+};
+
+// Appends the user-supplied message to the Google-Test-generated message.
+GTEST_API_ std::string AppendUserMessage(const std::string& gtest_msg,
+ const Message& user_msg);
+
+#if GTEST_HAS_EXCEPTIONS
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(
+ 4275 /* an exported class was derived from a class that was not exported */)
+
+// This exception is thrown by (and only by) a failed Google Test
+// assertion 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 GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
+ public:
+ explicit GoogleTestFailureException(const TestPartResult& failure);
+};
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+namespace edit_distance {
+// Returns the optimal edits to go from 'left' to 'right'.
+// All edits cost the same, with replace having lower priority than
+// add/remove.
+// Simple implementation of the Wagner-Fischer algorithm.
+// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
+enum EditType { kMatch, kAdd, kRemove, kReplace };
+GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<size_t>& left, const std::vector<size_t>& right);
+
+// Same as above, but the input is represented as strings.
+GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<std::string>& left,
+ const std::vector<std::string>& right);
+
+// Create a diff of the input strings in Unified diff format.
+GTEST_API_ std::string CreateUnifiedDiff(const std::vector<std::string>& left,
+ const std::vector<std::string>& right,
+ size_t context = 2);
+
+} // namespace edit_distance
+
+// 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 if and only if 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 std::string& expected_value,
+ const std::string& actual_value,
+ bool ignoring_case);
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+GTEST_API_ std::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 <typename RawType>
+class FloatingPoint {
+ public:
+ // Defines the unsigned integer type that has the same size as the
+ // floating point number.
+ typedef typename TypeWithSize<sizeof(RawType)>::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<RawType>::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<Bits>(1) << (kBitCount - 1);
+
+ // The mask for the fraction bits.
+ static const Bits kFractionBitMask = ~static_cast<Bits>(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://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+ static const uint32_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); }
+
+ // Returns the maximum representable finite floating-point number.
+ static RawType Max();
+
+ // 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 if and only if 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 if and only if 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_;
+};
+
+// We cannot use std::numeric_limits<T>::max() as it clashes with the max()
+// macro defined by <windows.h>.
+template <>
+inline float FloatingPoint<float>::Max() {
+ return FLT_MAX;
+}
+template <>
+inline double FloatingPoint<double>::Max() {
+ return DBL_MAX;
+}
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test suite, 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 <typename T>
+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<T>::dummy_ for different Ts as an "optimization".
+ static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() 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 <typename T>
+TypeId GetTypeId() {
+ // The compiler is required to allocate a different
+ // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+ // the template. Therefore, the address of dummy_ is guaranteed to
+ // be unique.
+ return &(TypeIdHelper<T>::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:
+ TestFactoryBase(const TestFactoryBase&) = delete;
+ TestFactoryBase& operator=(const TestFactoryBase&) = delete;
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase {
+ public:
+ Test* CreateTest() override { 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 SetUpTestSuite() and TearDownTestSuite() functions.
+using SetUpTestSuiteFunc = void (*)();
+using TearDownTestSuiteFunc = void (*)();
+
+struct CodeLocation {
+ CodeLocation(const std::string& a_file, int a_line)
+ : file(a_file), line(a_line) {}
+
+ std::string file;
+ int line;
+};
+
+// Helper to identify which setup function for TestCase / TestSuite to call.
+// Only one function is allowed, either TestCase or TestSute but not both.
+
+// Utility functions to help SuiteApiResolver
+using SetUpTearDownSuiteFuncType = void (*)();
+
+inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull(
+ SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) {
+ return a == def ? nullptr : a;
+}
+
+template <typename T>
+// Note that SuiteApiResolver inherits from T because
+// SetUpTestSuite()/TearDownTestSuite() could be protected. This way
+// SuiteApiResolver can access them.
+struct SuiteApiResolver : T {
+ // testing::Test is only forward declared at this point. So we make it a
+ // dependent class for the compiler to be OK with it.
+ using Test =
+ typename std::conditional<sizeof(T) != 0, ::testing::Test, void>::type;
+
+ static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename,
+ int line_num) {
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ SetUpTearDownSuiteFuncType test_case_fp =
+ GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase);
+ SetUpTearDownSuiteFuncType test_suite_fp =
+ GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite);
+
+ GTEST_CHECK_(!test_case_fp || !test_suite_fp)
+ << "Test can not provide both SetUpTestSuite and SetUpTestCase, please "
+ "make sure there is only one present at "
+ << filename << ":" << line_num;
+
+ return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
+#else
+ (void)(filename);
+ (void)(line_num);
+ return &T::SetUpTestSuite;
+#endif
+ }
+
+ static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename,
+ int line_num) {
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ SetUpTearDownSuiteFuncType test_case_fp =
+ GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase);
+ SetUpTearDownSuiteFuncType test_suite_fp =
+ GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite);
+
+ GTEST_CHECK_(!test_case_fp || !test_suite_fp)
+ << "Test can not provide both TearDownTestSuite and TearDownTestCase,"
+ " please make sure there is only one present at"
+ << filename << ":" << line_num;
+
+ return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
+#else
+ (void)(filename);
+ (void)(line_num);
+ return &T::TearDownTestSuite;
+#endif
+ }
+};
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_suite_name: name of the test suite
+// 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.
+// code_location: code location where the test is defined
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+// 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_suite_name, const char* name, const char* type_param,
+ const char* value_param, CodeLocation code_location,
+ TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
+ TearDownTestSuiteFunc 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);
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// State of the definition of a type-parameterized test suite.
+class GTEST_API_ TypedTestSuitePState {
+ public:
+ TypedTestSuitePState() : registered_(false) {}
+
+ // Adds the given test name to defined_test_names_ and return true
+ // if the test suite 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_SUITE_P(%s, ...).\n",
+ FormatFileLocation(file, line).c_str(), test_name, case_name);
+ fflush(stderr);
+ posix::Abort();
+ }
+ registered_tests_.insert(
+ ::std::make_pair(test_name, CodeLocation(file, line)));
+ return true;
+ }
+
+ bool TestExists(const std::string& test_name) const {
+ return registered_tests_.count(test_name) > 0;
+ }
+
+ const CodeLocation& GetCodeLocation(const std::string& test_name) const {
+ RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name);
+ GTEST_CHECK_(it != registered_tests_.end());
+ return it->second;
+ }
+
+ // 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* test_suite_name,
+ const char* file, int line,
+ const char* registered_tests);
+
+ private:
+ typedef ::std::map<std::string, CodeLocation> RegisteredTestsMap;
+
+ bool registered_;
+ RegisteredTestsMap registered_tests_;
+};
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+using TypedTestCasePState = TypedTestSuitePState;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+// 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 == nullptr) {
+ return nullptr;
+ }
+ 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 std::string GetPrefixUntilComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ return comma == nullptr ? str : std::string(str, comma);
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields.
+void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector<::std::string>* dest);
+
+// The default argument to the template below for the case when the user does
+// not provide a name generator.
+struct DefaultNameGenerator {
+ template <typename T>
+ static std::string GetName(int i) {
+ return StreamableToString(i);
+ }
+};
+
+template <typename Provided = DefaultNameGenerator>
+struct NameGeneratorSelector {
+ typedef Provided type;
+};
+
+template <typename NameGenerator>
+void GenerateNamesRecursively(internal::None, std::vector<std::string>*, int) {}
+
+template <typename NameGenerator, typename Types>
+void GenerateNamesRecursively(Types, std::vector<std::string>* result, int i) {
+ result->push_back(NameGenerator::template GetName<typename Types::Head>(i));
+ GenerateNamesRecursively<NameGenerator>(typename Types::Tail(), result,
+ i + 1);
+}
+
+template <typename NameGenerator, typename Types>
+std::vector<std::string> GenerateNames() {
+ std::vector<std::string> result;
+ GenerateNamesRecursively<NameGenerator>(Types(), &result, 0);
+ return result;
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::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 <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+ // 'index' is the index of the test in the type list 'Types'
+ // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite,
+ // Types). Valid values for 'index' are [0, N - 1] where N is the
+ // length of Types.
+ static bool Register(const char* prefix, const CodeLocation& code_location,
+ const char* case_name, const char* test_names, int index,
+ const std::vector<std::string>& type_names =
+ GenerateNames<DefaultNameGenerator, Types>()) {
+ typedef typename Types::Head Type;
+ typedef Fixture<Type> FixtureClass;
+ typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+ // First, registers the first type-parameterized test in the type
+ // list.
+ MakeAndRegisterTestInfo(
+ (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name +
+ "/" + type_names[static_cast<size_t>(index)])
+ .c_str(),
+ StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(),
+ GetTypeName<Type>().c_str(),
+ nullptr, // No value parameter.
+ code_location, GetTypeId<FixtureClass>(),
+ SuiteApiResolver<TestClass>::GetSetUpCaseOrSuite(
+ code_location.file.c_str(), code_location.line),
+ SuiteApiResolver<TestClass>::GetTearDownCaseOrSuite(
+ code_location.file.c_str(), code_location.line),
+ new TestFactoryImpl<TestClass>);
+
+ // Next, recurses (at compile time) with the tail of the type list.
+ return TypeParameterizedTest<Fixture, TestSel,
+ typename Types::Tail>::Register(prefix,
+ code_location,
+ case_name,
+ test_names,
+ index + 1,
+ type_names);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, internal::None> {
+ public:
+ static bool Register(const char* /*prefix*/, const CodeLocation&,
+ const char* /*case_name*/, const char* /*test_names*/,
+ int /*index*/,
+ const std::vector<std::string>& =
+ std::vector<std::string>() /*type_names*/) {
+ return true;
+ }
+};
+
+GTEST_API_ void RegisterTypeParameterizedTestSuite(const char* test_suite_name,
+ CodeLocation code_location);
+GTEST_API_ void RegisterTypeParameterizedTestSuiteInstantiation(
+ const char* case_name);
+
+// TypeParameterizedTestSuite<Fixture, Tests, Types>::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 <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestSuite {
+ public:
+ static bool Register(const char* prefix, CodeLocation code_location,
+ const TypedTestSuitePState* state, const char* case_name,
+ const char* test_names,
+ const std::vector<std::string>& type_names =
+ GenerateNames<DefaultNameGenerator, Types>()) {
+ RegisterTypeParameterizedTestSuiteInstantiation(case_name);
+ std::string test_name =
+ StripTrailingSpaces(GetPrefixUntilComma(test_names));
+ if (!state->TestExists(test_name)) {
+ fprintf(stderr, "Failed to get code location for test %s.%s at %s.",
+ case_name, test_name.c_str(),
+ FormatFileLocation(code_location.file.c_str(), code_location.line)
+ .c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+ const CodeLocation& test_location = state->GetCodeLocation(test_name);
+
+ typedef typename Tests::Head Head;
+
+ // First, register the first test in 'Test' for each type in 'Types'.
+ TypeParameterizedTest<Fixture, Head, Types>::Register(
+ prefix, test_location, case_name, test_names, 0, type_names);
+
+ // Next, recurses (at compile time) with the tail of the test list.
+ return TypeParameterizedTestSuite<Fixture, typename Tests::Tail,
+ Types>::Register(prefix, code_location,
+ state, case_name,
+ SkipComma(test_names),
+ type_names);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestSuite<Fixture, internal::None, Types> {
+ public:
+ static bool Register(const char* /*prefix*/, const CodeLocation&,
+ const TypedTestSuitePState* /*state*/,
+ const char* /*case_name*/, const char* /*test_names*/,
+ const std::vector<std::string>& =
+ std::vector<std::string>() /*type_names*/) {
+ return true;
+ }
+};
+
+// Returns the current OS stack trace as an std::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_ std::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;
+};
+
+// Helper for declaring std::string within 'if' statement
+// in pre C++17 build environment.
+struct TrueWithString {
+ TrueWithString() = default;
+ explicit TrueWithString(const char* str) : value(str) {}
+ explicit TrueWithString(const std::string& str) : value(str) {}
+ explicit operator bool() const { return true; }
+ std::string 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_t kMaxRange = 1u << 31;
+
+ explicit Random(uint32_t seed) : state_(seed) {}
+
+ void Reseed(uint32_t seed) { state_ = seed; }
+
+ // Generates a random number from [0, range). Crashes if 'range' is
+ // 0 or greater than kMaxRange.
+ uint32_t Generate(uint32_t range);
+
+ private:
+ uint32_t state_;
+ Random(const Random&) = delete;
+ Random& operator=(const Random&) = delete;
+};
+
+// Turns const U&, U&, const U, and U all into U.
+#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
+ typename std::remove_const<typename std::remove_reference<T>::type>::type
+
+// HasDebugStringAndShortDebugString<T>::value is a compile-time bool constant
+// that's true if and only if T has methods DebugString() and ShortDebugString()
+// that return std::string.
+template <typename T>
+class HasDebugStringAndShortDebugString {
+ private:
+ template <typename C>
+ static auto CheckDebugString(C*) -> typename std::is_same<
+ std::string, decltype(std::declval<const C>().DebugString())>::type;
+ template <typename>
+ static std::false_type CheckDebugString(...);
+
+ template <typename C>
+ static auto CheckShortDebugString(C*) -> typename std::is_same<
+ std::string, decltype(std::declval<const C>().ShortDebugString())>::type;
+ template <typename>
+ static std::false_type CheckShortDebugString(...);
+
+ using HasDebugStringType = decltype(CheckDebugString<T>(nullptr));
+ using HasShortDebugStringType = decltype(CheckShortDebugString<T>(nullptr));
+
+ public:
+ static constexpr bool value =
+ HasDebugStringType::value && HasShortDebugStringType::value;
+};
+
+template <typename T>
+constexpr bool HasDebugStringAndShortDebugString<T>::value;
+
+// When the compiler sees expression IsContainerTest<C>(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<C>(0).
+// The value of the expression is insignificant.
+//
+// In C++11 mode we check the existence of a const_iterator and that an
+// iterator is properly implemented for the container.
+//
+// For pre-C++11 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 <class C,
+ class Iterator = decltype(::std::declval<const C&>().begin()),
+ class = decltype(::std::declval<const C&>().end()),
+ class = decltype(++::std::declval<Iterator&>()),
+ class = decltype(*::std::declval<Iterator>()),
+ class = typename C::const_iterator>
+IsContainer IsContainerTest(int /* dummy */) {
+ return 0;
+}
+
+typedef char IsNotContainer;
+template <class C>
+IsNotContainer IsContainerTest(long /* dummy */) {
+ return '\0';
+}
+
+// Trait to detect whether a type T is a hash table.
+// The heuristic used is that the type contains an inner type `hasher` and does
+// not contain an inner type `reverse_iterator`.
+// If the container is iterable in reverse, then order might actually matter.
+template <typename T>
+struct IsHashTable {
+ private:
+ template <typename U>
+ static char test(typename U::hasher*, typename U::reverse_iterator*);
+ template <typename U>
+ static int test(typename U::hasher*, ...);
+ template <typename U>
+ static char test(...);
+
+ public:
+ static const bool value = sizeof(test<T>(nullptr, nullptr)) == sizeof(int);
+};
+
+template <typename T>
+const bool IsHashTable<T>::value;
+
+template <typename C,
+ bool = sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer)>
+struct IsRecursiveContainerImpl;
+
+template <typename C>
+struct IsRecursiveContainerImpl<C, false> : public std::false_type {};
+
+// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to
+// obey the same inconsistencies as the IsContainerTest, namely check if
+// something is a container is relying on only const_iterator in C++11 and
+// is relying on both const_iterator and iterator otherwise
+template <typename C>
+struct IsRecursiveContainerImpl<C, true> {
+ using value_type = decltype(*std::declval<typename C::const_iterator>());
+ using type =
+ std::is_same<typename std::remove_const<
+ typename std::remove_reference<value_type>::type>::type,
+ C>;
+};
+
+// IsRecursiveContainer<Type> is a unary compile-time predicate that
+// evaluates whether C is a recursive container type. A recursive container
+// type is a container type whose value_type is equal to the container type
+// itself. An example for a recursive container type is
+// boost::filesystem::path, whose iterator has a value_type that is equal to
+// boost::filesystem::path.
+template <typename C>
+struct IsRecursiveContainer : public IsRecursiveContainerImpl<C>::type {};
+
+// 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 <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline bool ArrayEq(const T& lhs, const U& rhs) {
+ return lhs == rhs;
+}
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+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 <typename T, typename U>
+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 <typename Iter, typename Element>
+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 <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline void CopyArray(const T& from, U* to) {
+ *to = from;
+}
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+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 <typename T, typename U>
+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.
+// We use 2 different structs to allow non-copyable types to be used, as long
+// as RelationToSourceReference() is passed.
+struct RelationToSourceReference {};
+struct RelationToSourceCopy {};
+
+// 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 <typename Element>
+class NativeArray {
+ public:
+ // STL-style container typedefs.
+ typedef Element value_type;
+ typedef Element* iterator;
+ typedef const Element* const_iterator;
+
+ // Constructs from a native array. References the source.
+ NativeArray(const Element* array, size_t count, RelationToSourceReference) {
+ InitRef(array, count);
+ }
+
+ // Constructs from a native array. Copies the source.
+ NativeArray(const Element* array, size_t count, RelationToSourceCopy) {
+ InitCopy(array, count);
+ }
+
+ // Copy constructor.
+ NativeArray(const NativeArray& rhs) {
+ (this->*rhs.clone_)(rhs.array_, rhs.size_);
+ }
+
+ ~NativeArray() {
+ if (clone_ != &NativeArray::InitRef) 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:
+ static_assert(!std::is_const<Element>::value, "Type must not be const");
+ static_assert(!std::is_reference<Element>::value,
+ "Type must not be a reference");
+
+ // Initializes this object with a copy of the input.
+ void InitCopy(const Element* array, size_t a_size) {
+ Element* const copy = new Element[a_size];
+ CopyArray(array, a_size, copy);
+ array_ = copy;
+ size_ = a_size;
+ clone_ = &NativeArray::InitCopy;
+ }
+
+ // Initializes this object with a reference of the input.
+ void InitRef(const Element* array, size_t a_size) {
+ array_ = array;
+ size_ = a_size;
+ clone_ = &NativeArray::InitRef;
+ }
+
+ const Element* array_;
+ size_t size_;
+ void (NativeArray::*clone_)(const Element*, size_t);
+};
+
+// Backport of std::index_sequence.
+template <size_t... Is>
+struct IndexSequence {
+ using type = IndexSequence;
+};
+
+// Double the IndexSequence, and one if plus_one is true.
+template <bool plus_one, typename T, size_t sizeofT>
+struct DoubleSequence;
+template <size_t... I, size_t sizeofT>
+struct DoubleSequence<true, IndexSequence<I...>, sizeofT> {
+ using type = IndexSequence<I..., (sizeofT + I)..., 2 * sizeofT>;
+};
+template <size_t... I, size_t sizeofT>
+struct DoubleSequence<false, IndexSequence<I...>, sizeofT> {
+ using type = IndexSequence<I..., (sizeofT + I)...>;
+};
+
+// Backport of std::make_index_sequence.
+// It uses O(ln(N)) instantiation depth.
+template <size_t N>
+struct MakeIndexSequenceImpl
+ : DoubleSequence<N % 2 == 1, typename MakeIndexSequenceImpl<N / 2>::type,
+ N / 2>::type {};
+
+template <>
+struct MakeIndexSequenceImpl<0> : IndexSequence<> {};
+
+template <size_t N>
+using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::type;
+
+template <typename... T>
+using IndexSequenceFor = typename MakeIndexSequence<sizeof...(T)>::type;
+
+template <size_t>
+struct Ignore {
+ Ignore(...); // NOLINT
+};
+
+template <typename>
+struct ElemFromListImpl;
+template <size_t... I>
+struct ElemFromListImpl<IndexSequence<I...>> {
+ // We make Ignore a template to solve a problem with MSVC.
+ // A non-template Ignore would work fine with `decltype(Ignore(I))...`, but
+ // MSVC doesn't understand how to deal with that pack expansion.
+ // Use `0 * I` to have a single instantiation of Ignore.
+ template <typename R>
+ static R Apply(Ignore<0 * I>..., R (*)(), ...);
+};
+
+template <size_t N, typename... T>
+struct ElemFromList {
+ using type =
+ decltype(ElemFromListImpl<typename MakeIndexSequence<N>::type>::Apply(
+ static_cast<T (*)()>(nullptr)...));
+};
+
+struct FlatTupleConstructTag {};
+
+template <typename... T>
+class FlatTuple;
+
+template <typename Derived, size_t I>
+struct FlatTupleElemBase;
+
+template <typename... T, size_t I>
+struct FlatTupleElemBase<FlatTuple<T...>, I> {
+ using value_type = typename ElemFromList<I, T...>::type;
+ FlatTupleElemBase() = default;
+ template <typename Arg>
+ explicit FlatTupleElemBase(FlatTupleConstructTag, Arg&& t)
+ : value(std::forward<Arg>(t)) {}
+ value_type value;
+};
+
+template <typename Derived, typename Idx>
+struct FlatTupleBase;
+
+template <size_t... Idx, typename... T>
+struct FlatTupleBase<FlatTuple<T...>, IndexSequence<Idx...>>
+ : FlatTupleElemBase<FlatTuple<T...>, Idx>... {
+ using Indices = IndexSequence<Idx...>;
+ FlatTupleBase() = default;
+ template <typename... Args>
+ explicit FlatTupleBase(FlatTupleConstructTag, Args&&... args)
+ : FlatTupleElemBase<FlatTuple<T...>, Idx>(FlatTupleConstructTag{},
+ std::forward<Args>(args))... {}
+
+ template <size_t I>
+ const typename ElemFromList<I, T...>::type& Get() const {
+ return FlatTupleElemBase<FlatTuple<T...>, I>::value;
+ }
+
+ template <size_t I>
+ typename ElemFromList<I, T...>::type& Get() {
+ return FlatTupleElemBase<FlatTuple<T...>, I>::value;
+ }
+
+ template <typename F>
+ auto Apply(F&& f) -> decltype(std::forward<F>(f)(this->Get<Idx>()...)) {
+ return std::forward<F>(f)(Get<Idx>()...);
+ }
+
+ template <typename F>
+ auto Apply(F&& f) const -> decltype(std::forward<F>(f)(this->Get<Idx>()...)) {
+ return std::forward<F>(f)(Get<Idx>()...);
+ }
+};
+
+// Analog to std::tuple but with different tradeoffs.
+// This class minimizes the template instantiation depth, thus allowing more
+// elements than std::tuple would. std::tuple has been seen to require an
+// instantiation depth of more than 10x the number of elements in some
+// implementations.
+// FlatTuple and ElemFromList are not recursive and have a fixed depth
+// regardless of T...
+// MakeIndexSequence, on the other hand, it is recursive but with an
+// instantiation depth of O(ln(N)).
+template <typename... T>
+class FlatTuple
+ : private FlatTupleBase<FlatTuple<T...>,
+ typename MakeIndexSequence<sizeof...(T)>::type> {
+ using Indices = typename FlatTupleBase<
+ FlatTuple<T...>, typename MakeIndexSequence<sizeof...(T)>::type>::Indices;
+
+ public:
+ FlatTuple() = default;
+ template <typename... Args>
+ explicit FlatTuple(FlatTupleConstructTag tag, Args&&... args)
+ : FlatTuple::FlatTupleBase(tag, std::forward<Args>(args)...) {}
+
+ using FlatTuple::FlatTupleBase::Apply;
+ using FlatTuple::FlatTupleBase::Get;
+};
+
+// Utility functions to be called with static_assert to induce deprecation
+// warnings.
+GTEST_INTERNAL_DEPRECATED(
+ "INSTANTIATE_TEST_CASE_P is deprecated, please use "
+ "INSTANTIATE_TEST_SUITE_P")
+constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "TYPED_TEST_CASE_P is deprecated, please use "
+ "TYPED_TEST_SUITE_P")
+constexpr bool TypedTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "TYPED_TEST_CASE is deprecated, please use "
+ "TYPED_TEST_SUITE")
+constexpr bool TypedTestCaseIsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "REGISTER_TYPED_TEST_CASE_P is deprecated, please use "
+ "REGISTER_TYPED_TEST_SUITE_P")
+constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use "
+ "INSTANTIATE_TYPED_TEST_SUITE_P")
+constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; }
+
+} // namespace internal
+} // namespace testing
+
+namespace std {
+// Some standard library implementations use `struct tuple_size` and some use
+// `class tuple_size`. Clang warns about the mismatch.
+// https://reviews.llvm.org/D55466
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmismatched-tags"
+#endif
+template <typename... Ts>
+struct tuple_size<testing::internal::FlatTuple<Ts...>>
+ : std::integral_constant<size_t, sizeof...(Ts)> {};
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+} // namespace std
+
+#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)
+
+#define GTEST_SKIP_(message) \
+ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip)
+
+// Suppress MSVC warning 4072 (unreachable code) for the code following
+// statement if it returns or throws (or doesn't return or throw in some
+// situations).
+// NOTE: The "else" is important to keep this expansion to prevent a top-level
+// "else" from attaching to our "if".
+#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
+ if (::testing::internal::AlwaysTrue()) { \
+ statement; \
+ } else /* NOLINT */ \
+ static_assert(true, "") // User must have a semicolon after expansion.
+
+#if GTEST_HAS_EXCEPTIONS
+
+namespace testing {
+namespace internal {
+
+class NeverThrown {
+ public:
+ const char* what() const noexcept {
+ return "this exception should never be thrown";
+ }
+};
+
+} // namespace internal
+} // namespace testing
+
+#if GTEST_HAS_RTTI
+
+#define GTEST_EXCEPTION_TYPE_(e) ::testing::internal::GetTypeName(typeid(e))
+
+#else // GTEST_HAS_RTTI
+
+#define GTEST_EXCEPTION_TYPE_(e) \
+ std::string { "an std::exception-derived error" }
+
+#endif // GTEST_HAS_RTTI
+
+#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \
+ catch (typename std::conditional< \
+ std::is_same<typename std::remove_cv<typename std::remove_reference< \
+ expected_exception>::type>::type, \
+ std::exception>::value, \
+ const ::testing::internal::NeverThrown&, const std::exception&>::type \
+ e) { \
+ gtest_msg.value = "Expected: " #statement \
+ " throws an exception of type " #expected_exception \
+ ".\n Actual: it throws "; \
+ gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \
+ gtest_msg.value += " with description \""; \
+ gtest_msg.value += e.what(); \
+ gtest_msg.value += "\"."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ }
+
+#else // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception)
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::TrueWithString gtest_msg{}) { \
+ bool gtest_caught_expected = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (expected_exception const&) { \
+ gtest_caught_expected = true; \
+ } \
+ GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \
+ 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 /*NOLINT*/ \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
+ : fail(gtest_msg.value.c_str())
+
+#if GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \
+ catch (std::exception const& e) { \
+ gtest_msg.value = "it throws "; \
+ gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \
+ gtest_msg.value += " with description \""; \
+ gtest_msg.value += e.what(); \
+ gtest_msg.value += "\"."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+ }
+
+#else // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_()
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::TrueWithString gtest_msg{}) { \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \
+ catch (...) { \
+ gtest_msg.value = "it throws."; \
+ 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: " + \
+ gtest_msg.value) \
+ .c_str())
+
+#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
+// representation 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_suite_name, test_name) \
+ test_suite_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \
+ static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \
+ "test_suite_name must not be empty"); \
+ static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \
+ "test_name must not be empty"); \
+ class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ : public parent_class { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() = default; \
+ ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ (const GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) &) = delete; \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) & operator=( \
+ const GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name) &) = delete; /* NOLINT */ \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ (GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) &&) noexcept = delete; \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) & operator=( \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name) &&) noexcept = delete; /* NOLINT */ \
+ \
+ private: \
+ void TestBody() override; \
+ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \
+ }; \
+ \
+ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)::test_info_ = \
+ ::testing::internal::MakeAndRegisterTestInfo( \
+ #test_suite_name, #test_name, nullptr, nullptr, \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \
+ ::testing::internal::SuiteApiResolver< \
+ parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \
+ ::testing::internal::SuiteApiResolver< \
+ parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \
+ new ::testing::internal::TestFactoryImpl<GTEST_TEST_CLASS_NAME_( \
+ test_suite_name, test_name)>); \
+ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody()
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-param-util.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-param-util.h
new file mode 100644
index 0000000..e7af2f9
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-param-util.h
@@ -0,0 +1,956 @@
+// 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.
+
+// Type and function utilities for implementing parameterized tests.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <ctype.h>
+
+#include <cassert>
+#include <iterator>
+#include <memory>
+#include <set>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest-printers.h"
+#include "gtest/gtest-test-part.h"
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+// Input to a parameterized test name generator, describing a test parameter.
+// Consists of the parameter value and the integer parameter index.
+template <class ParamType>
+struct TestParamInfo {
+ TestParamInfo(const ParamType& a_param, size_t an_index)
+ : param(a_param), index(an_index) {}
+ ParamType param;
+ size_t index;
+};
+
+// A builtin parameterized test name generator which returns the result of
+// testing::PrintToString.
+struct PrintToStringParamName {
+ template <class ParamType>
+ std::string operator()(const TestParamInfo<ParamType>& info) const {
+ return PrintToString(info.param);
+ }
+};
+
+namespace internal {
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// Utility Functions
+
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test suite. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name,
+ CodeLocation code_location);
+
+template <typename>
+class ParamGeneratorInterface;
+template <typename>
+class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+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<T>* 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<T>.
+ 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<T>::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<T>::operator==().
+ virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+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<T>* 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<T>;
+ explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+ std::unique_ptr<ParamIteratorInterface<T>> impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface {
+ public:
+ typedef T ParamType;
+
+ virtual ~ParamGeneratorInterface() {}
+
+ // Generator interface definition
+ virtual ParamIteratorInterface<T>* Begin() const = 0;
+ virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInterface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template <typename T>
+class ParamGenerator {
+ public:
+ typedef ParamIterator<T> iterator;
+
+ explicit ParamGenerator(ParamGeneratorInterface<T>* 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:
+ std::shared_ptr<const ParamGeneratorInterface<T>> 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 <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ RangeGenerator(T begin, T end, IncrementT step)
+ : begin_(begin),
+ end_(end),
+ step_(step),
+ end_index_(CalculateEndIndex(begin, end, step)) {}
+ ~RangeGenerator() override {}
+
+ ParamIteratorInterface<T>* Begin() const override {
+ return new Iterator(this, begin_, 0, step_);
+ }
+ ParamIteratorInterface<T>* End() const override {
+ return new Iterator(this, end_, end_index_, step_);
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+ IncrementT step)
+ : base_(base), value_(value), index_(index), step_(step) {}
+ ~Iterator() override {}
+
+ const ParamGeneratorInterface<T>* BaseGenerator() const override {
+ return base_;
+ }
+ void Advance() override {
+ value_ = static_cast<T>(value_ + step_);
+ index_++;
+ }
+ ParamIteratorInterface<T>* Clone() const override {
+ return new Iterator(*this);
+ }
+ const T* Current() const override { return &value_; }
+ bool Equals(const ParamIteratorInterface<T>& other) const override {
+ // 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<const Iterator>(&other)->index_;
+ return index_ == other_index;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : ParamIteratorInterface<T>(),
+ base_(other.base_),
+ value_(other.value_),
+ index_(other.index_),
+ step_(other.step_) {}
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<T>* 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 = static_cast<T>(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 <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ template <typename ForwardIterator>
+ ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+ : container_(begin, end) {}
+ ~ValuesInIteratorRangeGenerator() override {}
+
+ ParamIteratorInterface<T>* Begin() const override {
+ return new Iterator(this, container_.begin());
+ }
+ ParamIteratorInterface<T>* End() const override {
+ return new Iterator(this, container_.end());
+ }
+
+ private:
+ typedef typename ::std::vector<T> ContainerType;
+
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base,
+ typename ContainerType::const_iterator iterator)
+ : base_(base), iterator_(iterator) {}
+ ~Iterator() override {}
+
+ const ParamGeneratorInterface<T>* BaseGenerator() const override {
+ return base_;
+ }
+ void Advance() override {
+ ++iterator_;
+ value_.reset();
+ }
+ ParamIteratorInterface<T>* Clone() const override {
+ 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.
+ const T* Current() const override {
+ if (value_.get() == nullptr) value_.reset(new T(*iterator_));
+ return value_.get();
+ }
+ bool Equals(const ParamIteratorInterface<T>& other) const override {
+ // 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<const Iterator>(&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<T>(),
+ base_(other.base_),
+ iterator_(other.iterator_) {}
+
+ const ParamGeneratorInterface<T>* 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 std::unique_ptr helps manage cached value's lifetime,
+ // which is bound by the lifespan of the iterator itself.
+ mutable std::unique_ptr<const T> 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.
+//
+// Default parameterized test name generator, returns a string containing the
+// integer test parameter index.
+template <class ParamType>
+std::string DefaultParamName(const TestParamInfo<ParamType>& info) {
+ Message name_stream;
+ name_stream << info.index;
+ return name_stream.GetString();
+}
+
+template <typename T = int>
+void TestNotEmpty() {
+ static_assert(sizeof(T) == 0, "Empty arguments are not allowed.");
+}
+template <typename T = int>
+void TestNotEmpty(const T&) {}
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase {
+ public:
+ typedef typename TestClass::ParamType ParamType;
+ explicit ParameterizedTestFactory(ParamType parameter)
+ : parameter_(parameter) {}
+ Test* CreateTest() override {
+ TestClass::SetParam(&parameter_);
+ return new TestClass();
+ }
+
+ private:
+ const ParamType parameter_;
+
+ ParameterizedTestFactory(const ParameterizedTestFactory&) = delete;
+ ParameterizedTestFactory& operator=(const ParameterizedTestFactory&) = delete;
+};
+
+// 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 ParamType>
+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 ParameterizedTestSuiteInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestSuite>
+class TestMetaFactory
+ : public TestMetaFactoryBase<typename TestSuite::ParamType> {
+ public:
+ using ParamType = typename TestSuite::ParamType;
+
+ TestMetaFactory() {}
+
+ TestFactoryBase* CreateTestFactory(ParamType parameter) override {
+ return new ParameterizedTestFactory<TestSuite>(parameter);
+ }
+
+ private:
+ TestMetaFactory(const TestMetaFactory&) = delete;
+ TestMetaFactory& operator=(const TestMetaFactory&) = delete;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestSuiteInfoBase is a generic interface
+// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds
+// a collection of pointers to the ParameterizedTestSuiteInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestSuiteInfoBase {
+ public:
+ virtual ~ParameterizedTestSuiteInfoBase() {}
+
+ // Base part of test suite name for display purposes.
+ virtual const std::string& GetTestSuiteName() const = 0;
+ // Test suite id to verify identity.
+ virtual TypeId GetTestSuiteTypeId() const = 0;
+ // UnitTest class invokes this method to register tests in this
+ // test suite right before running them in RUN_ALL_TESTS macro.
+ // This method should not be called more than once on any single
+ // instance of a ParameterizedTestSuiteInfoBase derived class.
+ virtual void RegisterTests() = 0;
+
+ protected:
+ ParameterizedTestSuiteInfoBase() {}
+
+ private:
+ ParameterizedTestSuiteInfoBase(const ParameterizedTestSuiteInfoBase&) =
+ delete;
+ ParameterizedTestSuiteInfoBase& operator=(
+ const ParameterizedTestSuiteInfoBase&) = delete;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Report a the name of a test_suit as safe to ignore
+// as the side effect of construction of this type.
+struct GTEST_API_ MarkAsIgnored {
+ explicit MarkAsIgnored(const char* test_suite);
+};
+
+GTEST_API_ void InsertSyntheticTestCase(const std::string& name,
+ CodeLocation location, bool has_test_p);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test suite and generators
+// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that
+// test suite. It registers tests with all values generated by all
+// generators when asked.
+template <class TestSuite>
+class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase {
+ public:
+ // ParamType and GeneratorCreationFunc are private types but are required
+ // for declarations of public methods AddTestPattern() and
+ // AddTestSuiteInstantiation().
+ using ParamType = typename TestSuite::ParamType;
+ // A function that returns an instance of appropriate generator type.
+ typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+ using ParamNameGeneratorFunc = std::string(const TestParamInfo<ParamType>&);
+
+ explicit ParameterizedTestSuiteInfo(const char* name,
+ CodeLocation code_location)
+ : test_suite_name_(name), code_location_(code_location) {}
+
+ // Test suite base name for display purposes.
+ const std::string& GetTestSuiteName() const override {
+ return test_suite_name_;
+ }
+ // Test suite id to verify identity.
+ TypeId GetTestSuiteTypeId() const override { return GetTypeId<TestSuite>(); }
+ // TEST_P macro uses AddTestPattern() to record information
+ // about a single test in a LocalTestInfo structure.
+ // test_suite_name is the base name of the test suite (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 suite base name and DoBar is test base name.
+ void AddTestPattern(const char* test_suite_name, const char* test_base_name,
+ TestMetaFactoryBase<ParamType>* meta_factory,
+ CodeLocation code_location) {
+ tests_.push_back(std::shared_ptr<TestInfo>(new TestInfo(
+ test_suite_name, test_base_name, meta_factory, code_location)));
+ }
+ // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information
+ // about a generator.
+ int AddTestSuiteInstantiation(const std::string& instantiation_name,
+ GeneratorCreationFunc* func,
+ ParamNameGeneratorFunc* name_func,
+ const char* file, int line) {
+ instantiations_.push_back(
+ InstantiationInfo(instantiation_name, func, name_func, file, line));
+ return 0; // Return value used only to run this method in namespace scope.
+ }
+ // UnitTest class invokes this method to register tests in this test suite
+ // right before running tests in RUN_ALL_TESTS macro.
+ // This method should not be called more than once on any single
+ // instance of a ParameterizedTestSuiteInfoBase derived class.
+ // UnitTest has a guard to prevent from calling this method more than once.
+ void RegisterTests() override {
+ bool generated_instantiations = false;
+
+ for (typename TestInfoContainer::iterator test_it = tests_.begin();
+ test_it != tests_.end(); ++test_it) {
+ std::shared_ptr<TestInfo> test_info = *test_it;
+ for (typename InstantiationContainer::iterator gen_it =
+ instantiations_.begin();
+ gen_it != instantiations_.end(); ++gen_it) {
+ const std::string& instantiation_name = gen_it->name;
+ ParamGenerator<ParamType> generator((*gen_it->generator)());
+ ParamNameGeneratorFunc* name_func = gen_it->name_func;
+ const char* file = gen_it->file;
+ int line = gen_it->line;
+
+ std::string test_suite_name;
+ if (!instantiation_name.empty())
+ test_suite_name = instantiation_name + "/";
+ test_suite_name += test_info->test_suite_base_name;
+
+ size_t i = 0;
+ std::set<std::string> test_param_names;
+ for (typename ParamGenerator<ParamType>::iterator param_it =
+ generator.begin();
+ param_it != generator.end(); ++param_it, ++i) {
+ generated_instantiations = true;
+
+ Message test_name_stream;
+
+ std::string param_name =
+ name_func(TestParamInfo<ParamType>(*param_it, i));
+
+ GTEST_CHECK_(IsValidParamName(param_name))
+ << "Parameterized test name '" << param_name
+ << "' is invalid, in " << file << " line " << line << std::endl;
+
+ GTEST_CHECK_(test_param_names.count(param_name) == 0)
+ << "Duplicate parameterized test name '" << param_name << "', in "
+ << file << " line " << line << std::endl;
+
+ test_param_names.insert(param_name);
+
+ if (!test_info->test_base_name.empty()) {
+ test_name_stream << test_info->test_base_name << "/";
+ }
+ test_name_stream << param_name;
+ MakeAndRegisterTestInfo(
+ test_suite_name.c_str(), test_name_stream.GetString().c_str(),
+ nullptr, // No type parameter.
+ PrintToString(*param_it).c_str(), test_info->code_location,
+ GetTestSuiteTypeId(),
+ SuiteApiResolver<TestSuite>::GetSetUpCaseOrSuite(file, line),
+ SuiteApiResolver<TestSuite>::GetTearDownCaseOrSuite(file, line),
+ test_info->test_meta_factory->CreateTestFactory(*param_it));
+ } // for param_it
+ } // for gen_it
+ } // for test_it
+
+ if (!generated_instantiations) {
+ // There are no generaotrs, or they all generate nothing ...
+ InsertSyntheticTestCase(GetTestSuiteName(), code_location_,
+ !tests_.empty());
+ }
+ } // RegisterTests
+
+ private:
+ // LocalTestInfo structure keeps information about a single test registered
+ // with TEST_P macro.
+ struct TestInfo {
+ TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name,
+ TestMetaFactoryBase<ParamType>* a_test_meta_factory,
+ CodeLocation a_code_location)
+ : test_suite_base_name(a_test_suite_base_name),
+ test_base_name(a_test_base_name),
+ test_meta_factory(a_test_meta_factory),
+ code_location(a_code_location) {}
+
+ const std::string test_suite_base_name;
+ const std::string test_base_name;
+ const std::unique_ptr<TestMetaFactoryBase<ParamType>> test_meta_factory;
+ const CodeLocation code_location;
+ };
+ using TestInfoContainer = ::std::vector<std::shared_ptr<TestInfo>>;
+ // Records data received from INSTANTIATE_TEST_SUITE_P macros:
+ // <Instantiation name, Sequence generator creation function,
+ // Name generator function, Source file, Source line>
+ struct InstantiationInfo {
+ InstantiationInfo(const std::string& name_in,
+ GeneratorCreationFunc* generator_in,
+ ParamNameGeneratorFunc* name_func_in, const char* file_in,
+ int line_in)
+ : name(name_in),
+ generator(generator_in),
+ name_func(name_func_in),
+ file(file_in),
+ line(line_in) {}
+
+ std::string name;
+ GeneratorCreationFunc* generator;
+ ParamNameGeneratorFunc* name_func;
+ const char* file;
+ int line;
+ };
+ typedef ::std::vector<InstantiationInfo> InstantiationContainer;
+
+ static bool IsValidParamName(const std::string& name) {
+ // Check for empty string
+ if (name.empty()) return false;
+
+ // Check for invalid characters
+ for (std::string::size_type index = 0; index < name.size(); ++index) {
+ if (!IsAlNum(name[index]) && name[index] != '_') return false;
+ }
+
+ return true;
+ }
+
+ const std::string test_suite_name_;
+ CodeLocation code_location_;
+ TestInfoContainer tests_;
+ InstantiationContainer instantiations_;
+
+ ParameterizedTestSuiteInfo(const ParameterizedTestSuiteInfo&) = delete;
+ ParameterizedTestSuiteInfo& operator=(const ParameterizedTestSuiteInfo&) =
+ delete;
+}; // class ParameterizedTestSuiteInfo
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+template <class TestCase>
+using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo<TestCase>;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestSuiteRegistry contains a map of
+// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P
+// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding
+// ParameterizedTestSuiteInfo descriptors.
+class ParameterizedTestSuiteRegistry {
+ public:
+ ParameterizedTestSuiteRegistry() {}
+ ~ParameterizedTestSuiteRegistry() {
+ for (auto& test_suite_info : test_suite_infos_) {
+ delete test_suite_info;
+ }
+ }
+
+ // Looks up or creates and returns a structure containing information about
+ // tests and instantiations of a particular test suite.
+ template <class TestSuite>
+ ParameterizedTestSuiteInfo<TestSuite>* GetTestSuitePatternHolder(
+ const char* test_suite_name, CodeLocation code_location) {
+ ParameterizedTestSuiteInfo<TestSuite>* typed_test_info = nullptr;
+ for (auto& test_suite_info : test_suite_infos_) {
+ if (test_suite_info->GetTestSuiteName() == test_suite_name) {
+ if (test_suite_info->GetTestSuiteTypeId() != GetTypeId<TestSuite>()) {
+ // Complain about incorrect usage of Google Test facilities
+ // and terminate the program since we cannot guaranty correct
+ // test suite setup and tear-down in this case.
+ ReportInvalidTestSuiteType(test_suite_name, code_location);
+ 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<
+ ParameterizedTestSuiteInfo<TestSuite>>(test_suite_info);
+ }
+ break;
+ }
+ }
+ if (typed_test_info == nullptr) {
+ typed_test_info = new ParameterizedTestSuiteInfo<TestSuite>(
+ test_suite_name, code_location);
+ test_suite_infos_.push_back(typed_test_info);
+ }
+ return typed_test_info;
+ }
+ void RegisterTests() {
+ for (auto& test_suite_info : test_suite_infos_) {
+ test_suite_info->RegisterTests();
+ }
+ }
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ template <class TestCase>
+ ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+ const char* test_case_name, CodeLocation code_location) {
+ return GetTestSuitePatternHolder<TestCase>(test_case_name, code_location);
+ }
+
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ private:
+ using TestSuiteInfoContainer = ::std::vector<ParameterizedTestSuiteInfoBase*>;
+
+ TestSuiteInfoContainer test_suite_infos_;
+
+ ParameterizedTestSuiteRegistry(const ParameterizedTestSuiteRegistry&) =
+ delete;
+ ParameterizedTestSuiteRegistry& operator=(
+ const ParameterizedTestSuiteRegistry&) = delete;
+};
+
+// Keep track of what type-parameterized test suite are defined and
+// where as well as which are intatiated. This allows susequently
+// identifying suits that are defined but never used.
+class TypeParameterizedTestSuiteRegistry {
+ public:
+ // Add a suite definition
+ void RegisterTestSuite(const char* test_suite_name,
+ CodeLocation code_location);
+
+ // Add an instantiation of a suit.
+ void RegisterInstantiation(const char* test_suite_name);
+
+ // For each suit repored as defined but not reported as instantiation,
+ // emit a test that reports that fact (configurably, as an error).
+ void CheckForInstantiations();
+
+ private:
+ struct TypeParameterizedTestSuiteInfo {
+ explicit TypeParameterizedTestSuiteInfo(CodeLocation c)
+ : code_location(c), instantiated(false) {}
+
+ CodeLocation code_location;
+ bool instantiated;
+ };
+
+ std::map<std::string, TypeParameterizedTestSuiteInfo> suites_;
+};
+
+} // namespace internal
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container);
+
+namespace internal {
+// Used in the Values() function to provide polymorphic capabilities.
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4100)
+#endif
+
+template <typename... Ts>
+class ValueArray {
+ public:
+ explicit ValueArray(Ts... v) : v_(FlatTupleConstructTag{}, std::move(v)...) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { // NOLINT
+ return ValuesIn(MakeVector<T>(MakeIndexSequence<sizeof...(Ts)>()));
+ }
+
+ private:
+ template <typename T, size_t... I>
+ std::vector<T> MakeVector(IndexSequence<I...>) const {
+ return std::vector<T>{static_cast<T>(v_.template Get<I>())...};
+ }
+
+ FlatTuple<Ts...> v_;
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+template <typename... T>
+class CartesianProductGenerator
+ : public ParamGeneratorInterface<::std::tuple<T...>> {
+ public:
+ typedef ::std::tuple<T...> ParamType;
+
+ CartesianProductGenerator(const std::tuple<ParamGenerator<T>...>& g)
+ : generators_(g) {}
+ ~CartesianProductGenerator() override {}
+
+ ParamIteratorInterface<ParamType>* Begin() const override {
+ return new Iterator(this, generators_, false);
+ }
+ ParamIteratorInterface<ParamType>* End() const override {
+ return new Iterator(this, generators_, true);
+ }
+
+ private:
+ template <class I>
+ class IteratorImpl;
+ template <size_t... I>
+ class IteratorImpl<IndexSequence<I...>>
+ : public ParamIteratorInterface<ParamType> {
+ public:
+ IteratorImpl(const ParamGeneratorInterface<ParamType>* base,
+ const std::tuple<ParamGenerator<T>...>& generators,
+ bool is_end)
+ : base_(base),
+ begin_(std::get<I>(generators).begin()...),
+ end_(std::get<I>(generators).end()...),
+ current_(is_end ? end_ : begin_) {
+ ComputeCurrentValue();
+ }
+ ~IteratorImpl() override {}
+
+ const ParamGeneratorInterface<ParamType>* BaseGenerator() const override {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ void Advance() override {
+ assert(!AtEnd());
+ // Advance the last iterator.
+ ++std::get<sizeof...(T) - 1>(current_);
+ // if that reaches end, propagate that up.
+ AdvanceIfEnd<sizeof...(T) - 1>();
+ ComputeCurrentValue();
+ }
+ ParamIteratorInterface<ParamType>* Clone() const override {
+ return new IteratorImpl(*this);
+ }
+
+ const ParamType* Current() const override { return current_value_.get(); }
+
+ bool Equals(const ParamIteratorInterface<ParamType>& other) const override {
+ // 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 IteratorImpl* typed_other =
+ CheckedDowncastToActualType<const IteratorImpl>(&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().
+ if (AtEnd() && typed_other->AtEnd()) return true;
+
+ bool same = true;
+ bool dummy[] = {
+ (same = same && std::get<I>(current_) ==
+ std::get<I>(typed_other->current_))...};
+ (void)dummy;
+ return same;
+ }
+
+ private:
+ template <size_t ThisI>
+ void AdvanceIfEnd() {
+ if (std::get<ThisI>(current_) != std::get<ThisI>(end_)) return;
+
+ bool last = ThisI == 0;
+ if (last) {
+ // We are done. Nothing else to propagate.
+ return;
+ }
+
+ constexpr size_t NextI = ThisI - (ThisI != 0);
+ std::get<ThisI>(current_) = std::get<ThisI>(begin_);
+ ++std::get<NextI>(current_);
+ AdvanceIfEnd<NextI>();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = std::make_shared<ParamType>(*std::get<I>(current_)...);
+ }
+ bool AtEnd() const {
+ bool at_end = false;
+ bool dummy[] = {
+ (at_end = at_end || std::get<I>(current_) == std::get<I>(end_))...};
+ (void)dummy;
+ return at_end;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ std::tuple<typename ParamGenerator<T>::iterator...> begin_;
+ std::tuple<typename ParamGenerator<T>::iterator...> end_;
+ std::tuple<typename ParamGenerator<T>::iterator...> current_;
+ std::shared_ptr<ParamType> current_value_;
+ };
+
+ using Iterator = IteratorImpl<typename MakeIndexSequence<sizeof...(T)>::type>;
+
+ std::tuple<ParamGenerator<T>...> generators_;
+};
+
+template <class... Gen>
+class CartesianProductHolder {
+ public:
+ CartesianProductHolder(const Gen&... g) : generators_(g...) {}
+ template <typename... T>
+ operator ParamGenerator<::std::tuple<T...>>() const {
+ return ParamGenerator<::std::tuple<T...>>(
+ new CartesianProductGenerator<T...>(generators_));
+ }
+
+ private:
+ std::tuple<Gen...> generators_;
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-port-arch.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-port-arch.h
new file mode 100644
index 0000000..f025db7
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-port-arch.h
@@ -0,0 +1,116 @@
+// Copyright 2015, 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file defines the GTEST_OS_* macro.
+// It is separate from gtest-port.h so that custom/gtest-port.h can include it.
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+#define GTEST_OS_CYGWIN 1
+#elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
+#define GTEST_OS_WINDOWS_MINGW 1
+#define GTEST_OS_WINDOWS 1
+#elif defined _WIN32
+#define GTEST_OS_WINDOWS 1
+#ifdef _WIN32_WCE
+#define GTEST_OS_WINDOWS_MOBILE 1
+#elif defined(WINAPI_FAMILY)
+#include <winapifamily.h>
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#define GTEST_OS_WINDOWS_DESKTOP 1
+#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+#define GTEST_OS_WINDOWS_PHONE 1
+#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+#define GTEST_OS_WINDOWS_RT 1
+#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)
+#define GTEST_OS_WINDOWS_PHONE 1
+#define GTEST_OS_WINDOWS_TV_TITLE 1
+#else
+// WINAPI_FAMILY defined but no known partition matched.
+// Default to desktop.
+#define GTEST_OS_WINDOWS_DESKTOP 1
+#endif
+#else
+#define GTEST_OS_WINDOWS_DESKTOP 1
+#endif // _WIN32_WCE
+#elif defined __OS2__
+#define GTEST_OS_OS2 1
+#elif defined __APPLE__
+#define GTEST_OS_MAC 1
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE
+#define GTEST_OS_IOS 1
+#endif
+#elif defined __DragonFly__
+#define GTEST_OS_DRAGONFLY 1
+#elif defined __FreeBSD__
+#define GTEST_OS_FREEBSD 1
+#elif defined __Fuchsia__
+#define GTEST_OS_FUCHSIA 1
+#elif defined(__GNU__)
+#define GTEST_OS_GNU_HURD 1
+#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__)
+#define GTEST_OS_GNU_KFREEBSD 1
+#elif defined __linux__
+#define GTEST_OS_LINUX 1
+#if defined __ANDROID__
+#define GTEST_OS_LINUX_ANDROID 1
+#endif
+#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
+#elif defined __NetBSD__
+#define GTEST_OS_NETBSD 1
+#elif defined __OpenBSD__
+#define GTEST_OS_OPENBSD 1
+#elif defined __QNX__
+#define GTEST_OS_QNX 1
+#elif defined(__HAIKU__)
+#define GTEST_OS_HAIKU 1
+#elif defined ESP8266
+#define GTEST_OS_ESP8266 1
+#elif defined ESP32
+#define GTEST_OS_ESP32 1
+#elif defined(__XTENSA__)
+#define GTEST_OS_XTENSA 1
+#endif // __CYGWIN__
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-port.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-port.h
new file mode 100644
index 0000000..0003d27
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-port.h
@@ -0,0 +1,2413 @@
+// 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.
+
+// Low-level types and utilities for porting Google Test to various
+// platforms. All macros ending with _ and symbols defined in an
+// internal namespace are subject to change without notice. Code
+// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't
+// end with _ are part of Google Test's public API and can be used by
+// code outside Google Test.
+//
+// This file is fundamental to Google Test. All other Google Test source
+// files are expected to #include this. Therefore, it cannot #include
+// any other Google Test header.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// Environment-describing macros
+// -----------------------------
+//
+// Google Test can be used in many different environments. Macros in
+// this section tell Google Test what kind of environment it is being
+// used in, such that Google Test can provide environment-specific
+// features and implementations.
+//
+// Google Test tries to automatically detect the properties of its
+// environment, so users usually don't need to worry about these
+// macros. However, the automatic detection is not perfect.
+// Sometimes it's necessary for a user to define some of the following
+// macros in the build script to override Google Test's decisions.
+//
+// If the user doesn't define a macro in the list, Google Test will
+// provide a default definition. After this header is #included, all
+// macros in this list will be defined to either 1 or 0.
+//
+// Notes to maintainers:
+// - Each macro here is a user-tweakable knob; do not grow the list
+// lightly.
+// - Use #if to key off these macros. Don't use #ifdef or "#if
+// defined(...)", which will not work as these macros are ALWAYS
+// defined.
+//
+// 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_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 <pthread.h>
+// 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_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_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.
+// GTEST_DEFAULT_DEATH_TEST_STYLE
+// - The default value of --gtest_death_test_style.
+// The legacy default has been "fast" in the open
+// source version since 2008. The recommended value
+// is "threadsafe", and can be set in
+// custom/gtest-port.h.
+
+// Platform-indicating macros
+// --------------------------
+//
+// Macros indicating the platform on which Google Test is being used
+// (a macro is defined to 1 if compiled on the given platform;
+// otherwise UNDEFINED -- it's never defined to 0.). Google Test
+// defines these macros automatically. Code outside Google Test MUST
+// NOT define them.
+//
+// GTEST_OS_AIX - IBM AIX
+// GTEST_OS_CYGWIN - Cygwin
+// GTEST_OS_DRAGONFLY - DragonFlyBSD
+// GTEST_OS_FREEBSD - FreeBSD
+// GTEST_OS_FUCHSIA - Fuchsia
+// GTEST_OS_GNU_HURD - GNU/Hurd
+// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD
+// GTEST_OS_HAIKU - Haiku
+// GTEST_OS_HPUX - HP-UX
+// GTEST_OS_LINUX - Linux
+// GTEST_OS_LINUX_ANDROID - Google Android
+// GTEST_OS_MAC - Mac OS X
+// GTEST_OS_IOS - iOS
+// GTEST_OS_NACL - Google Native Client (NaCl)
+// GTEST_OS_NETBSD - NetBSD
+// GTEST_OS_OPENBSD - OpenBSD
+// GTEST_OS_OS2 - OS/2
+// GTEST_OS_QNX - QNX
+// GTEST_OS_SOLARIS - Sun Solaris
+// 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_WINDOWS_PHONE - Windows Phone
+// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT
+// GTEST_OS_ZOS - z/OS
+//
+// Among the platforms, Cygwin, Linux, Mac 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!).
+//
+// It is possible that none of the GTEST_OS_* macros are defined.
+
+// Feature-indicating macros
+// -------------------------
+//
+// Macros indicating which Google Test features are available (a macro
+// is defined to 1 if the corresponding feature is supported;
+// otherwise UNDEFINED -- it's never defined to 0.). Google Test
+// defines these macros automatically. Code outside Google Test MUST
+// NOT define them.
+//
+// These macros are public so that portable tests can be written.
+// Such tests typically surround code using a feature with an #if
+// which controls that code. For example:
+//
+// #if GTEST_HAS_DEATH_TEST
+// EXPECT_DEATH(DoSomethingDeadly());
+// #endif
+//
+// GTEST_HAS_DEATH_TEST - death tests
+// GTEST_HAS_TYPED_TEST - typed tests
+// GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+// GTEST_IS_THREADSAFE - Google Test is thread-safe.
+// GTEST_USES_RE2 - the RE2 regular expression library is used
+// 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 RE\b(s) are mutually exclusive.
+
+// Misc public macros
+// ------------------
+//
+// GTEST_FLAG(flag_name) - references the variable corresponding to
+// the given Google Test flag.
+
+// Internal utilities
+// ------------------
+//
+// The following macros and utilities are for Google Test's INTERNAL
+// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY.
+//
+// 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_MUST_USE_RESULT_ - declares that a function's result must be used.
+// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is
+// suppressed (constant conditional).
+// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127
+// is suppressed.
+// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter<std::any> or
+// UniversalPrinter<absl::any> specializations.
+// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter<std::optional>
+// or
+// UniversalPrinter<absl::optional>
+// specializations.
+// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or
+// Matcher<absl::string_view>
+// specializations.
+// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter<std::variant> or
+// UniversalPrinter<absl::variant>
+// specializations.
+//
+// Synchronization:
+// Mutex, MutexLock, ThreadLocal, GetThreadCount()
+// - synchronization primitives.
+//
+// Regular expressions:
+// RE - a simple regular expression class using
+// 1) the RE2 syntax on all platforms when built with RE2
+// and Abseil as dependencies
+// 2) the POSIX Extended Regular Expression syntax on
+// UNIX-like platforms,
+// 3) 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.
+// TimeInMillis - integers of known sizes.
+// BiggestInt - the biggest signed integer type.
+//
+// Command-line utilities:
+// GetInjectableArgvs() - 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_t environment variable.
+// StringFromGTestEnv() - parses a string environment variable.
+//
+// Deprecation warnings:
+// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as
+// deprecated; calling a marked function
+// should generate a compiler warning
+
+#include <ctype.h> // for isspace, etc
+#include <stddef.h> // for ptrdiff_t
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cerrno>
+// #include <condition_variable> // Guarded by GTEST_IS_THREADSAFE below
+#include <cstdint>
+#include <iostream>
+#include <limits>
+#include <locale>
+#include <memory>
+#include <string>
+// #include <mutex> // Guarded by GTEST_IS_THREADSAFE below
+#include <tuple>
+#include <type_traits>
+#include <vector>
+
+#ifndef _WIN32_WCE
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif // !_WIN32_WCE
+
+#if defined __APPLE__
+#include <AvailabilityMacros.h>
+#include <TargetConditionals.h>
+#endif
+
+#include "gtest/internal/custom/gtest-port.h"
+#include "gtest/internal/gtest-port-arch.h"
+
+#if GTEST_HAS_ABSL
+#include "absl/flags/declare.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/reflection.h"
+#endif
+
+#if !defined(GTEST_DEV_EMAIL_)
+#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_ "https://github.com/google/googletest/"
+#endif // !defined(GTEST_DEV_EMAIL_)
+
+#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_)
+#define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest"
+#endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_)
+
+// 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__
+
+// Macros for disabling Microsoft Visual C++ warnings.
+//
+// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385)
+// /* code that triggers warnings C4800 and C4385 */
+// GTEST_DISABLE_MSC_WARNINGS_POP_()
+#if defined(_MSC_VER)
+#define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \
+ __pragma(warning(push)) __pragma(warning(disable : warnings))
+#define GTEST_DISABLE_MSC_WARNINGS_POP_() __pragma(warning(pop))
+#else
+// Not all compilers are MSVC
+#define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings)
+#define GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
+
+// Clang on Windows does not understand MSVC's pragma warning.
+// We need clang-specific way to disable function deprecation warning.
+#ifdef __clang__
+#define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \
+ _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"")
+#define GTEST_DISABLE_MSC_DEPRECATED_POP_() _Pragma("clang diagnostic pop")
+#else
+#define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
+#define GTEST_DISABLE_MSC_DEPRECATED_POP_() GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
+
+// 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
+#if !GTEST_OS_WINDOWS_MOBILE
+#include <direct.h>
+#include <io.h>
+#endif
+// In order to avoid having to include <windows.h>, use forward declaration
+#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR)
+// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two
+// separate (equivalent) structs, instead of using typedef
+typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION;
+#else
+// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION.
+// This assumption is verified by
+// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION.
+typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
+#endif
+#elif GTEST_OS_XTENSA
+#include <unistd.h>
+// Xtensa toolchains define strcasecmp in the string.h header instead of
+// strings.h. string.h is already included.
+#else
+// 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 <strings.h>
+#include <unistd.h>
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_OS_LINUX_ANDROID
+// Used to define __ANDROID_API__ matching the target NDK API level.
+#include <android/api-level.h> // NOLINT
+#endif
+
+// Defines this to true if and only if Google Test can use POSIX regular
+// expressions.
+#ifndef GTEST_HAS_POSIX_RE
+#if GTEST_OS_LINUX_ANDROID
+// On Android, <regex.h> is only available starting with Gingerbread.
+#define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
+#else
+#define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS && !GTEST_OS_XTENSA)
+#endif
+#endif
+
+// Select the regular expression implementation.
+#if GTEST_HAS_ABSL
+// When using Abseil, RE2 is required.
+#include "absl/strings/string_view.h"
+#include "re2/re2.h"
+#define GTEST_USES_RE2 1
+#elif GTEST_HAS_POSIX_RE
+#include <regex.h> // NOLINT
+#define GTEST_USES_POSIX_RE 1
+#else
+// Use our own simple regex implementation.
+#define GTEST_USES_SIMPLE_RE 1
+#endif
+
+#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(_CPPUNWIND)
+// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled.
+#define GTEST_HAS_EXCEPTIONS 1
+#elif defined(__BORLANDC__)
+// C++Builder's implementation of the STL uses 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(__clang__)
+// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang
+// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files,
+// there can be cleanups for ObjC exceptions which also need cleanups, even if
+// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which
+// checks for C++ exceptions starting at clang r206352, but which checked for
+// cleanups prior to that. To reliably check for C++ exception availability with
+// clang, check for
+// __EXCEPTIONS && __has_feature(cxx_exceptions).
+#define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions))
+#elif defined(__GNUC__) && __EXCEPTIONS
+// gcc defines __EXCEPTIONS to 1 if and only if 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 if and only if 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
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// 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 || \
+ GTEST_OS_HAIKU || GTEST_OS_ESP32 || GTEST_OS_ESP8266 || GTEST_OS_XTENSA))
+
+#endif // GTEST_HAS_STD_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 if and only if 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 if and only if RTTI is
+// enabled.
+#elif defined(__GNUC__)
+
+#ifdef __GXX_RTTI
+// When building against STLport with the Android NDK and with
+// -frtti -fno-exceptions, the build fails at link time with undefined
+// references to __cxa_bad_typeid. Note sure if STL or toolchain bug,
+// so disable RTTI when detected.
+#if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && !defined(__EXCEPTIONS)
+#define GTEST_HAS_RTTI 0
+#else
+#define GTEST_HAS_RTTI 1
+#endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS
+#else
+#define GTEST_HAS_RTTI 0
+#endif // __GXX_RTTI
+
+// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends
+// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the
+// first version with C++ support.
+#elif defined(__clang__)
+
+#define GTEST_HAS_RTTI __has_feature(cxx_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 <typeinfo> when RTTI
+// is enabled.
+#if GTEST_HAS_RTTI
+#include <typeinfo>
+#endif
+
+// Determines whether Google Test can use the pthreads library.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us explicitly, so we make reasonable assumptions about
+// which platforms have pthreads support.
+//
+// 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 || GTEST_OS_QNX || \
+ GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \
+ GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \
+ GTEST_OS_HAIKU || GTEST_OS_GNU_HURD)
+#endif // GTEST_HAS_PTHREAD
+
+#if GTEST_HAS_PTHREAD
+// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
+// true.
+#include <pthread.h> // NOLINT
+
+// For timespec and nanosleep, used below.
+#include <time.h> // NOLINT
+#endif
+
+// 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__)
+#if GTEST_OS_LINUX_ANDROID
+// On Android, clone() became available at different API levels for each 32-bit
+// architecture.
+#if defined(__LP64__) || (defined(__arm__) && __ANDROID_API__ >= 9) || \
+ (defined(__mips__) && __ANDROID_API__ >= 12) || \
+ (defined(__i386__) && __ANDROID_API__ >= 17)
+#define GTEST_HAS_CLONE 1
+#else
+#define GTEST_HAS_CLONE 0
+#endif
+#else
+#define GTEST_HAS_CLONE 1
+#endif
+#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_WINDOWS_PHONE || \
+ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_XTENSA
+#define GTEST_HAS_STREAM_REDIRECTION 0
+#else
+#define GTEST_HAS_STREAM_REDIRECTION 1
+#endif // !GTEST_OS_WINDOWS_MOBILE
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+// Determines whether to support death tests.
+// pops up a dialog window that cannot be suppressed programmatically.
+#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+ (GTEST_OS_MAC && !GTEST_OS_IOS) || \
+ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \
+ GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \
+ GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \
+ GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU || \
+ GTEST_OS_GNU_HURD)
+#define GTEST_HAS_DEATH_TEST 1
+#endif
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
+// Sun Pro CC, IBM Visual Age, and HP aCC support.
+#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \
+ defined(__IBMCPP__) || defined(__HP_aCC)
+#define GTEST_HAS_TYPED_TEST 1
+#define GTEST_HAS_TYPED_TEST_P 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_AIX || GTEST_OS_OS2)
+
+// Determines whether test results can be streamed to a socket.
+#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \
+ GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD || \
+ GTEST_OS_GNU_HURD
+#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))
+#elif defined(__clang__)
+#if __has_attribute(unused)
+#define GTEST_ATTRIBUTE_UNUSED_ __attribute__((unused))
+#endif
+#endif
+#ifndef GTEST_ATTRIBUTE_UNUSED_
+#define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// Use this annotation before a function that takes a printf format string.
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC)
+#if defined(__MINGW_PRINTF_FORMAT)
+// MinGW has two different printf implementations. Ensure the format macro
+// matches the selected implementation. See
+// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/.
+#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
+ __attribute__(( \
+ __format__(__MINGW_PRINTF_FORMAT, string_index, first_to_check)))
+#else
+#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
+ __attribute__((__format__(__printf__, string_index, first_to_check)))
+#endif
+#else
+#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check)
+#endif
+
+// 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__) && !defined(COMPILER_ICC)
+#define GTEST_MUST_USE_RESULT_ __attribute__((warn_unused_result))
+#else
+#define GTEST_MUST_USE_RESULT_
+#endif // __GNUC__ && !COMPILER_ICC
+
+// MS C++ compiler emits warning when a conditional expression is compile time
+// constant. In some contexts this warning is false positive and needs to be
+// suppressed. Use the following two macros in such cases:
+//
+// GTEST_INTENTIONAL_CONST_COND_PUSH_()
+// while (true) {
+// GTEST_INTENTIONAL_CONST_COND_POP_()
+// }
+#define GTEST_INTENTIONAL_CONST_COND_PUSH_() \
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127)
+#define GTEST_INTENTIONAL_CONST_COND_POP_() GTEST_DISABLE_MSC_WARNINGS_POP_()
+
+// 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
+
+#ifndef GTEST_IS_THREADSAFE
+
+#define GTEST_IS_THREADSAFE \
+ (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \
+ (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \
+ GTEST_HAS_PTHREAD)
+
+#endif // GTEST_IS_THREADSAFE
+
+#if GTEST_IS_THREADSAFE
+// Some platforms don't support including these threading related headers.
+#include <condition_variable> // NOLINT
+#include <mutex> // NOLINT
+#endif // GTEST_IS_THREADSAFE
+
+// GTEST_API_ qualifies all symbols that must be exported. The definitions below
+// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in
+// gtest/internal/custom/gtest-port.h
+#ifndef GTEST_API_
+
+#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
+#elif __GNUC__ >= 4 || defined(__clang__)
+#define GTEST_API_ __attribute__((visibility("default")))
+#endif // _MSC_VER
+
+#endif // GTEST_API_
+
+#ifndef GTEST_API_
+#define GTEST_API_
+#endif // GTEST_API_
+
+#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE
+#define GTEST_DEFAULT_DEATH_TEST_STYLE "fast"
+#endif // GTEST_DEFAULT_DEATH_TEST_STYLE
+
+#ifdef __GNUC__
+// Ask the compiler to never inline a given function.
+#define GTEST_NO_INLINE_ __attribute__((noinline))
+#else
+#define GTEST_NO_INLINE_
+#endif
+
+#if defined(__clang__)
+// Nested ifs to avoid triggering MSVC warning.
+#if __has_attribute(disable_tail_calls)
+// Ask the compiler not to perform tail call optimization inside
+// the marked function.
+#define GTEST_NO_TAIL_CALL_ __attribute__((disable_tail_calls))
+#endif
+#elif __GNUC__
+#define GTEST_NO_TAIL_CALL_ \
+ __attribute__((optimize("no-optimize-sibling-calls")))
+#else
+#define GTEST_NO_TAIL_CALL_
+#endif
+
+// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project.
+#if !defined(GTEST_HAS_CXXABI_H_)
+#if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER))
+#define GTEST_HAS_CXXABI_H_ 1
+#else
+#define GTEST_HAS_CXXABI_H_ 0
+#endif
+#endif
+
+// A function level attribute to disable checking for use of uninitialized
+// memory when built with MemorySanitizer.
+#if defined(__clang__)
+#if __has_feature(memory_sanitizer)
+#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ __attribute__((no_sanitize_memory))
+#else
+#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+#endif // __has_feature(memory_sanitizer)
+#else
+#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+#endif // __clang__
+
+// A function level attribute to disable AddressSanitizer instrumentation.
+#if defined(__clang__)
+#if __has_feature(address_sanitizer)
+#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \
+ __attribute__((no_sanitize_address))
+#else
+#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+#endif // __has_feature(address_sanitizer)
+#else
+#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+#endif // __clang__
+
+// A function level attribute to disable HWAddressSanitizer instrumentation.
+#if defined(__clang__)
+#if __has_feature(hwaddress_sanitizer)
+#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \
+ __attribute__((no_sanitize("hwaddress")))
+#else
+#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+#endif // __has_feature(hwaddress_sanitizer)
+#else
+#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+#endif // __clang__
+
+// A function level attribute to disable ThreadSanitizer instrumentation.
+#if defined(__clang__)
+#if __has_feature(thread_sanitizer)
+#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ __attribute__((no_sanitize_thread))
+#else
+#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+#endif // __has_feature(thread_sanitizer)
+#else
+#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+#endif // __clang__
+
+namespace testing {
+
+class Message;
+
+// Legacy imports for backwards compatibility.
+// New code should use std:: names directly.
+using std::get;
+using std::make_tuple;
+using std::tuple;
+using std::tuple_element;
+using std::tuple_size;
+
+namespace internal {
+
+// 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;
+
+// A helper for suppressing warnings on constant condition. It just
+// returns 'condition'.
+GTEST_API_ bool IsTrue(bool condition);
+
+// Defines RE.
+
+#if GTEST_USES_RE2
+
+// This is almost `using RE = ::RE2`, except it is copy-constructible, and it
+// needs to disambiguate the `std::string`, `absl::string_view`, and `const
+// char*` constructors.
+class GTEST_API_ RE {
+ public:
+ RE(absl::string_view regex) : regex_(regex) {} // NOLINT
+ RE(const char* regex) : RE(absl::string_view(regex)) {} // NOLINT
+ RE(const std::string& regex) : RE(absl::string_view(regex)) {} // NOLINT
+ RE(const RE& other) : RE(other.pattern()) {}
+
+ const std::string& pattern() const { return regex_.pattern(); }
+
+ static bool FullMatch(absl::string_view str, const RE& re) {
+ return RE2::FullMatch(str, re.regex_);
+ }
+ static bool PartialMatch(absl::string_view str, const RE& re) {
+ return RE2::PartialMatch(str, re.regex_);
+ }
+
+ private:
+ RE2 regex_;
+};
+
+#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE
+
+// A simple C++ wrapper for <regex.h>. 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
+
+ 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 if and only if regular expression re
+ // matches the entire str.
+ // PartialMatch(str, re) returns true if and only if regular expression re
+ // matches a substring of str (including str itself).
+ 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);
+ }
+
+ static bool FullMatch(const char* str, const RE& re);
+ static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+ void Init(const char* regex);
+ 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
+};
+
+#endif // ::testing::internal::RE implementation
+
+// 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_;
+
+ GTestLog(const GTestLog&) = delete;
+ GTestLog& operator=(const GTestLog&) = delete;
+};
+
+#if !defined(GTEST_LOG_)
+
+#define GTEST_LOG_(severity) \
+ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
+ __FILE__, __LINE__) \
+ .GetStream()
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(nullptr); }
+
+#endif // !defined(GTEST_LOG_)
+
+#if !defined(GTEST_CHECK_)
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+// Synopsis:
+// 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. "
+#endif // !defined(GTEST_CHECK_)
+
+// 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
+
+// Transforms "T" into "const T&" according to standard reference collapsing
+// rules (this is only needed as a backport for C++98 compilers that do not
+// support reference collapsing). Specifically, it transforms:
+//
+// char ==> const char&
+// const char ==> const char&
+// char& ==> char&
+// const char& ==> const char&
+//
+// Note that the non-const reference will not have "const" added. This is
+// standard, and necessary so that "T" can always bind to "const T&".
+template <typename T>
+struct ConstRef {
+ typedef const T& type;
+};
+template <typename T>
+struct ConstRef<T&> {
+ typedef T& type;
+};
+
+// The argument T must depend on some template parameters.
+#define GTEST_REFERENCE_TO_CONST_(T) \
+ typename ::testing::internal::ConstRef<T>::type
+
+// 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 convertible to a target type.
+//
+// The syntax for using ImplicitCast_ is the same as for static_cast:
+//
+// ImplicitCast_<ToType>(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 <typename To>
+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<Subclass1>(foo)) HandleASubclass1Object(foo);
+// if (dynamic_cast<Subclass2>(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 <typename To, typename From> // use like this: DownCast_<T*>(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.
+ GTEST_INTENTIONAL_CONST_COND_PUSH_()
+ if (false) {
+ GTEST_INTENTIONAL_CONST_COND_POP_()
+ const To to = nullptr;
+ ::testing::internal::ImplicitCast_<From*>(to);
+ }
+
+#if GTEST_HAS_RTTI
+ // RTTI: debug mode only!
+ GTEST_CHECK_(f == nullptr || dynamic_cast<To>(f) != nullptr);
+#endif
+ return static_cast<To>(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 <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base) {
+#if GTEST_HAS_RTTI
+ GTEST_CHECK_(typeid(*base) == typeid(Derived));
+#endif
+
+#if GTEST_HAS_DOWNCAST_
+ return ::down_cast<Derived*>(base);
+#elif GTEST_HAS_RTTI
+ return dynamic_cast<Derived*>(base); // NOLINT
+#else
+ return static_cast<Derived*>(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_ std::string GetCapturedStdout();
+GTEST_API_ void CaptureStderr();
+GTEST_API_ std::string GetCapturedStderr();
+
+#endif // GTEST_HAS_STREAM_REDIRECTION
+// Returns the size (in bytes) of a file.
+GTEST_API_ size_t GetFileSize(FILE* file);
+
+// Reads the entire content of a file as a string.
+GTEST_API_ std::string ReadEntireFile(FILE* file);
+
+// All command line arguments.
+GTEST_API_ std::vector<std::string> GetArgvs();
+
+#if GTEST_HAS_DEATH_TEST
+
+std::vector<std::string> GetInjectableArgvs();
+// Deprecated: pass the args vector by value instead.
+void SetInjectableArgvs(const std::vector<std::string>* new_argvs);
+void SetInjectableArgvs(const std::vector<std::string>& new_argvs);
+void ClearInjectableArgvs();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+#if GTEST_IS_THREADSAFE
+
+#if GTEST_OS_WINDOWS
+// Provides leak-safe Windows kernel handle ownership.
+// Used in death tests and in threading support.
+class GTEST_API_ AutoHandle {
+ public:
+ // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to
+ // avoid including <windows.h> in this header file. Including <windows.h> is
+ // undesirable because it defines a lot of symbols and macros that tend to
+ // conflict with client code. This assumption is verified by
+ // WindowsTypesTest.HANDLEIsVoidStar.
+ typedef void* Handle;
+ AutoHandle();
+ explicit AutoHandle(Handle handle);
+
+ ~AutoHandle();
+
+ Handle Get() const;
+ void Reset();
+ void Reset(Handle handle);
+
+ private:
+ // Returns true if and only if the handle is a valid handle object that can be
+ // closed.
+ bool IsCloseable() const;
+
+ Handle handle_;
+
+ AutoHandle(const AutoHandle&) = delete;
+ AutoHandle& operator=(const AutoHandle&) = delete;
+};
+#endif
+
+#if GTEST_HAS_NOTIFICATION_
+// Notification has already been imported into the namespace.
+// Nothing to do here.
+
+#else
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// 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.
+// TODO(b/203539622): Replace unconditionally with absl::Notification.
+class GTEST_API_ Notification {
+ public:
+ Notification() : notified_(false) {}
+ Notification(const Notification&) = delete;
+ Notification& operator=(const Notification&) = delete;
+
+ // Notifies all threads created with this notification to start. Must
+ // be called from the controller thread.
+ void Notify() {
+ std::lock_guard<std::mutex> lock(mu_);
+ notified_ = true;
+ cv_.notify_all();
+ }
+
+ // Blocks until the controller thread notifies. Must be called from a test
+ // thread.
+ void WaitForNotification() {
+ std::unique_lock<std::mutex> lock(mu_);
+ cv_.wait(lock, [this]() { return notified_; });
+ }
+
+ private:
+ std::mutex mu_;
+ std::condition_variable cv_;
+ bool notified_;
+};
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+#endif // GTEST_HAS_NOTIFICATION_
+
+// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD
+// defined, but we don't want to use MinGW's pthreads implementation, which
+// has conformance problems with some versions of the POSIX standard.
+#if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW
+
+// 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<ThreadWithParamBase*>(thread)->Run();
+ return nullptr;
+}
+
+// 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<int> 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 <typename T>
+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_, nullptr, &ThreadFuncWithCLinkage, base));
+ }
+ ~ThreadWithParam() override { Join(); }
+
+ void Join() {
+ if (!finished_) {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr));
+ finished_ = true;
+ }
+ }
+
+ void Run() override {
+ if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification();
+ func_(param_);
+ }
+
+ private:
+ UserThreadFunc* const 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 if and only if we know that the thread function has
+ // finished.
+ pthread_t thread_; // The native thread object.
+
+ ThreadWithParam(const ThreadWithParam&) = delete;
+ ThreadWithParam& operator=(const ThreadWithParam&) = delete;
+};
+#endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD ||
+ // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+
+#if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+// Mutex and ThreadLocal have already been imported into the namespace.
+// Nothing to do here.
+
+#elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+
+// Mutex implements mutex on Windows platforms. It is used in conjunction
+// with class MutexLock:
+//
+// Mutex mutex;
+// ...
+// MutexLock lock(&mutex); // Acquires the mutex and releases it at the
+// // end of the current scope.
+//
+// A static Mutex *must* be defined or declared using one of the following
+// macros:
+// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+//
+// (A non-static Mutex is defined/declared in the usual way).
+class GTEST_API_ Mutex {
+ public:
+ enum MutexType { kStatic = 0, kDynamic = 1 };
+ // We rely on kStaticMutex being 0 as it is to what the linker initializes
+ // type_ in static mutexes. critical_section_ will be initialized lazily
+ // in ThreadSafeLazyInit().
+ enum StaticConstructorSelector { kStaticMutex = 0 };
+
+ // This constructor intentionally does nothing. It relies on type_ being
+ // statically initialized to 0 (effectively setting it to kStatic) and on
+ // ThreadSafeLazyInit() to lazily initialize the rest of the members.
+ explicit Mutex(StaticConstructorSelector /*dummy*/) {}
+
+ Mutex();
+ ~Mutex();
+
+ void Lock();
+
+ void Unlock();
+
+ // Does nothing if the current thread holds the mutex. Otherwise, crashes
+ // with high probability.
+ void AssertHeld();
+
+ private:
+ // Initializes owner_thread_id_ and critical_section_ in static mutexes.
+ void ThreadSafeLazyInit();
+
+ // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503,
+ // we assume that 0 is an invalid value for thread IDs.
+ unsigned int owner_thread_id_;
+
+ // For static mutexes, we rely on these members being initialized to zeros
+ // by the linker.
+ MutexType type_;
+ long critical_section_init_phase_; // NOLINT
+ GTEST_CRITICAL_SECTION* critical_section_;
+
+ Mutex(const Mutex&) = delete;
+ Mutex& operator=(const Mutex&) = delete;
+};
+
+#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::Mutex mutex
+
+#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex)
+
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); }
+
+ ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+ Mutex* const mutex_;
+
+ GTestMutexLock(const GTestMutexLock&) = delete;
+ GTestMutexLock& operator=(const GTestMutexLock&) = delete;
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Base class for ValueHolder<T>. Allows a caller to hold and delete a value
+// without knowing its type.
+class ThreadLocalValueHolderBase {
+ public:
+ virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Provides a way for a thread to send notifications to a ThreadLocal
+// regardless of its parameter type.
+class ThreadLocalBase {
+ public:
+ // Creates a new ValueHolder<T> object holding a default value passed to
+ // this ThreadLocal<T>'s constructor and returns it. It is the caller's
+ // responsibility not to call this when the ThreadLocal<T> instance already
+ // has a value on the current thread.
+ virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0;
+
+ protected:
+ ThreadLocalBase() {}
+ virtual ~ThreadLocalBase() {}
+
+ private:
+ ThreadLocalBase(const ThreadLocalBase&) = delete;
+ ThreadLocalBase& operator=(const ThreadLocalBase&) = delete;
+};
+
+// Maps a thread to a set of ThreadLocals that have values instantiated on that
+// thread and notifies them when the thread exits. A ThreadLocal instance is
+// expected to persist until all threads it has values on have terminated.
+class GTEST_API_ ThreadLocalRegistry {
+ public:
+ // Registers thread_local_instance as having value on the current thread.
+ // Returns a value that can be used to identify the thread from other threads.
+ static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance);
+
+ // Invoked when a ThreadLocal instance is destroyed.
+ static void OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance);
+};
+
+class GTEST_API_ ThreadWithParamBase {
+ public:
+ void Join();
+
+ protected:
+ class Runnable {
+ public:
+ virtual ~Runnable() {}
+ virtual void Run() = 0;
+ };
+
+ ThreadWithParamBase(Runnable* runnable, Notification* thread_can_start);
+ virtual ~ThreadWithParamBase();
+
+ private:
+ AutoHandle thread_;
+};
+
+// Helper class for testing Google Test's multi-threading constructs.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+ typedef void UserThreadFunc(T);
+
+ ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
+ : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) {}
+ virtual ~ThreadWithParam() {}
+
+ private:
+ class RunnableImpl : public Runnable {
+ public:
+ RunnableImpl(UserThreadFunc* func, T param) : func_(func), param_(param) {}
+ virtual ~RunnableImpl() {}
+ virtual void Run() { func_(param_); }
+
+ private:
+ UserThreadFunc* const func_;
+ const T param_;
+
+ RunnableImpl(const RunnableImpl&) = delete;
+ RunnableImpl& operator=(const RunnableImpl&) = delete;
+ };
+
+ ThreadWithParam(const ThreadWithParam&) = delete;
+ ThreadWithParam& operator=(const ThreadWithParam&) = delete;
+};
+
+// Implements thread-local storage on Windows systems.
+//
+// // Thread 1
+// ThreadLocal<int> 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.
+//
+// The users of a TheadLocal instance have to make sure that all but one
+// threads (including the main one) using that instance have exited before
+// destroying it. Otherwise, the per-thread objects managed for them by the
+// ThreadLocal instance are not guaranteed to be destroyed on all platforms.
+//
+// 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 <typename T>
+class ThreadLocal : public ThreadLocalBase {
+ public:
+ ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {}
+ explicit ThreadLocal(const T& value)
+ : default_factory_(new InstanceValueHolderFactory(value)) {}
+
+ ~ThreadLocal() override { ThreadLocalRegistry::OnThreadLocalDestroyed(this); }
+
+ 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 T. Can be deleted via its base class without the caller
+ // knowing the type of T.
+ class ValueHolder : public ThreadLocalValueHolderBase {
+ public:
+ ValueHolder() : value_() {}
+ explicit ValueHolder(const T& value) : value_(value) {}
+
+ T* pointer() { return &value_; }
+
+ private:
+ T value_;
+ ValueHolder(const ValueHolder&) = delete;
+ ValueHolder& operator=(const ValueHolder&) = delete;
+ };
+
+ T* GetOrCreateValue() const {
+ return static_cast<ValueHolder*>(
+ ThreadLocalRegistry::GetValueOnCurrentThread(this))
+ ->pointer();
+ }
+
+ ThreadLocalValueHolderBase* NewValueForCurrentThread() const override {
+ return default_factory_->MakeNewHolder();
+ }
+
+ class ValueHolderFactory {
+ public:
+ ValueHolderFactory() {}
+ virtual ~ValueHolderFactory() {}
+ virtual ValueHolder* MakeNewHolder() const = 0;
+
+ private:
+ ValueHolderFactory(const ValueHolderFactory&) = delete;
+ ValueHolderFactory& operator=(const ValueHolderFactory&) = delete;
+ };
+
+ class DefaultValueHolderFactory : public ValueHolderFactory {
+ public:
+ DefaultValueHolderFactory() {}
+ ValueHolder* MakeNewHolder() const override { return new ValueHolder(); }
+
+ private:
+ DefaultValueHolderFactory(const DefaultValueHolderFactory&) = delete;
+ DefaultValueHolderFactory& operator=(const DefaultValueHolderFactory&) =
+ delete;
+ };
+
+ class InstanceValueHolderFactory : public ValueHolderFactory {
+ public:
+ explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
+ ValueHolder* MakeNewHolder() const override {
+ return new ValueHolder(value_);
+ }
+
+ private:
+ const T value_; // The value for each thread.
+
+ InstanceValueHolderFactory(const InstanceValueHolderFactory&) = delete;
+ InstanceValueHolderFactory& operator=(const InstanceValueHolderFactory&) =
+ delete;
+ };
+
+ std::unique_ptr<ValueHolderFactory> default_factory_;
+
+ ThreadLocal(const ThreadLocal&) = delete;
+ ThreadLocal& operator=(const ThreadLocal&) = delete;
+};
+
+#elif GTEST_HAS_PTHREAD
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms.
+class MutexBase {
+ public:
+ // Acquires this mutex.
+ void Lock() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
+ owner_ = pthread_self();
+ has_owner_ = true;
+ }
+
+ // Releases this mutex.
+ void Unlock() {
+ // Since the lock is being released the owner_ field should no longer be
+ // considered valid. We don't protect writing to has_owner_ here, as it's
+ // the caller's responsibility to ensure that the current thread holds the
+ // mutex when this is called.
+ has_owner_ = false;
+ 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_(has_owner_ && pthread_equal(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.
+ // has_owner_ indicates whether the owner_ field below contains a valid thread
+ // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All
+ // accesses to the owner_ field should be protected by a check of this field.
+ // An alternative might be to memset() owner_ to all zeros, but there's no
+ // guarantee that a zero'd pthread_t is necessarily invalid or even different
+ // from pthread_self().
+ bool has_owner_;
+ pthread_t owner_; // The thread holding the mutex.
+};
+
+// 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.
+// The initialization list here does not explicitly initialize each field,
+// instead relying on default initialization for the unspecified fields. In
+// particular, the owner_ field (a pthread_t) is not explicitly initialized.
+// This allows initialization to work whether pthread_t is a scalar or struct.
+// The flag -Wmissing-field-initializers must not be specified for this to work.
+#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 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_, nullptr));
+ has_owner_ = false;
+ }
+ ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); }
+
+ private:
+ Mutex(const Mutex&) = delete;
+ Mutex& operator=(const Mutex&) = delete;
+};
+
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->Lock(); }
+
+ ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+ MutexBase* const mutex_;
+
+ GTestMutexLock(const GTestMutexLock&) = delete;
+ GTestMutexLock& operator=(const GTestMutexLock&) = delete;
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Helpers for ThreadLocal.
+
+// pthread_key_create() requires DeleteThreadLocalValue() to have
+// C-linkage. Therefore it cannot be templatized to access
+// ThreadLocal<T>. 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<ThreadLocalValueHolderBase*>(value_holder);
+}
+
+// Implements thread-local storage on pthreads-based systems.
+template <typename T>
+class GTEST_API_ ThreadLocal {
+ public:
+ ThreadLocal()
+ : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {}
+ explicit ThreadLocal(const T& value)
+ : key_(CreateKey()),
+ default_factory_(new InstanceValueHolderFactory(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:
+ ValueHolder() : value_() {}
+ explicit ValueHolder(const T& value) : value_(value) {}
+
+ T* pointer() { return &value_; }
+
+ private:
+ T value_;
+ ValueHolder(const ValueHolder&) = delete;
+ ValueHolder& operator=(const ValueHolder&) = delete;
+ };
+
+ 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<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
+ if (holder != nullptr) {
+ return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
+ }
+
+ ValueHolder* const new_holder = default_factory_->MakeNewHolder();
+ ThreadLocalValueHolderBase* const holder_base = new_holder;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
+ return new_holder->pointer();
+ }
+
+ class ValueHolderFactory {
+ public:
+ ValueHolderFactory() {}
+ virtual ~ValueHolderFactory() {}
+ virtual ValueHolder* MakeNewHolder() const = 0;
+
+ private:
+ ValueHolderFactory(const ValueHolderFactory&) = delete;
+ ValueHolderFactory& operator=(const ValueHolderFactory&) = delete;
+ };
+
+ class DefaultValueHolderFactory : public ValueHolderFactory {
+ public:
+ DefaultValueHolderFactory() {}
+ ValueHolder* MakeNewHolder() const override { return new ValueHolder(); }
+
+ private:
+ DefaultValueHolderFactory(const DefaultValueHolderFactory&) = delete;
+ DefaultValueHolderFactory& operator=(const DefaultValueHolderFactory&) =
+ delete;
+ };
+
+ class InstanceValueHolderFactory : public ValueHolderFactory {
+ public:
+ explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
+ ValueHolder* MakeNewHolder() const override {
+ return new ValueHolder(value_);
+ }
+
+ private:
+ const T value_; // The value for each thread.
+
+ InstanceValueHolderFactory(const InstanceValueHolderFactory&) = delete;
+ InstanceValueHolderFactory& operator=(const InstanceValueHolderFactory&) =
+ delete;
+ };
+
+ // A key pthreads uses for looking up per-thread values.
+ const pthread_key_t key_;
+ std::unique_ptr<ValueHolderFactory> default_factory_;
+
+ ThreadLocal(const ThreadLocal&) = delete;
+ ThreadLocal& operator=(const ThreadLocal&) = delete;
+};
+
+#endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+
+#else // GTEST_IS_THREADSAFE
+
+// 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 Lock() {}
+ void Unlock() {}
+ void AssertHeld() const {}
+};
+
+#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::Mutex mutex
+
+#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
+
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex*) {} // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class GTEST_API_ 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_;
+};
+
+#endif // GTEST_IS_THREADSAFE
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+GTEST_API_ size_t GetThreadCount();
+
+#if GTEST_OS_WINDOWS
+#define GTEST_PATH_SEP_ "\\"
+#define GTEST_HAS_ALT_PATH_SEP_ 1
+#else
+#define GTEST_PATH_SEP_ "/"
+#define GTEST_HAS_ALT_PATH_SEP_ 0
+#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<unsigned char>(ch)) != 0;
+}
+inline bool IsAlNum(char ch) {
+ return isalnum(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsDigit(char ch) {
+ return isdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsLower(char ch) {
+ return islower(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsSpace(char ch) {
+ return isspace(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsUpper(char ch) {
+ return isupper(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(char ch) {
+ return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+#ifdef __cpp_char8_t
+inline bool IsXDigit(char8_t ch) {
+ return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+#endif
+inline bool IsXDigit(char16_t ch) {
+ const unsigned char low_byte = static_cast<unsigned char>(ch);
+ return ch == low_byte && isxdigit(low_byte) != 0;
+}
+inline bool IsXDigit(char32_t ch) {
+ const unsigned char low_byte = static_cast<unsigned char>(ch);
+ return ch == low_byte && isxdigit(low_byte) != 0;
+}
+inline bool IsXDigit(wchar_t ch) {
+ const unsigned char low_byte = static_cast<unsigned char>(ch);
+ return ch == low_byte && isxdigit(low_byte) != 0;
+}
+
+inline char ToLower(char ch) {
+ return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
+}
+inline char ToUpper(char ch) {
+ return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
+}
+
+inline std::string StripTrailingSpaces(std::string str) {
+ std::string::iterator it = str.end();
+ while (it != str.begin() && IsSpace(*--it)) it = str.erase(it);
+ return str;
+}
+
+// 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 DoIsATTY(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 || GTEST_OS_ZOS || GTEST_OS_IOS || \
+ GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM)
+inline int DoIsATTY(int /* fd */) { return 0; }
+#else
+inline int DoIsATTY(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<int>(_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
+
+#elif GTEST_OS_ESP8266
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int DoIsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) {
+ // stat function not implemented on ESP8266
+ return 0;
+}
+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); }
+
+#else
+
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int DoIsATTY(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
+
+inline int IsATTY(int fd) {
+ // DoIsATTY might change errno (for example ENOTTY in case you redirect stdout
+ // to a file on Linux), which is unexpected, so save the previous value, and
+ // restore it after the call.
+ int savedErrno = errno;
+ int isAttyValue = DoIsATTY(fd);
+ errno = savedErrno;
+
+ return isAttyValue;
+}
+
+// Functions deprecated by MSVC 8.0.
+
+GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
+
+// 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 && !GTEST_OS_WINDOWS_PHONE && \
+ !GTEST_OS_WINDOWS_RT && !GTEST_OS_ESP8266 && !GTEST_OS_XTENSA
+inline int ChDir(const char* dir) { return chdir(dir); }
+#endif
+inline FILE* FOpen(const char* path, const char* mode) {
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+ struct wchar_codecvt : public std::codecvt<wchar_t, char, std::mbstate_t> {};
+ std::wstring_convert<wchar_codecvt> converter;
+ std::wstring wide_path = converter.from_bytes(path);
+ std::wstring wide_mode = converter.from_bytes(mode);
+ return _wfopen(wide_path.c_str(), wide_mode.c_str());
+#else // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+ return fopen(path, mode);
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+}
+#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<int>(read(fd, buf, count));
+}
+inline int Write(int fd, const void* buf, unsigned int count) {
+ return static_cast<int>(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 || GTEST_OS_WINDOWS_PHONE || \
+ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_XTENSA
+ // We are on an embedded platform, which has no environment variables.
+ static_cast<void>(name); // To prevent 'unused argument' warning.
+ return nullptr;
+#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 != nullptr && env[0] != '\0') ? env : nullptr;
+#else
+ return getenv(name);
+#endif
+}
+
+GTEST_DISABLE_MSC_DEPRECATED_POP_()
+
+#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.
+[[noreturn]] void Abort();
+#else
+[[noreturn]] inline void Abort() { abort(); }
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+} // namespace posix
+
+// MSVC "deprecates" snprintf and issues warnings wherever it is used. In
+// order to avoid these warnings, we need to use _snprintf or _snprintf_s on
+// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate
+// function in order to achieve that. We use macro definition here because
+// snprintf is a variadic function.
+#if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE
+// MSVC 2005 and above support variadic macros.
+#define GTEST_SNPRINTF_(buffer, size, format, ...) \
+ _snprintf_s(buffer, size, size, format, __VA_ARGS__)
+#elif defined(_MSC_VER)
+// Windows CE does not define _snprintf_s
+#define GTEST_SNPRINTF_ _snprintf
+#else
+#define GTEST_SNPRINTF_ snprintf
+#endif
+
+// The biggest signed integer type the compiler supports.
+//
+// long long is guaranteed to be at least 64-bits in C++11.
+using BiggestInt = long long; // NOLINT
+
+// The maximum number a BiggestInt can represent.
+constexpr BiggestInt kMaxBiggestInt = (std::numeric_limits<BiggestInt>::max)();
+
+// 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 <size_t size>
+class TypeWithSize {
+ public:
+ // This prevents the user from using TypeWithSize<N> with incorrect
+ // values of N.
+ using UInt = void;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+ using Int = std::int32_t;
+ using UInt = std::uint32_t;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+ using Int = std::int64_t;
+ using UInt = std::uint64_t;
+};
+
+// Integer types of known sizes.
+using TimeInMillis = int64_t; // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// Macro for referencing flags.
+#if !defined(GTEST_FLAG)
+#define GTEST_FLAG_NAME_(name) gtest_##name
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+#endif // !defined(GTEST_FLAG)
+
+// Pick a command line flags implementation.
+#if GTEST_HAS_ABSL
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+ ABSL_FLAG(bool, GTEST_FLAG_NAME_(name), default_val, doc)
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+ ABSL_FLAG(int32_t, GTEST_FLAG_NAME_(name), default_val, doc)
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+ ABSL_FLAG(std::string, GTEST_FLAG_NAME_(name), default_val, doc)
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) \
+ ABSL_DECLARE_FLAG(bool, GTEST_FLAG_NAME_(name))
+#define GTEST_DECLARE_int32_(name) \
+ ABSL_DECLARE_FLAG(int32_t, GTEST_FLAG_NAME_(name))
+#define GTEST_DECLARE_string_(name) \
+ ABSL_DECLARE_FLAG(std::string, GTEST_FLAG_NAME_(name))
+
+#define GTEST_FLAG_SAVER_ ::absl::FlagSaver
+
+#define GTEST_FLAG_GET(name) ::absl::GetFlag(GTEST_FLAG(name))
+#define GTEST_FLAG_SET(name, value) \
+ (void)(::absl::SetFlag(&GTEST_FLAG(name), value))
+#define GTEST_USE_OWN_FLAGFILE_FLAG_ 0
+
+#else // GTEST_HAS_ABSL
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+ namespace testing { \
+ GTEST_API_ bool GTEST_FLAG(name) = (default_val); \
+ } \
+ static_assert(true, "no-op to require trailing semicolon")
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+ namespace testing { \
+ GTEST_API_ std::int32_t GTEST_FLAG(name) = (default_val); \
+ } \
+ static_assert(true, "no-op to require trailing semicolon")
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+ namespace testing { \
+ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val); \
+ } \
+ static_assert(true, "no-op to require trailing semicolon")
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) \
+ namespace testing { \
+ GTEST_API_ extern bool GTEST_FLAG(name); \
+ } \
+ static_assert(true, "no-op to require trailing semicolon")
+#define GTEST_DECLARE_int32_(name) \
+ namespace testing { \
+ GTEST_API_ extern std::int32_t GTEST_FLAG(name); \
+ } \
+ static_assert(true, "no-op to require trailing semicolon")
+#define GTEST_DECLARE_string_(name) \
+ namespace testing { \
+ GTEST_API_ extern ::std::string GTEST_FLAG(name); \
+ } \
+ static_assert(true, "no-op to require trailing semicolon")
+
+#define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver
+
+#define GTEST_FLAG_GET(name) ::testing::GTEST_FLAG(name)
+#define GTEST_FLAG_SET(name, value) (void)(::testing::GTEST_FLAG(name) = value)
+#define GTEST_USE_OWN_FLAGFILE_FLAG_ 1
+
+#endif // GTEST_HAS_ABSL
+
+// Thread annotations
+#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_)
+#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+#define GTEST_LOCK_EXCLUDED_(locks)
+#endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_)
+
+// 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.
+GTEST_API_ bool ParseInt32(const Message& src_text, const char* str,
+ int32_t* value);
+
+// Parses a bool/int32_t/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+GTEST_API_ int32_t Int32FromGTestEnv(const char* flag, int32_t default_val);
+std::string OutputFlagAlsoCheckEnvVar();
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+} // namespace internal
+} // namespace testing
+
+#if !defined(GTEST_INTERNAL_DEPRECATED)
+
+// Internal Macro to mark an API deprecated, for googletest usage only
+// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or
+// GTEST_INTERNAL_DEPRECATED(message) <return_type> myFunction(); Every usage of
+// a deprecated entity will trigger a warning when compiled with
+// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler).
+// For msvc /W3 option will need to be used
+// Note that for 'other' compilers this macro evaluates to nothing to prevent
+// compilations errors.
+#if defined(_MSC_VER)
+#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message))
+#elif defined(__GNUC__)
+#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message)))
+#else
+#define GTEST_INTERNAL_DEPRECATED(message)
+#endif
+
+#endif // !defined(GTEST_INTERNAL_DEPRECATED)
+
+#if GTEST_HAS_ABSL
+// Always use absl::any for UniversalPrinter<> specializations if googletest
+// is built with absl support.
+#define GTEST_INTERNAL_HAS_ANY 1
+#include "absl/types/any.h"
+namespace testing {
+namespace internal {
+using Any = ::absl::any;
+} // namespace internal
+} // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<any>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::any for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_ANY 1
+#include <any>
+namespace testing {
+namespace internal {
+using Any = ::std::any;
+} // namespace internal
+} // namespace testing
+// The case where absl is configured NOT to alias std::any is not
+// supported.
+#endif // __has_include(<any>) && __cplusplus >= 201703L
+#endif // __has_include
+#endif // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::optional for UniversalPrinter<> specializations if
+// googletest is built with absl support.
+#define GTEST_INTERNAL_HAS_OPTIONAL 1
+#include "absl/types/optional.h"
+namespace testing {
+namespace internal {
+template <typename T>
+using Optional = ::absl::optional<T>;
+inline ::absl::nullopt_t Nullopt() { return ::absl::nullopt; }
+} // namespace internal
+} // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<optional>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::optional for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_OPTIONAL 1
+#include <optional>
+namespace testing {
+namespace internal {
+template <typename T>
+using Optional = ::std::optional<T>;
+inline ::std::nullopt_t Nullopt() { return ::std::nullopt; }
+} // namespace internal
+} // namespace testing
+// The case where absl is configured NOT to alias std::optional is not
+// supported.
+#endif // __has_include(<optional>) && __cplusplus >= 201703L
+#endif // __has_include
+#endif // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::string_view for Matcher<> specializations if googletest
+// is built with absl support.
+#define GTEST_INTERNAL_HAS_STRING_VIEW 1
+#include "absl/strings/string_view.h"
+namespace testing {
+namespace internal {
+using StringView = ::absl::string_view;
+} // namespace internal
+} // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<string_view>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::string_view for Matcher<>
+// specializations.
+#define GTEST_INTERNAL_HAS_STRING_VIEW 1
+#include <string_view>
+namespace testing {
+namespace internal {
+using StringView = ::std::string_view;
+} // namespace internal
+} // namespace testing
+// The case where absl is configured NOT to alias std::string_view is not
+// supported.
+#endif // __has_include(<string_view>) && __cplusplus >= 201703L
+#endif // __has_include
+#endif // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::variant for UniversalPrinter<> specializations if googletest
+// is built with absl support.
+#define GTEST_INTERNAL_HAS_VARIANT 1
+#include "absl/types/variant.h"
+namespace testing {
+namespace internal {
+template <typename... T>
+using Variant = ::absl::variant<T...>;
+} // namespace internal
+} // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<variant>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::variant for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_VARIANT 1
+#include <variant>
+namespace testing {
+namespace internal {
+template <typename... T>
+using Variant = ::std::variant<T...>;
+} // namespace internal
+} // namespace testing
+// The case where absl is configured NOT to alias std::variant is not supported.
+#endif // __has_include(<variant>) && __cplusplus >= 201703L
+#endif // __has_include
+#endif // GTEST_HAS_ABSL
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-string.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-string.h
new file mode 100644
index 0000000..cca2e1f
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-string.h
@@ -0,0 +1,177 @@
+// 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.
+
+// The Google C++ Testing and Mocking 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 gtest-internal.h.
+// It should not be #included by other files.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#ifdef __BORLANDC__
+// string.h is not guaranteed to provide strcpy on C++ Builder.
+#include <mem.h>
+#endif
+
+#include <string.h>
+
+#include <cstdint>
+#include <string>
+
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+namespace internal {
+
+// String - an abstract class holding static string utilities.
+class GTEST_API_ String {
+ public:
+ // Static utility methods
+
+ // 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 if and only if 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 std::string ShowWideCString(const wchar_t* wide_c_str);
+
+ // Compares two wide C strings. Returns true if and only if 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 if and only if
+ // 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 if and only if
+ // 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);
+
+ // Returns true if and only if the given string ends with the given suffix,
+ // ignoring case. Any string is considered to end with an empty suffix.
+ static bool EndsWithCaseInsensitive(const std::string& str,
+ const std::string& suffix);
+
+ // Formats an int value as "%02d".
+ static std::string FormatIntWidth2(int value); // "%02d" for width == 2
+
+ // Formats an int value to given width with leading zeros.
+ static std::string FormatIntWidthN(int value, int width);
+
+ // Formats an int value as "%X".
+ static std::string FormatHexInt(int value);
+
+ // Formats an int value as "%X".
+ static std::string FormatHexUInt32(uint32_t value);
+
+ // Formats a byte as "%02X".
+ static std::string FormatByte(unsigned char value);
+
+ private:
+ String(); // Not meant to be instantiated.
+}; // class String
+
+// Gets the content of the stringstream's buffer as an std::string. Each '\0'
+// character in the buffer is replaced with "\\0".
+GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
diff --git a/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-type-util.h b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-type-util.h
new file mode 100644
index 0000000..6bc02a7
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/include/gtest/internal/gtest-type-util.h
@@ -0,0 +1,186 @@
+// 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.
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests.
+
+// IWYU pragma: private, include "gtest/gtest.h"
+// IWYU pragma: friend gtest/.*
+// IWYU pragma: friend gmock/.*
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include "gtest/internal/gtest-port.h"
+
+// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+#if GTEST_HAS_CXXABI_H_
+#include <cxxabi.h>
+#elif defined(__HP_aCC)
+#include <acxx_demangle.h>
+#endif // GTEST_HASH_CXXABI_H_
+
+namespace testing {
+namespace internal {
+
+// Canonicalizes a given name with respect to the Standard C++ Library.
+// This handles removing the inline namespace within `std` that is
+// used by various standard libraries (e.g., `std::__1`). Names outside
+// of namespace std are returned unmodified.
+inline std::string CanonicalizeForStdLibVersioning(std::string s) {
+ static const char prefix[] = "std::__";
+ if (s.compare(0, strlen(prefix), prefix) == 0) {
+ std::string::size_type end = s.find("::", strlen(prefix));
+ if (end != s.npos) {
+ // Erase everything between the initial `std` and the second `::`.
+ s.erase(strlen("std"), end - strlen("std"));
+ }
+ }
+ return s;
+}
+
+#if GTEST_HAS_RTTI
+// GetTypeName(const std::type_info&) returns a human-readable name of type T.
+inline std::string GetTypeName(const std::type_info& type) {
+ const char* const name = type.name();
+#if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
+ int status = 0;
+ // gcc's implementation of typeid(T).name() mangles the type name,
+ // so we have to demangle it.
+#if GTEST_HAS_CXXABI_H_
+ using abi::__cxa_demangle;
+#endif // GTEST_HAS_CXXABI_H_
+ char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status);
+ const std::string name_str(status == 0 ? readable_name : name);
+ free(readable_name);
+ return CanonicalizeForStdLibVersioning(name_str);
+#else
+ return name;
+#endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
+}
+#endif // GTEST_HAS_RTTI
+
+// GetTypeName<T>() returns a human-readable name of type T if and only if
+// RTTI is enabled, otherwise it returns a dummy type name.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+std::string GetTypeName() {
+#if GTEST_HAS_RTTI
+ return GetTypeName(typeid(T));
+#else
+ return "<type>";
+#endif // GTEST_HAS_RTTI
+}
+
+// A unique type indicating an empty node
+struct None {};
+
+#define GTEST_TEMPLATE_ \
+ template <typename T> \
+ class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>. This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+ template <typename T>
+ struct Bind {
+ typedef Tmpl<T> type;
+ };
+};
+
+#define GTEST_BIND_(TmplSel, T) TmplSel::template Bind<T>::type
+
+template <GTEST_TEMPLATE_ Head_, GTEST_TEMPLATE_... Tail_>
+struct Templates {
+ using Head = TemplateSel<Head_>;
+ using Tail = Templates<Tail_...>;
+};
+
+template <GTEST_TEMPLATE_ Head_>
+struct Templates<Head_> {
+ using Head = TemplateSel<Head_>;
+ using Tail = None;
+};
+
+// Tuple-like type lists
+template <typename Head_, typename... Tail_>
+struct Types {
+ using Head = Head_;
+ using Tail = Types<Tail_...>;
+};
+
+template <typename Head_>
+struct Types<Head_> {
+ using Head = Head_;
+ using Tail = None;
+};
+
+// Helper metafunctions to tell apart a single type from types
+// generated by ::testing::Types
+template <typename... Ts>
+struct ProxyTypeList {
+ using type = Types<Ts...>;
+};
+
+template <typename>
+struct is_proxy_type_list : std::false_type {};
+
+template <typename... Ts>
+struct is_proxy_type_list<ProxyTypeList<Ts...>> : std::true_type {};
+
+// Generator which conditionally creates type lists.
+// It recognizes if a requested type list should be created
+// and prevents creating a new type list nested within another one.
+template <typename T>
+struct GenerateTypeList {
+ private:
+ using proxy = typename std::conditional<is_proxy_type_list<T>::value, T,
+ ProxyTypeList<T>>::type;
+
+ public:
+ using type = typename proxy::type;
+};
+
+} // namespace internal
+
+template <typename... Ts>
+using Types = internal::ProxyTypeList<Ts...>;
+
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-all.cc b/libs/cpp-httplib/test/gtest/src/gtest-all.cc
new file mode 100644
index 0000000..2a70ed8
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-all.cc
@@ -0,0 +1,49 @@
+// 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.
+
+//
+// Google C++ Testing and Mocking 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.
+#include "src/gtest-assertion-result.cc"
+#include "src/gtest-death-test.cc"
+#include "src/gtest-filepath.cc"
+#include "src/gtest-matchers.cc"
+#include "src/gtest-port.cc"
+#include "src/gtest-printers.cc"
+#include "src/gtest-test-part.cc"
+#include "src/gtest-typed-test.cc"
+#include "src/gtest.cc"
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-assertion-result.cc b/libs/cpp-httplib/test/gtest/src/gtest-assertion-result.cc
new file mode 100644
index 0000000..f1c0b10
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-assertion-result.cc
@@ -0,0 +1,77 @@
+// 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This file defines the AssertionResult type.
+
+#include "gtest/gtest-assertion-result.h"
+
+#include <string>
+#include <utility>
+
+#include "gtest/gtest-message.h"
+
+namespace testing {
+
+// AssertionResult constructors.
+// Used in EXPECT_TRUE/FALSE(assertion_result).
+AssertionResult::AssertionResult(const AssertionResult& other)
+ : success_(other.success_),
+ message_(other.message_.get() != nullptr
+ ? new ::std::string(*other.message_)
+ : static_cast< ::std::string*>(nullptr)) {}
+
+// Swaps two AssertionResults.
+void AssertionResult::swap(AssertionResult& other) {
+ using std::swap;
+ swap(success_, other.success_);
+ swap(message_, other.message_);
+}
+
+// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+AssertionResult AssertionResult::operator!() const {
+ AssertionResult negation(!success_);
+ if (message_.get() != nullptr) 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 testing
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-death-test.cc b/libs/cpp-httplib/test/gtest/src/gtest-death-test.cc
new file mode 100644
index 0000000..e6abc62
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-death-test.cc
@@ -0,0 +1,1620 @@
+// 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.
+
+//
+// This file implements death tests.
+
+#include "gtest/gtest-death-test.h"
+
+#include <functional>
+#include <utility>
+
+#include "gtest/internal/custom/gtest.h"
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_MAC
+#include <crt_externs.h>
+#endif // GTEST_OS_MAC
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#if GTEST_OS_LINUX
+#include <signal.h>
+#endif // GTEST_OS_LINUX
+
+#include <stdarg.h>
+
+#if GTEST_OS_WINDOWS
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#include <sys/wait.h>
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_OS_QNX
+#include <spawn.h>
+#endif // GTEST_OS_QNX
+
+#if GTEST_OS_FUCHSIA
+#include <lib/fdio/fd.h>
+#include <lib/fdio/io.h>
+#include <lib/fdio/spawn.h>
+#include <lib/zx/channel.h>
+#include <lib/zx/port.h>
+#include <lib/zx/process.h>
+#include <lib/zx/socket.h>
+#include <zircon/processargs.h>
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/policy.h>
+#include <zircon/syscalls/port.h>
+#endif // GTEST_OS_FUCHSIA
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-string.h"
+#include "src/gtest-internal-inl.h"
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+//
+// This is defined in internal/gtest-port.h as "fast", but can be overridden by
+// a definition in internal/custom/gtest-port.h. The recommended value, which is
+// used internally at Google, is "threadsafe".
+static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE;
+
+} // namespace testing
+
+GTEST_DEFINE_string_(
+ death_test_style,
+ testing::internal::StringFromGTestEnv("death_test_style",
+ testing::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,
+ testing::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.");
+
+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 "
+ "the '|' characters. 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 testing {
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal {
+
+// Valid only for fast death tests. Indicates the code is running in the
+// child process of a fast style death test.
+#if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+static bool g_in_fast_death_test_child = false;
+#endif
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process. Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests. IMPORTANT: This is an internal utility. Using it may break the
+// implementation of death tests. User code MUST NOT use it.
+bool InDeathTestChild() {
+#if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
+
+ // On Windows and Fuchsia, death tests are thread-safe regardless of the value
+ // of the death_test_style flag.
+ return !GTEST_FLAG_GET(internal_run_death_test).empty();
+
+#else
+
+ if (GTEST_FLAG_GET(death_test_style) == "threadsafe")
+ return !GTEST_FLAG_GET(internal_run_death_test).empty();
+ else
+ return g_in_fast_death_test_child;
+#endif
+}
+
+} // namespace internal
+
+// 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 || GTEST_OS_FUCHSIA
+
+ return exit_status == exit_code_;
+
+#else
+
+ return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+
+#endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
+}
+
+#if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+#if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
+ {
+ bool result;
+ if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) {
+ return result;
+ }
+ }
+#endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
+ return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+#endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static std::string ExitSummary(int exit_code) {
+ Message m;
+
+#if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
+
+ 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 || GTEST_OS_FUCHSIA
+
+ 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 && !GTEST_OS_FUCHSIA
+// 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 std::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.";
+ }
+ msg << " See "
+ "https://github.com/google/googletest/blob/master/docs/"
+ "advanced.md#death-tests-and-threads"
+ << " for more explanation and suggested solutions, especially if"
+ << " this is the last message you see before your test times out.";
+ return msg.GetString();
+}
+#endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+
+// 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';
+
+#if GTEST_OS_FUCHSIA
+
+// File descriptor used for the pipe in the child process.
+static const int kFuchsiaReadPipeFd = 3;
+
+#endif
+
+// 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.
+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.
+static void DeathTestAbort(const std::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 != nullptr) {
+ 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(::std::string("CHECK failed: File ") + __FILE__ + \
+ ", line " + \
+ ::testing::internal::StreamableToString(__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(::std::string("CHECK failed: File ") + __FILE__ + \
+ ", line " + \
+ ::testing::internal::StreamableToString(__LINE__) + \
+ ": " + #expression + " != -1"); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// Returns the message describing the last system error in errno.
+std::string GetLastErrnoDescription() {
+ return 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 == nullptr) {
+ 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,
+ Matcher<const std::string&> matcher, const char* file,
+ int line, DeathTest** test) {
+ return GetUnitTestImpl()->death_test_factory()->Create(
+ statement, std::move(matcher), file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+ return last_death_test_message_.c_str();
+}
+
+void DeathTest::set_last_death_test_message(const std::string& message) {
+ last_death_test_message_ = message;
+}
+
+std::string DeathTest::last_death_test_message_;
+
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest {
+ protected:
+ DeathTestImpl(const char* a_statement, Matcher<const std::string&> matcher)
+ : statement_(a_statement),
+ matcher_(std::move(matcher)),
+ 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() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+ void Abort(AbortReason reason) override;
+ bool Passed(bool status_ok) override;
+
+ const char* statement() const { return statement_; }
+ 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();
+
+ // Returns stderr output from the child process.
+ virtual std::string GetErrorLogs();
+
+ 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_;
+ // A matcher that's expected to match the stderr output by the child process.
+ Matcher<const std::string&> matcher_;
+ // 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<unsigned int>(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);
+}
+
+std::string DeathTestImpl::GetErrorLogs() { return GetCapturedStderr(); }
+
+// 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.
+// matcher_: A matcher that's expected to match the stderr output by the child
+// process.
+//
+// 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 if and only if 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 std::string error_message = GetErrorLogs();
+
+ 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) {
+ if (matcher_.Matches(error_message)) {
+ success = true;
+ } else {
+ std::ostringstream stream;
+ matcher_.DescribeTo(&stream);
+ buffer << " Result: died but not with expected error.\n"
+ << " Expected: " << stream.str() << "\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, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : DeathTestImpl(a_statement, std::move(matcher)),
+ 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<int>(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 != nullptr) {
+ // 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),
+ nullptr, 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<intptr_t>(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.
+ nullptr)); // The even is unnamed.
+ GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr);
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ "filter=" + info->test_suite_name() + "." +
+ info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ +
+ "internal_run_death_test=" + file_ + "|" + StreamableToString(line_) +
+ "|" + StreamableToString(death_test_index) + "|" +
+ StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) +
+ // size_t has the same width as pointers on both 32-bit and 64-bit
+ // Windows platforms.
+ // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+ "|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) + "|" +
+ StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
+
+ char executable_path[_MAX_PATH + 1]; // NOLINT
+ GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr,
+ executable_path,
+ _MAX_PATH));
+
+ std::string command_line = std::string(::GetCommandLineA()) + " " +
+ filter_flag + " \"" + internal_flag + "\"";
+
+ 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<char*>(command_line.c_str()),
+ nullptr, // Returned process handle is not inheritable.
+ nullptr, // Returned thread handle is not inheritable.
+ TRUE, // Child inherits all inheritable handles (for write_handle_).
+ 0x0, // Default creation flags.
+ nullptr, // 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;
+}
+
+#elif GTEST_OS_FUCHSIA
+
+class FuchsiaDeathTest : public DeathTestImpl {
+ public:
+ FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : DeathTestImpl(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ int Wait() override;
+ TestRole AssumeRole() override;
+ std::string GetErrorLogs() override;
+
+ 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_;
+ // The stderr data captured by the child process.
+ std::string captured_stderr_;
+
+ zx::process child_process_;
+ zx::channel exception_channel_;
+ zx::socket stderr_socket_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() { args_.push_back(nullptr); }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::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]; }
+
+ int size() { return static_cast<int>(args_.size()) - 1; }
+
+ private:
+ std::vector<char*> args_;
+};
+
+// 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 FuchsiaDeathTest::Wait() {
+ const int kProcessKey = 0;
+ const int kSocketKey = 1;
+ const int kExceptionKey = 2;
+
+ if (!spawned()) return 0;
+
+ // Create a port to wait for socket/task/exception events.
+ zx_status_t status_zx;
+ zx::port port;
+ status_zx = zx::port::create(0, &port);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for the child process to terminate.
+ status_zx =
+ child_process_.wait_async(port, kProcessKey, ZX_PROCESS_TERMINATED, 0);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for the socket to be readable or closed.
+ status_zx = stderr_socket_.wait_async(
+ port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for an exception.
+ status_zx = exception_channel_.wait_async(port, kExceptionKey,
+ ZX_CHANNEL_READABLE, 0);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ bool process_terminated = false;
+ bool socket_closed = false;
+ do {
+ zx_port_packet_t packet = {};
+ status_zx = port.wait(zx::time::infinite(), &packet);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ if (packet.key == kExceptionKey) {
+ // Process encountered an exception. Kill it directly rather than
+ // letting other handlers process the event. We will get a kProcessKey
+ // event when the process actually terminates.
+ status_zx = child_process_.kill();
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ } else if (packet.key == kProcessKey) {
+ // Process terminated.
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED);
+ process_terminated = true;
+ } else if (packet.key == kSocketKey) {
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ if (packet.signal.observed & ZX_SOCKET_READABLE) {
+ // Read data from the socket.
+ constexpr size_t kBufferSize = 1024;
+ do {
+ size_t old_length = captured_stderr_.length();
+ size_t bytes_read = 0;
+ captured_stderr_.resize(old_length + kBufferSize);
+ status_zx =
+ stderr_socket_.read(0, &captured_stderr_.front() + old_length,
+ kBufferSize, &bytes_read);
+ captured_stderr_.resize(old_length + bytes_read);
+ } while (status_zx == ZX_OK);
+ if (status_zx == ZX_ERR_PEER_CLOSED) {
+ socket_closed = true;
+ } else {
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT);
+ status_zx = stderr_socket_.wait_async(
+ port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ }
+ } else {
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED);
+ socket_closed = true;
+ }
+ }
+ } while (!process_terminated && !socket_closed);
+
+ ReadAndInterpretStatusByte();
+
+ zx_info_process_t buffer;
+ status_zx = child_process_.get_info(ZX_INFO_PROCESS, &buffer, sizeof(buffer),
+ nullptr, nullptr);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ GTEST_DEATH_TEST_CHECK_(buffer.flags & ZX_INFO_PROCESS_FLAG_EXITED);
+ set_status(static_cast<int>(buffer.return_code));
+ return status();
+}
+
+// The AssumeRole process for a Fuchsia 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 FuchsiaDeathTest::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 != nullptr) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(kFuchsiaReadPipeFd);
+ return EXECUTE_TEST;
+ }
+
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // Build the child process command line.
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ "filter=" + info->test_suite_name() + "." +
+ info->name();
+ const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kInternalRunDeathTestFlag + "=" + file_ +
+ "|" + StreamableToString(line_) + "|" +
+ StreamableToString(death_test_index);
+ Arguments args;
+ args.AddArguments(GetInjectableArgvs());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ // Build the pipe for communication with the child.
+ zx_status_t status;
+ zx_handle_t child_pipe_handle;
+ int child_pipe_fd;
+ status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ set_read_fd(child_pipe_fd);
+
+ // Set the pipe handle for the child.
+ fdio_spawn_action_t spawn_actions[2] = {};
+ fdio_spawn_action_t* add_handle_action = &spawn_actions[0];
+ add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
+ add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd);
+ add_handle_action->h.handle = child_pipe_handle;
+
+ // Create a socket pair will be used to receive the child process' stderr.
+ zx::socket stderr_producer_socket;
+ status = zx::socket::create(0, &stderr_producer_socket, &stderr_socket_);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+ int stderr_producer_fd = -1;
+ status =
+ fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+
+ // Make the stderr socket nonblocking.
+ GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0);
+
+ fdio_spawn_action_t* add_stderr_action = &spawn_actions[1];
+ add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD;
+ add_stderr_action->fd.local_fd = stderr_producer_fd;
+ add_stderr_action->fd.target_fd = STDERR_FILENO;
+
+ // Create a child job.
+ zx_handle_t child_job = ZX_HANDLE_INVALID;
+ status = zx_job_create(zx_job_default(), 0, &child_job);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ zx_policy_basic_t policy;
+ policy.condition = ZX_POL_NEW_ANY;
+ policy.policy = ZX_POL_ACTION_ALLOW;
+ status = zx_job_set_policy(child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC,
+ &policy, 1);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Create an exception channel attached to the |child_job|, to allow
+ // us to suppress the system default exception handler from firing.
+ status = zx_task_create_exception_channel(
+ child_job, 0, exception_channel_.reset_and_get_address());
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Spawn the child process.
+ status = fdio_spawn_etc(child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0],
+ args.Argv(), nullptr, 2, spawn_actions,
+ child_process_.reset_and_get_address(), nullptr);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+std::string FuchsiaDeathTest::GetErrorLogs() { return captured_stderr_; }
+
+#else // We are neither on Windows, nor on Fuchsia.
+
+// 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, Matcher<const std::string&> matcher);
+
+ // All of these virtual functions are inherited from DeathTest.
+ int Wait() override;
+
+ 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,
+ Matcher<const std::string&> matcher)
+ : DeathTestImpl(a_statement, std::move(matcher)), 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, Matcher<const std::string&> matcher)
+ : ForkingDeathTest(a_statement, std::move(matcher)) {}
+ TestRole AssumeRole() override;
+};
+
+// 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();
+ g_in_fast_death_test_child = true;
+ 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, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : ForkingDeathTest(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+ TestRole AssumeRole() override;
+
+ private:
+ static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() {
+ ::std::vector<std::string> args = GetInjectableArgvs();
+#if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
+ ::std::vector<std::string> extra_args =
+ GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_();
+ args.insert(args.end(), extra_args.begin(), extra_args.end());
+#endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
+ return args;
+ }
+ // 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(nullptr); }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::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<char*> 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_QNX
+extern "C" char** environ;
+#else // GTEST_OS_QNX
+// 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<ExecDeathTestArgs*>(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(std::string("chdir(\"") + original_dir +
+ "\") failed: " + GetLastErrnoDescription());
+ return EXIT_FAILURE;
+ }
+
+ // We can safely call execv() as it's almost a direct system call. We
+ // cannot use execvp() as it's a libc function and thus potentially
+ // unsafe. Since execv() doesn't search the PATH, the user must
+ // invoke the test program via a valid path that contains at least
+ // one path separator.
+ execv(args->argv[0], args->argv);
+ DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " +
+ original_dir + " failed: " + GetLastErrnoDescription());
+ return EXIT_FAILURE;
+}
+#endif // GTEST_OS_QNX
+
+#if GTEST_HAS_CLONE
+// 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.
+static void StackLowerThanAddress(const void* ptr,
+ bool* result) GTEST_NO_INLINE_;
+// Make sure sanitizers do not tamper with the stack here.
+// Ideally, we want to use `__builtin_frame_address` instead of a local variable
+// address with sanitizer disabled, but it does not work when the
+// compiler optimizes the stack frame out, which happens on PowerPC targets.
+// HWAddressSanitizer add a random tag to the MSB of the local variable address,
+// making comparison result unpredictable.
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+static void StackLowerThanAddress(const void* ptr, bool* result) {
+ int dummy = 0;
+ *result = std::less<const void*>()(&dummy, ptr);
+}
+
+// Make sure AddressSanitizer does not tamper with the stack here.
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+static bool StackGrowsDown() {
+ int dummy = 0;
+ bool result;
+ StackLowerThanAddress(&dummy, &result);
+ return result;
+}
+#endif // GTEST_HAS_CLONE
+
+// Spawns a child process with the same executable as the current process in
+// a thread-safe manner and instructs it to run the death test. The
+// implementation uses fork(2) + exec. On systems where clone(2) is
+// available, it is used instead, being slightly more thread-safe. On QNX,
+// fork supports only single-threaded environments, so this function uses
+// spawn(2) there instead. The function dies with an error message if
+// anything goes wrong.
+static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
+ ExecDeathTestArgs args = {argv, close_fd};
+ pid_t child_pid = -1;
+
+#if GTEST_OS_QNX
+ // Obtains the current directory and sets it to be closed in the child
+ // process.
+ const int cwd_fd = open(".", O_RDONLY);
+ GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
+ // 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(std::string("chdir(\"") + original_dir +
+ "\") failed: " + GetLastErrnoDescription());
+ return EXIT_FAILURE;
+ }
+
+ int fd_flags;
+ // Set close_fd to be closed after spawn.
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(
+ fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC));
+ struct inheritance inherit = {0};
+ // spawn is a system call.
+ child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, environ);
+ // Restores the current working directory.
+ GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
+
+#else // GTEST_OS_QNX
+#if GTEST_OS_LINUX
+ // When a SIGPROF signal is received while fork() or clone() are executing,
+ // the process may hang. To avoid this, we ignore SIGPROF here and re-enable
+ // it after the call to fork()/clone() is complete.
+ struct sigaction saved_sigprof_action;
+ struct sigaction ignore_sigprof_action;
+ memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
+ sigemptyset(&ignore_sigprof_action.sa_mask);
+ ignore_sigprof_action.sa_handler = SIG_IGN;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(
+ sigaction(SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_CLONE
+ const bool use_fork = GTEST_FLAG_GET(death_test_use_fork);
+
+ if (!use_fork) {
+ static const bool stack_grows_down = StackGrowsDown();
+ const auto stack_size = static_cast<size_t>(getpagesize() * 2);
+ // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
+ void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+
+ // Maximum stack alignment in bytes: For a downward-growing stack, this
+ // amount is subtracted from size of the stack space to get an address
+ // that is within the stack space and is aligned on all systems we care
+ // about. As far as I know there is no ABI with stack alignment greater
+ // than 64. We assume stack and stack_size already have alignment of
+ // kMaxStackAlignment.
+ const size_t kMaxStackAlignment = 64;
+ void* const stack_top =
+ static_cast<char*>(stack) +
+ (stack_grows_down ? stack_size - kMaxStackAlignment : 0);
+ GTEST_DEATH_TEST_CHECK_(
+ static_cast<size_t>(stack_size) > kMaxStackAlignment &&
+ reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 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);
+ }
+#endif // GTEST_OS_QNX
+#if GTEST_OS_LINUX
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(
+ sigaction(SIGPROF, &saved_sigprof_action, nullptr));
+#endif // GTEST_OS_LINUX
+
+ 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 != nullptr) {
+ 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 std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ "filter=" + info->test_suite_name() + "." +
+ info->name();
+ const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ "internal_run_death_test=" + file_ + "|" +
+ StreamableToString(line_) + "|" +
+ StreamableToString(death_test_index) + "|" +
+ StreamableToString(pipe_fd[1]);
+ Arguments args;
+ args.AddArguments(GetArgvsForDeathTestChildProcess());
+ 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 = ExecDeathTestSpawnChild(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,
+ Matcher<const std::string&> matcher,
+ 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 != nullptr) {
+ if (death_test_index > flag->index()) {
+ DeathTest::set_last_death_test_message(
+ "Death test count (" + StreamableToString(death_test_index) +
+ ") somehow exceeded expected maximum (" +
+ StreamableToString(flag->index()) + ")");
+ return false;
+ }
+
+ if (!(flag->file() == file && flag->line() == line &&
+ flag->index() == death_test_index)) {
+ *test = nullptr;
+ return true;
+ }
+ }
+
+#if GTEST_OS_WINDOWS
+
+ if (GTEST_FLAG_GET(death_test_style) == "threadsafe" ||
+ GTEST_FLAG_GET(death_test_style) == "fast") {
+ *test = new WindowsDeathTest(statement, std::move(matcher), file, line);
+ }
+
+#elif GTEST_OS_FUCHSIA
+
+ if (GTEST_FLAG_GET(death_test_style) == "threadsafe" ||
+ GTEST_FLAG_GET(death_test_style) == "fast") {
+ *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line);
+ }
+
+#else
+
+ if (GTEST_FLAG_GET(death_test_style) == "threadsafe") {
+ *test = new ExecDeathTest(statement, std::move(matcher), file, line);
+ } else if (GTEST_FLAG_GET(death_test_style) == "fast") {
+ *test = new NoExecDeathTest(statement, std::move(matcher));
+ }
+
+#endif // GTEST_OS_WINDOWS
+
+ else { // NOLINT - this is more readable than unbalanced brackets inside #if.
+ DeathTest::set_last_death_test_message("Unknown death test style \"" +
+ GTEST_FLAG_GET(death_test_style) +
+ "\" encountered");
+ return false;
+ }
+
+ return true;
+}
+
+#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.
+static 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("Unable to open parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
+
+ const HANDLE write_handle = reinterpret_cast<HANDLE>(write_handle_as_size_t);
+ HANDLE dup_write_handle;
+
+ // The newly initialized handle is accessible only 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("Unable to duplicate the pipe handle " +
+ StreamableToString(write_handle_as_size_t) +
+ " from the parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ const HANDLE event_handle = reinterpret_cast<HANDLE>(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("Unable to duplicate the event handle " +
+ StreamableToString(event_handle_as_size_t) +
+ " from the parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ const int write_fd =
+ ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+ if (write_fd == -1) {
+ DeathTestAbort("Unable to convert pipe handle " +
+ StreamableToString(write_handle_as_size_t) +
+ " to a file descriptor");
+ }
+
+ // 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_GET(internal_run_death_test) == "") return nullptr;
+
+ // 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_GET(internal_run_death_test), '|', &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("Bad --gtest_internal_run_death_test flag: " +
+ GTEST_FLAG_GET(internal_run_death_test));
+ }
+ write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t,
+ event_handle_as_size_t);
+
+#elif GTEST_OS_FUCHSIA
+
+ if (fields.size() != 3 || !ParseNaturalNumber(fields[1], &line) ||
+ !ParseNaturalNumber(fields[2], &index)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
+ GTEST_FLAG_GET(internal_run_death_test));
+ }
+
+#else
+
+ if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) ||
+ !ParseNaturalNumber(fields[2], &index) ||
+ !ParseNaturalNumber(fields[3], &write_fd)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
+ GTEST_FLAG_GET(internal_run_death_test));
+ }
+
+#endif // GTEST_OS_WINDOWS
+
+ return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
+}
+
+} // namespace internal
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace testing
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-filepath.cc b/libs/cpp-httplib/test/gtest/src/gtest-filepath.cc
new file mode 100644
index 0000000..f6ee90c
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-filepath.cc
@@ -0,0 +1,367 @@
+// 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.
+
+#include "gtest/internal/gtest-filepath.h"
+
+#include <stdlib.h>
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_OS_WINDOWS_MOBILE
+#include <windows.h>
+#elif GTEST_OS_WINDOWS
+#include <direct.h>
+#include <io.h>
+#else
+#include <limits.h>
+
+#include <climits> // Some Linux distributions define PATH_MAX here.
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#include "gtest/internal/gtest-string.h"
+
+#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 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 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 || GTEST_OS_WINDOWS_PHONE || \
+ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 || \
+ GTEST_OS_XTENSA
+ // These platforms do not 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)) == nullptr ? "" : cwd);
+#else
+ char cwd[GTEST_PATH_MAX_ + 1] = {'\0'};
+ char* result = getcwd(cwd, sizeof(cwd));
+#if GTEST_OS_NACL
+ // getcwd will likely fail in NaCl due to the sandbox, so return something
+ // reasonable. The user may have provided a shim implementation for getcwd,
+ // however, so fallback only when failure is detected.
+ return FilePath(result == nullptr ? kCurrentDirectoryString : cwd);
+#endif // GTEST_OS_NACL
+ return FilePath(result == nullptr ? "" : 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 {
+ const std::string dot_extension = std::string(".") + extension;
+ if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
+ return FilePath(
+ pathname_.substr(0, pathname_.length() - dot_extension.length()));
+ }
+ return *this;
+}
+
+// Returns a pointer to the last occurrence 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 != nullptr &&
+ (last_sep == nullptr || 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(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();
+ std::string dir;
+ if (last_sep) {
+ dir = std::string(c_str(), static_cast<size_t>(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) {
+ std::string file;
+ if (number == 0) {
+ file = base_name.string() + "." + extension;
+ } else {
+ file =
+ base_name.string() + "_" + StreamableToString(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(dir.string() + kPathSeparator + relative_path.string());
+}
+
+// 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
+ 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_<number>.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, nullptr) ? 0 : -1;
+ delete[] unicode;
+#elif GTEST_OS_WINDOWS
+ int result = _mkdir(pathname_.c_str());
+#elif GTEST_OS_ESP8266 || GTEST_OS_XTENSA
+ // do nothing
+ int result = 0;
+#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(pathname_.substr(0, 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 "..".
+void FilePath::Normalize() {
+ auto out = pathname_.begin();
+
+ for (const char character : pathname_) {
+ if (!IsPathSeparator(character)) {
+ *(out++) = character;
+ } else if (out == pathname_.begin() || *std::prev(out) != kPathSeparator) {
+ *(out++) = kPathSeparator;
+ } else {
+ continue;
+ }
+ }
+
+ pathname_.erase(out, pathname_.end());
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-internal-inl.h b/libs/cpp-httplib/test/gtest/src/gtest-internal-inl.h
new file mode 100644
index 0000000..0b9e929
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-internal-inl.h
@@ -0,0 +1,1212 @@
+// 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.//
+// This file contains purely Google Test's internal implementation. Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
+#define GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
+
+#ifndef _WIN32_WCE
+#include <errno.h>
+#endif // !_WIN32_WCE
+#include <stddef.h>
+#include <stdlib.h> // For strtoll/_strtoul64/malloc/free.
+#include <string.h> // For memmove.
+
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_CAN_STREAM_RESULTS_
+#include <arpa/inet.h> // NOLINT
+#include <netdb.h> // NOLINT
+#endif
+
+#if GTEST_OS_WINDOWS
+#include <windows.h> // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// 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 testing {
+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;
+
+// A valid random seed must be in [1, kMaxRandomSeed].
+const int kMaxRandomSeed = 99999;
+
+// g_help_flag is true if and only if 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 if and only if 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);
+
+// Converts the given time in milliseconds to a date string in the ISO 8601
+// format, without the timezone information. N.B.: due to the use the
+// non-reentrant localtime() function, this function is not thread safe. Do
+// not use it in any code that can be called from multiple threads.
+GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(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 ParseFlag(const char* str, const char* flag, int32_t* value);
+
+// Returns a random seed in range [1, kMaxRandomSeed] based on the
+// given --gtest_random_seed flag value.
+inline int GetRandomSeedFromFlag(int32_t random_seed_flag) {
+ const unsigned int raw_seed =
+ (random_seed_flag == 0) ? static_cast<unsigned int>(GetTimeInMillis())
+ : static_cast<unsigned int>(random_seed_flag);
+
+ // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
+ // it's easy to type.
+ const int normalized_seed =
+ static_cast<int>((raw_seed - 1U) %
+ static_cast<unsigned int>(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_GET(also_run_disabled_tests);
+ break_on_failure_ = GTEST_FLAG_GET(break_on_failure);
+ catch_exceptions_ = GTEST_FLAG_GET(catch_exceptions);
+ color_ = GTEST_FLAG_GET(color);
+ death_test_style_ = GTEST_FLAG_GET(death_test_style);
+ death_test_use_fork_ = GTEST_FLAG_GET(death_test_use_fork);
+ fail_fast_ = GTEST_FLAG_GET(fail_fast);
+ filter_ = GTEST_FLAG_GET(filter);
+ internal_run_death_test_ = GTEST_FLAG_GET(internal_run_death_test);
+ list_tests_ = GTEST_FLAG_GET(list_tests);
+ output_ = GTEST_FLAG_GET(output);
+ brief_ = GTEST_FLAG_GET(brief);
+ print_time_ = GTEST_FLAG_GET(print_time);
+ print_utf8_ = GTEST_FLAG_GET(print_utf8);
+ random_seed_ = GTEST_FLAG_GET(random_seed);
+ repeat_ = GTEST_FLAG_GET(repeat);
+ recreate_environments_when_repeating_ =
+ GTEST_FLAG_GET(recreate_environments_when_repeating);
+ shuffle_ = GTEST_FLAG_GET(shuffle);
+ stack_trace_depth_ = GTEST_FLAG_GET(stack_trace_depth);
+ stream_result_to_ = GTEST_FLAG_GET(stream_result_to);
+ throw_on_failure_ = GTEST_FLAG_GET(throw_on_failure);
+ }
+
+ // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS.
+ ~GTestFlagSaver() {
+ GTEST_FLAG_SET(also_run_disabled_tests, also_run_disabled_tests_);
+ GTEST_FLAG_SET(break_on_failure, break_on_failure_);
+ GTEST_FLAG_SET(catch_exceptions, catch_exceptions_);
+ GTEST_FLAG_SET(color, color_);
+ GTEST_FLAG_SET(death_test_style, death_test_style_);
+ GTEST_FLAG_SET(death_test_use_fork, death_test_use_fork_);
+ GTEST_FLAG_SET(filter, filter_);
+ GTEST_FLAG_SET(fail_fast, fail_fast_);
+ GTEST_FLAG_SET(internal_run_death_test, internal_run_death_test_);
+ GTEST_FLAG_SET(list_tests, list_tests_);
+ GTEST_FLAG_SET(output, output_);
+ GTEST_FLAG_SET(brief, brief_);
+ GTEST_FLAG_SET(print_time, print_time_);
+ GTEST_FLAG_SET(print_utf8, print_utf8_);
+ GTEST_FLAG_SET(random_seed, random_seed_);
+ GTEST_FLAG_SET(repeat, repeat_);
+ GTEST_FLAG_SET(recreate_environments_when_repeating,
+ recreate_environments_when_repeating_);
+ GTEST_FLAG_SET(shuffle, shuffle_);
+ GTEST_FLAG_SET(stack_trace_depth, stack_trace_depth_);
+ GTEST_FLAG_SET(stream_result_to, stream_result_to_);
+ GTEST_FLAG_SET(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_;
+ std::string color_;
+ std::string death_test_style_;
+ bool death_test_use_fork_;
+ bool fail_fast_;
+ std::string filter_;
+ std::string internal_run_death_test_;
+ bool list_tests_;
+ std::string output_;
+ bool brief_;
+ bool print_time_;
+ bool print_utf8_;
+ int32_t random_seed_;
+ int32_t repeat_;
+ bool recreate_environments_when_repeating_;
+ bool shuffle_;
+ int32_t stack_trace_depth_;
+ std::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.
+// 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 converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+GTEST_API_ std::string CodePointToUtf8(uint32_t code_point);
+
+// 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)
+// 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_ std::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 a 32-bit integer. If it is unset,
+// returns default_val. If it is not a 32-bit integer, prints an error and
+// and aborts.
+GTEST_API_ int32_t Int32FromEnvOrDie(const char* env_var, int32_t default_val);
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true if and only if 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 <class Container, typename Predicate>
+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 (auto it = c.begin(); it != c.end(); ++it) {
+ if (predicate(*it)) ++count;
+ }
+ return count;
+}
+
+// Applies a function/functor to each element in the container.
+template <class Container, typename Functor>
+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 <typename E>
+inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
+ return (i < 0 || i >= static_cast<int>(v.size())) ? default_value
+ : v[static_cast<size_t>(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 <typename E>
+void ShuffleRange(internal::Random* random, int begin, int end,
+ std::vector<E>* v) {
+ const int size = static_cast<int>(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 +
+ static_cast<int>(random->Generate(static_cast<uint32_t>(range_width)));
+ std::swap((*v)[static_cast<size_t>(selected)],
+ (*v)[static_cast<size_t>(last_in_range)]);
+ }
+}
+
+// Performs an in-place shuffle of the vector's elements.
+template <typename E>
+inline void Shuffle(internal::Random* random, std::vector<E>* v) {
+ ShuffleRange(random, 0, static_cast<int>(v->size()), v);
+}
+
+// A function for deleting an object. Handy for being used as a
+// functor.
+template <typename T>
+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 std::string& key) : key_(key) {}
+
+ // Returns true if and only if the test name of test property matches on key_.
+ bool operator()(const TestProperty& test_property) const {
+ return test_property.key() == key_;
+ }
+
+ private:
+ std::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 std::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 std::string GetAbsolutePathToOutputFile();
+
+ // Functions for processing the gtest_filter flag.
+
+ // Returns true if and only if the user-specified filter matches the test
+ // suite name and the test name.
+ static bool FilterMatchesTest(const std::string& test_suite_name,
+ const std::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 std::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 an std::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 std::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;
+
+ // This string is inserted in place of stack frames that are part of
+ // Google Test's implementation.
+ static const char* const kElidedFramesMarker;
+
+ private:
+ OsStackTraceGetterInterface(const OsStackTraceGetterInterface&) = delete;
+ OsStackTraceGetterInterface& operator=(const OsStackTraceGetterInterface&) =
+ delete;
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetter() {}
+
+ std::string CurrentStackTrace(int max_depth, int skip_count) override;
+ void UponLeavingGTest() override;
+
+ private:
+#if GTEST_HAS_ABSL
+ 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 the stack trace code from within the user code.
+ void* caller_frame_ = nullptr;
+#endif // GTEST_HAS_ABSL
+
+ OsStackTraceGetter(const OsStackTraceGetter&) = delete;
+ OsStackTraceGetter& operator=(const OsStackTraceGetter&) = delete;
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+ const char* file;
+ int line;
+ std::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.
+ void ReportTestPartResult(const TestPartResult& result) override;
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ DefaultGlobalTestPartResultReporter(
+ const DefaultGlobalTestPartResultReporter&) = delete;
+ DefaultGlobalTestPartResultReporter& operator=(
+ const DefaultGlobalTestPartResultReporter&) = delete;
+};
+
+// 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_.
+ void ReportTestPartResult(const TestPartResult& result) override;
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ DefaultPerThreadTestPartResultReporter(
+ const DefaultPerThreadTestPartResultReporter&) = delete;
+ DefaultPerThreadTestPartResultReporter& operator=(
+ const DefaultPerThreadTestPartResultReporter&) = delete;
+};
+
+// 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 suites.
+ int successful_test_suite_count() const;
+
+ // Gets the number of failed test suites.
+ int failed_test_suite_count() const;
+
+ // Gets the number of all test suites.
+ int total_test_suite_count() const;
+
+ // Gets the number of all test suites that contain at least one test
+ // that should run.
+ int test_suite_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of skipped tests.
+ int skipped_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_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 time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns true if and only if the unit test passed (i.e. all test suites
+ // passed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true if and only if the unit test failed (i.e. some test suite
+ // failed or something outside of all tests failed).
+ bool Failed() const {
+ return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed();
+ }
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ const TestSuite* GetTestSuite(int i) const {
+ const int index = GetElementOr(test_suite_indices_, i, -1);
+ return index < 0 ? nullptr : test_suites_[static_cast<size_t>(i)];
+ }
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const TestCase* GetTestCase(int i) const { return GetTestSuite(i); }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ TestSuite* GetMutableSuiteCase(int i) {
+ const int index = GetElementOr(test_suite_indices_, i, -1);
+ return index < 0 ? nullptr : test_suites_[static_cast<size_t>(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 an std::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.
+ std::string CurrentOsStackTraceExceptTop(int skip_count)
+ GTEST_NO_INLINE_ GTEST_NO_TAIL_CALL_;
+
+ // Finds and returns a TestSuite with the given name. If one doesn't
+ // exist, creates one and returns it.
+ //
+ // Arguments:
+ //
+ // test_suite_name: name of the test suite
+ // 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 suite
+ // tear_down_tc: pointer to the function that tears down the test suite
+ TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc);
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ TestCase* GetTestCase(const char* test_case_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc) {
+ return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc);
+ }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Adds a TestInfo to the unit test.
+ //
+ // Arguments:
+ //
+ // set_up_tc: pointer to the function that sets up the test suite
+ // tear_down_tc: pointer to the function that tears down the test suite
+ // test_info: the TestInfo object
+ void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc,
+ TestInfo* test_info) {
+#if GTEST_HAS_DEATH_TEST
+ // 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.";
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ GetTestSuite(test_info->test_suite_name(), test_info->type_param(),
+ set_up_tc, tear_down_tc)
+ ->AddTestInfo(test_info);
+ }
+
+ // Returns ParameterizedTestSuiteRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() {
+ return parameterized_test_registry_;
+ }
+
+ std::set<std::string>* ignored_parameterized_test_suites() {
+ return &ignored_parameterized_test_suites_;
+ }
+
+ // Returns TypeParameterizedTestSuiteRegistry object used to keep track of
+ // type-parameterized tests and instantiations of them.
+ internal::TypeParameterizedTestSuiteRegistry&
+ type_parameterized_test_registry() {
+ return type_parameterized_test_registry_;
+ }
+
+ // Sets the TestSuite object for the test that's currently running.
+ void set_current_test_suite(TestSuite* a_current_test_suite) {
+ current_test_suite_ = a_current_test_suite;
+ }
+
+ // 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_SUITE_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_suites_, TestSuite::ClearTestSuiteResult);
+ }
+
+ // Clears the results of ad-hoc test assertions.
+ void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); }
+
+ // Adds a TestProperty to the current TestResult object when invoked in a
+ // context of a test or a test suite, or to the global property set. If the
+ // result already contains a property with the same key, the value will be
+ // updated.
+ void RecordProperty(const TestProperty& test_property);
+
+ 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 TestSuite 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 TestSuite* current_test_suite() const { return current_test_suite_; }
+ 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<Environment*>& environments() { return environments_; }
+
+ // Getters for the per-thread Google Test trace stack.
+ std::vector<TraceInfo>& gtest_trace_stack() {
+ return *(gtest_trace_stack_.pointer());
+ }
+ const std::vector<TraceInfo>& 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 suites, and the tests within each test suite,
+ // making sure that death tests are still run first.
+ void ShuffleTests();
+
+ // Restores the test suites 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<TestPartResultReporterInterface*>
+ 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<Environment*> environments_;
+
+ // The vector of TestSuites in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestSuite*> test_suites_;
+
+ // Provides a level of indirection for the test suite list to allow
+ // easy shuffling and restoring the test suite order. The i-th
+ // element of this vector is the index of the i-th test suite in the
+ // shuffled order.
+ std::vector<int> test_suite_indices_;
+
+ // ParameterizedTestRegistry object used to register value-parameterized
+ // tests.
+ internal::ParameterizedTestSuiteRegistry parameterized_test_registry_;
+ internal::TypeParameterizedTestSuiteRegistry
+ type_parameterized_test_registry_;
+
+ // The set holding the name of parameterized
+ // test suites that may go uninstantiated.
+ std::set<std::string> ignored_parameterized_test_suites_;
+
+ // Indicates whether RegisterParameterizedTests() has been called already.
+ bool parameterized_tests_registered_;
+
+ // Index of the last death test suite registered. Initially -1.
+ int last_death_test_suite_;
+
+ // This points to the TestSuite for the currently running test. It
+ // changes as Google Test goes through one test suite 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.
+ TestSuite* current_test_suite_;
+
+ // 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 if and only if 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_;
+
+ // The time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp_;
+
+ // 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.
+ std::unique_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+ std::unique_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+ internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
+
+ // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests()
+ // starts.
+ bool catch_exceptions_;
+
+ UnitTestImpl(const UnitTestImpl&) = delete;
+ UnitTestImpl& operator=(const UnitTestImpl&) = delete;
+}; // 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_ std::string GetLastErrnoDescription();
+
+// 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 <typename Integer>
+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.
+ using BiggestConvertible = unsigned long long; // NOLINT
+
+ const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); // NOLINT
+ const bool parse_success = *end == '\0' && errno == 0;
+
+ GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
+
+ const Integer result = static_cast<Integer>(parsed);
+ if (parse_success && static_cast<BiggestConvertible>(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 std::string& xml_element,
+ const TestProperty& property) {
+ test_result->RecordProperty(xml_element, property);
+ }
+
+ static void ClearTestPartResults(TestResult* test_result) {
+ test_result->ClearTestPartResults();
+ }
+
+ static const std::vector<testing::TestPartResult>& test_part_results(
+ const TestResult& test_result) {
+ return test_result.test_part_results();
+ }
+};
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Streams test results to the given port on the given host machine.
+class StreamingListener : public EmptyTestEventListener {
+ public:
+ // Abstract base class for writing strings to a socket.
+ class AbstractSocketWriter {
+ public:
+ virtual ~AbstractSocketWriter() {}
+
+ // Sends a string to the socket.
+ virtual void Send(const std::string& message) = 0;
+
+ // Closes the socket.
+ virtual void CloseConnection() {}
+
+ // Sends a string and a newline to the socket.
+ void SendLn(const std::string& message) { Send(message + "\n"); }
+ };
+
+ // Concrete class for actually writing strings to a socket.
+ class SocketWriter : public AbstractSocketWriter {
+ public:
+ SocketWriter(const std::string& host, const std::string& port)
+ : sockfd_(-1), host_name_(host), port_num_(port) {
+ MakeConnection();
+ }
+
+ ~SocketWriter() override {
+ if (sockfd_ != -1) CloseConnection();
+ }
+
+ // Sends a string to the socket.
+ void Send(const std::string& message) override {
+ GTEST_CHECK_(sockfd_ != -1)
+ << "Send() can be called only when there is a connection.";
+
+ const auto len = static_cast<size_t>(message.length());
+ if (write(sockfd_, message.c_str(), len) != static_cast<ssize_t>(len)) {
+ GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to "
+ << host_name_ << ":" << port_num_;
+ }
+ }
+
+ private:
+ // Creates a client socket and connects to the server.
+ void MakeConnection();
+
+ // Closes the socket.
+ void CloseConnection() override {
+ GTEST_CHECK_(sockfd_ != -1)
+ << "CloseConnection() can be called only when there is a connection.";
+
+ close(sockfd_);
+ sockfd_ = -1;
+ }
+
+ int sockfd_; // socket file descriptor
+ const std::string host_name_;
+ const std::string port_num_;
+
+ SocketWriter(const SocketWriter&) = delete;
+ SocketWriter& operator=(const SocketWriter&) = delete;
+ }; // class SocketWriter
+
+ // Escapes '=', '&', '%', and '\n' characters in str as "%xx".
+ static std::string UrlEncode(const char* str);
+
+ StreamingListener(const std::string& host, const std::string& port)
+ : socket_writer_(new SocketWriter(host, port)) {
+ Start();
+ }
+
+ explicit StreamingListener(AbstractSocketWriter* socket_writer)
+ : socket_writer_(socket_writer) {
+ Start();
+ }
+
+ void OnTestProgramStart(const UnitTest& /* unit_test */) override {
+ SendLn("event=TestProgramStart");
+ }
+
+ void OnTestProgramEnd(const UnitTest& unit_test) override {
+ // Note that Google Test current only report elapsed time for each
+ // test iteration, not for the entire test program.
+ SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
+
+ // Notify the streaming server to stop.
+ socket_writer_->CloseConnection();
+ }
+
+ void OnTestIterationStart(const UnitTest& /* unit_test */,
+ int iteration) override {
+ SendLn("event=TestIterationStart&iteration=" +
+ StreamableToString(iteration));
+ }
+
+ void OnTestIterationEnd(const UnitTest& unit_test,
+ int /* iteration */) override {
+ SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) +
+ "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) +
+ "ms");
+ }
+
+ // Note that "event=TestCaseStart" is a wire format and has to remain
+ // "case" for compatibility
+ void OnTestSuiteStart(const TestSuite& test_suite) override {
+ SendLn(std::string("event=TestCaseStart&name=") + test_suite.name());
+ }
+
+ // Note that "event=TestCaseEnd" is a wire format and has to remain
+ // "case" for compatibility
+ void OnTestSuiteEnd(const TestSuite& test_suite) override {
+ SendLn("event=TestCaseEnd&passed=" + FormatBool(test_suite.Passed()) +
+ "&elapsed_time=" + StreamableToString(test_suite.elapsed_time()) +
+ "ms");
+ }
+
+ void OnTestStart(const TestInfo& test_info) override {
+ SendLn(std::string("event=TestStart&name=") + test_info.name());
+ }
+
+ void OnTestEnd(const TestInfo& test_info) override {
+ SendLn("event=TestEnd&passed=" +
+ FormatBool((test_info.result())->Passed()) + "&elapsed_time=" +
+ StreamableToString((test_info.result())->elapsed_time()) + "ms");
+ }
+
+ void OnTestPartResult(const TestPartResult& test_part_result) override {
+ const char* file_name = test_part_result.file_name();
+ if (file_name == nullptr) file_name = "";
+ SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
+ "&line=" + StreamableToString(test_part_result.line_number()) +
+ "&message=" + UrlEncode(test_part_result.message()));
+ }
+
+ private:
+ // Sends the given message and a newline to the socket.
+ void SendLn(const std::string& message) { socket_writer_->SendLn(message); }
+
+ // Called at the start of streaming to notify the receiver what
+ // protocol we are using.
+ void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }
+
+ std::string FormatBool(bool value) { return value ? "1" : "0"; }
+
+ const std::unique_ptr<AbstractSocketWriter> socket_writer_;
+
+ StreamingListener(const StreamingListener&) = delete;
+ StreamingListener& operator=(const StreamingListener&) = delete;
+}; // class StreamingListener
+
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+} // namespace internal
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-matchers.cc b/libs/cpp-httplib/test/gtest/src/gtest-matchers.cc
new file mode 100644
index 0000000..7e3bcc0
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-matchers.cc
@@ -0,0 +1,98 @@
+// 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This file implements just enough of the matcher interface to allow
+// EXPECT_DEATH and friends to accept a matcher argument.
+
+#include "gtest/gtest-matchers.h"
+
+#include <string>
+
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+
+// Constructs a matcher that matches a const std::string& whose value is
+// equal to s.
+Matcher<const std::string&>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a const std::string& whose value is
+// equal to s.
+Matcher<const std::string&>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a std::string whose value is equal to
+// s.
+Matcher<std::string>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a std::string whose value is equal to
+// s.
+Matcher<std::string>::Matcher(const char* s) { *this = Eq(std::string(s)); }
+
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+// Constructs a matcher that matches a const StringView& whose value is
+// equal to s.
+Matcher<const internal::StringView&>::Matcher(const std::string& s) {
+ *this = Eq(s);
+}
+
+// Constructs a matcher that matches a const StringView& whose value is
+// equal to s.
+Matcher<const internal::StringView&>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a const StringView& whose value is
+// equal to s.
+Matcher<const internal::StringView&>::Matcher(internal::StringView s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a StringView whose value is equal to
+// s.
+Matcher<internal::StringView>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a StringView whose value is equal to
+// s.
+Matcher<internal::StringView>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a StringView whose value is equal to
+// s.
+Matcher<internal::StringView>::Matcher(internal::StringView s) {
+ *this = Eq(std::string(s));
+}
+#endif // GTEST_INTERNAL_HAS_STRING_VIEW
+
+} // namespace testing
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-port.cc b/libs/cpp-httplib/test/gtest/src/gtest-port.cc
new file mode 100644
index 0000000..d797fe4
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-port.cc
@@ -0,0 +1,1394 @@
+// 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.
+
+#include "gtest/internal/gtest-port.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cstdint>
+#include <fstream>
+#include <memory>
+
+#if GTEST_OS_WINDOWS
+#include <io.h>
+#include <sys/stat.h>
+#include <windows.h>
+
+#include <map> // Used in ThreadLocal.
+#ifdef _MSC_VER
+#include <crtdbg.h>
+#endif // _MSC_VER
+#else
+#include <unistd.h>
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_OS_MAC
+#include <mach/mach_init.h>
+#include <mach/task.h>
+#include <mach/vm_map.h>
+#endif // GTEST_OS_MAC
+
+#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
+ GTEST_OS_NETBSD || GTEST_OS_OPENBSD
+#include <sys/sysctl.h>
+#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
+#include <sys/user.h>
+#endif
+#endif
+
+#if GTEST_OS_QNX
+#include <devctl.h>
+#include <fcntl.h>
+#include <sys/procfs.h>
+#endif // GTEST_OS_QNX
+
+#if GTEST_OS_AIX
+#include <procinfo.h>
+#include <sys/types.h>
+#endif // GTEST_OS_AIX
+
+#if GTEST_OS_FUCHSIA
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+#endif // GTEST_OS_FUCHSIA
+
+#include "gtest/gtest-message.h"
+#include "gtest/gtest-spi.h"
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+#include "src/gtest-internal-inl.h"
+
+namespace testing {
+namespace internal {
+
+#if GTEST_OS_LINUX || GTEST_OS_GNU_HURD
+
+namespace {
+template <typename T>
+T ReadProcFileField(const std::string& filename, int field) {
+ std::string dummy;
+ std::ifstream file(filename.c_str());
+ while (field-- > 0) {
+ file >> dummy;
+ }
+ T output = 0;
+ file >> output;
+ return output;
+}
+} // namespace
+
+// Returns the number of active threads, or 0 when there is an error.
+size_t GetThreadCount() {
+ const std::string filename =
+ (Message() << "/proc/" << getpid() << "/stat").GetString();
+ return ReadProcFileField<size_t>(filename, 19);
+}
+
+#elif GTEST_OS_MAC
+
+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<vm_address_t>(thread_list),
+ sizeof(thread_t) * thread_count);
+ return static_cast<size_t>(thread_count);
+ } else {
+ return 0;
+ }
+}
+
+#elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
+ GTEST_OS_NETBSD
+
+#if GTEST_OS_NETBSD
+#undef KERN_PROC
+#define KERN_PROC KERN_PROC2
+#define kinfo_proc kinfo_proc2
+#endif
+
+#if GTEST_OS_DRAGONFLY
+#define KP_NLWP(kp) (kp.kp_nthreads)
+#elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
+#define KP_NLWP(kp) (kp.ki_numthreads)
+#elif GTEST_OS_NETBSD
+#define KP_NLWP(kp) (kp.p_nlwps)
+#endif
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ int mib[] = {
+ CTL_KERN,
+ KERN_PROC,
+ KERN_PROC_PID,
+ getpid(),
+#if GTEST_OS_NETBSD
+ sizeof(struct kinfo_proc),
+ 1,
+#endif
+ };
+ u_int miblen = sizeof(mib) / sizeof(mib[0]);
+ struct kinfo_proc info;
+ size_t size = sizeof(info);
+ if (sysctl(mib, miblen, &info, &size, NULL, 0)) {
+ return 0;
+ }
+ return static_cast<size_t>(KP_NLWP(info));
+}
+#elif GTEST_OS_OPENBSD
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ int mib[] = {
+ CTL_KERN,
+ KERN_PROC,
+ KERN_PROC_PID | KERN_PROC_SHOW_THREADS,
+ getpid(),
+ sizeof(struct kinfo_proc),
+ 0,
+ };
+ u_int miblen = sizeof(mib) / sizeof(mib[0]);
+
+ // get number of structs
+ size_t size;
+ if (sysctl(mib, miblen, NULL, &size, NULL, 0)) {
+ return 0;
+ }
+
+ mib[5] = static_cast<int>(size / static_cast<size_t>(mib[4]));
+
+ // populate array of structs
+ struct kinfo_proc info[mib[5]];
+ if (sysctl(mib, miblen, &info, &size, NULL, 0)) {
+ return 0;
+ }
+
+ // exclude empty members
+ size_t nthreads = 0;
+ for (size_t i = 0; i < size / static_cast<size_t>(mib[4]); i++) {
+ if (info[i].p_tid != -1) nthreads++;
+ }
+ return nthreads;
+}
+
+#elif GTEST_OS_QNX
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ const int fd = open("/proc/self/as", O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+ procfs_info process_info;
+ const int status =
+ devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr);
+ close(fd);
+ if (status == EOK) {
+ return static_cast<size_t>(process_info.num_threads);
+ } else {
+ return 0;
+ }
+}
+
+#elif GTEST_OS_AIX
+
+size_t GetThreadCount() {
+ struct procentry64 entry;
+ pid_t pid = getpid();
+ int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1);
+ if (status == 1) {
+ return entry.pi_thcount;
+ } else {
+ return 0;
+ }
+}
+
+#elif GTEST_OS_FUCHSIA
+
+size_t GetThreadCount() {
+ int dummy_buffer;
+ size_t avail;
+ zx_status_t status =
+ zx_object_get_info(zx_process_self(), ZX_INFO_PROCESS_THREADS,
+ &dummy_buffer, 0, nullptr, &avail);
+ if (status == ZX_OK) {
+ return avail;
+ } 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_LINUX
+
+#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
+
+AutoHandle::AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
+
+AutoHandle::AutoHandle(Handle handle) : handle_(handle) {}
+
+AutoHandle::~AutoHandle() { Reset(); }
+
+AutoHandle::Handle AutoHandle::Get() const { return handle_; }
+
+void AutoHandle::Reset() { Reset(INVALID_HANDLE_VALUE); }
+
+void AutoHandle::Reset(HANDLE handle) {
+ // Resetting with the same handle we already own is invalid.
+ if (handle_ != handle) {
+ if (IsCloseable()) {
+ ::CloseHandle(handle_);
+ }
+ handle_ = handle;
+ } else {
+ GTEST_CHECK_(!IsCloseable())
+ << "Resetting a valid handle to itself is likely a programmer error "
+ "and thus not allowed.";
+ }
+}
+
+bool AutoHandle::IsCloseable() const {
+ // Different Windows APIs may use either of these values to represent an
+ // invalid handle.
+ return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE;
+}
+
+Mutex::Mutex()
+ : owner_thread_id_(0),
+ type_(kDynamic),
+ critical_section_init_phase_(0),
+ critical_section_(new CRITICAL_SECTION) {
+ ::InitializeCriticalSection(critical_section_);
+}
+
+Mutex::~Mutex() {
+ // Static mutexes are leaked intentionally. It is not thread-safe to try
+ // to clean them up.
+ if (type_ == kDynamic) {
+ ::DeleteCriticalSection(critical_section_);
+ delete critical_section_;
+ critical_section_ = nullptr;
+ }
+}
+
+void Mutex::Lock() {
+ ThreadSafeLazyInit();
+ ::EnterCriticalSection(critical_section_);
+ owner_thread_id_ = ::GetCurrentThreadId();
+}
+
+void Mutex::Unlock() {
+ ThreadSafeLazyInit();
+ // We don't protect writing to owner_thread_id_ here, as it's the
+ // caller's responsibility to ensure that the current thread holds the
+ // mutex when this is called.
+ owner_thread_id_ = 0;
+ ::LeaveCriticalSection(critical_section_);
+}
+
+// Does nothing if the current thread holds the mutex. Otherwise, crashes
+// with high probability.
+void Mutex::AssertHeld() {
+ ThreadSafeLazyInit();
+ GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId())
+ << "The current thread is not holding the mutex @" << this;
+}
+
+namespace {
+
+#ifdef _MSC_VER
+// Use the RAII idiom to flag mem allocs that are intentionally never
+// deallocated. The motivation is to silence the false positive mem leaks
+// that are reported by the debug version of MS's CRT which can only detect
+// if an alloc is missing a matching deallocation.
+// Example:
+// MemoryIsNotDeallocated memory_is_not_deallocated;
+// critical_section_ = new CRITICAL_SECTION;
+//
+class MemoryIsNotDeallocated {
+ public:
+ MemoryIsNotDeallocated() : old_crtdbg_flag_(0) {
+ old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT
+ // doesn't report mem leak if there's no matching deallocation.
+ (void)_CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF);
+ }
+
+ ~MemoryIsNotDeallocated() {
+ // Restore the original _CRTDBG_ALLOC_MEM_DF flag
+ (void)_CrtSetDbgFlag(old_crtdbg_flag_);
+ }
+
+ private:
+ int old_crtdbg_flag_;
+
+ MemoryIsNotDeallocated(const MemoryIsNotDeallocated&) = delete;
+ MemoryIsNotDeallocated& operator=(const MemoryIsNotDeallocated&) = delete;
+};
+#endif // _MSC_VER
+
+} // namespace
+
+// Initializes owner_thread_id_ and critical_section_ in static mutexes.
+void Mutex::ThreadSafeLazyInit() {
+ // Dynamic mutexes are initialized in the constructor.
+ if (type_ == kStatic) {
+ switch (
+ ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) {
+ case 0:
+ // If critical_section_init_phase_ was 0 before the exchange, we
+ // are the first to test it and need to perform the initialization.
+ owner_thread_id_ = 0;
+ {
+ // Use RAII to flag that following mem alloc is never deallocated.
+#ifdef _MSC_VER
+ MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif // _MSC_VER
+ critical_section_ = new CRITICAL_SECTION;
+ }
+ ::InitializeCriticalSection(critical_section_);
+ // Updates the critical_section_init_phase_ to 2 to signal
+ // initialization complete.
+ GTEST_CHECK_(::InterlockedCompareExchange(&critical_section_init_phase_,
+ 2L, 1L) == 1L);
+ break;
+ case 1:
+ // Somebody else is already initializing the mutex; spin until they
+ // are done.
+ while (::InterlockedCompareExchange(&critical_section_init_phase_, 2L,
+ 2L) != 2L) {
+ // Possibly yields the rest of the thread's time slice to other
+ // threads.
+ ::Sleep(0);
+ }
+ break;
+
+ case 2:
+ break; // The mutex is already initialized and ready for use.
+
+ default:
+ GTEST_CHECK_(false)
+ << "Unexpected value of critical_section_init_phase_ "
+ << "while initializing a static mutex.";
+ }
+ }
+}
+
+namespace {
+
+class ThreadWithParamSupport : public ThreadWithParamBase {
+ public:
+ static HANDLE CreateThread(Runnable* runnable,
+ Notification* thread_can_start) {
+ ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start);
+ DWORD thread_id;
+ HANDLE thread_handle = ::CreateThread(
+ nullptr, // Default security.
+ 0, // Default stack size.
+ &ThreadWithParamSupport::ThreadMain,
+ param, // Parameter to ThreadMainStatic
+ 0x0, // Default creation flags.
+ &thread_id); // Need a valid pointer for the call to work under Win98.
+ GTEST_CHECK_(thread_handle != nullptr)
+ << "CreateThread failed with error " << ::GetLastError() << ".";
+ if (thread_handle == nullptr) {
+ delete param;
+ }
+ return thread_handle;
+ }
+
+ private:
+ struct ThreadMainParam {
+ ThreadMainParam(Runnable* runnable, Notification* thread_can_start)
+ : runnable_(runnable), thread_can_start_(thread_can_start) {}
+ std::unique_ptr<Runnable> runnable_;
+ // Does not own.
+ Notification* thread_can_start_;
+ };
+
+ static DWORD WINAPI ThreadMain(void* ptr) {
+ // Transfers ownership.
+ std::unique_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
+ if (param->thread_can_start_ != nullptr)
+ param->thread_can_start_->WaitForNotification();
+ param->runnable_->Run();
+ return 0;
+ }
+
+ // Prohibit instantiation.
+ ThreadWithParamSupport();
+
+ ThreadWithParamSupport(const ThreadWithParamSupport&) = delete;
+ ThreadWithParamSupport& operator=(const ThreadWithParamSupport&) = delete;
+};
+
+} // namespace
+
+ThreadWithParamBase::ThreadWithParamBase(Runnable* runnable,
+ Notification* thread_can_start)
+ : thread_(
+ ThreadWithParamSupport::CreateThread(runnable, thread_can_start)) {}
+
+ThreadWithParamBase::~ThreadWithParamBase() { Join(); }
+
+void ThreadWithParamBase::Join() {
+ GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0)
+ << "Failed to join the thread with error " << ::GetLastError() << ".";
+}
+
+// Maps a thread to a set of ThreadIdToThreadLocals that have values
+// instantiated on that thread and notifies them when the thread exits. A
+// ThreadLocal instance is expected to persist until all threads it has
+// values on have terminated.
+class ThreadLocalRegistryImpl {
+ public:
+ // Registers thread_local_instance as having value on the current thread.
+ // Returns a value that can be used to identify the thread from other threads.
+ static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance) {
+#ifdef _MSC_VER
+ MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif // _MSC_VER
+ DWORD current_thread = ::GetCurrentThreadId();
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ ThreadIdToThreadLocals::iterator thread_local_pos =
+ thread_to_thread_locals->find(current_thread);
+ if (thread_local_pos == thread_to_thread_locals->end()) {
+ thread_local_pos =
+ thread_to_thread_locals
+ ->insert(std::make_pair(current_thread, ThreadLocalValues()))
+ .first;
+ StartWatcherThreadFor(current_thread);
+ }
+ ThreadLocalValues& thread_local_values = thread_local_pos->second;
+ ThreadLocalValues::iterator value_pos =
+ thread_local_values.find(thread_local_instance);
+ if (value_pos == thread_local_values.end()) {
+ value_pos =
+ thread_local_values
+ .insert(std::make_pair(
+ thread_local_instance,
+ std::shared_ptr<ThreadLocalValueHolderBase>(
+ thread_local_instance->NewValueForCurrentThread())))
+ .first;
+ }
+ return value_pos->second.get();
+ }
+
+ static void OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance) {
+ std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
+ // Clean up the ThreadLocalValues data structure while holding the lock, but
+ // defer the destruction of the ThreadLocalValueHolderBases.
+ {
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ for (ThreadIdToThreadLocals::iterator it =
+ thread_to_thread_locals->begin();
+ it != thread_to_thread_locals->end(); ++it) {
+ ThreadLocalValues& thread_local_values = it->second;
+ ThreadLocalValues::iterator value_pos =
+ thread_local_values.find(thread_local_instance);
+ if (value_pos != thread_local_values.end()) {
+ value_holders.push_back(value_pos->second);
+ thread_local_values.erase(value_pos);
+ // This 'if' can only be successful at most once, so theoretically we
+ // could break out of the loop here, but we don't bother doing so.
+ }
+ }
+ }
+ // Outside the lock, let the destructor for 'value_holders' deallocate the
+ // ThreadLocalValueHolderBases.
+ }
+
+ static void OnThreadExit(DWORD thread_id) {
+ GTEST_CHECK_(thread_id != 0) << ::GetLastError();
+ std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
+ // Clean up the ThreadIdToThreadLocals data structure while holding the
+ // lock, but defer the destruction of the ThreadLocalValueHolderBases.
+ {
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ ThreadIdToThreadLocals::iterator thread_local_pos =
+ thread_to_thread_locals->find(thread_id);
+ if (thread_local_pos != thread_to_thread_locals->end()) {
+ ThreadLocalValues& thread_local_values = thread_local_pos->second;
+ for (ThreadLocalValues::iterator value_pos =
+ thread_local_values.begin();
+ value_pos != thread_local_values.end(); ++value_pos) {
+ value_holders.push_back(value_pos->second);
+ }
+ thread_to_thread_locals->erase(thread_local_pos);
+ }
+ }
+ // Outside the lock, let the destructor for 'value_holders' deallocate the
+ // ThreadLocalValueHolderBases.
+ }
+
+ private:
+ // In a particular thread, maps a ThreadLocal object to its value.
+ typedef std::map<const ThreadLocalBase*,
+ std::shared_ptr<ThreadLocalValueHolderBase> >
+ ThreadLocalValues;
+ // Stores all ThreadIdToThreadLocals having values in a thread, indexed by
+ // thread's ID.
+ typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
+
+ // Holds the thread id and thread handle that we pass from
+ // StartWatcherThreadFor to WatcherThreadFunc.
+ typedef std::pair<DWORD, HANDLE> ThreadIdAndHandle;
+
+ static void StartWatcherThreadFor(DWORD thread_id) {
+ // The returned handle will be kept in thread_map and closed by
+ // watcher_thread in WatcherThreadFunc.
+ HANDLE thread =
+ ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, thread_id);
+ GTEST_CHECK_(thread != nullptr);
+ // We need to pass a valid thread ID pointer into CreateThread for it
+ // to work correctly under Win98.
+ DWORD watcher_thread_id;
+ HANDLE watcher_thread = ::CreateThread(
+ nullptr, // Default security.
+ 0, // Default stack size
+ &ThreadLocalRegistryImpl::WatcherThreadFunc,
+ reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)),
+ CREATE_SUSPENDED, &watcher_thread_id);
+ GTEST_CHECK_(watcher_thread != nullptr)
+ << "CreateThread failed with error " << ::GetLastError() << ".";
+ // Give the watcher thread the same priority as ours to avoid being
+ // blocked by it.
+ ::SetThreadPriority(watcher_thread,
+ ::GetThreadPriority(::GetCurrentThread()));
+ ::ResumeThread(watcher_thread);
+ ::CloseHandle(watcher_thread);
+ }
+
+ // Monitors exit from a given thread and notifies those
+ // ThreadIdToThreadLocals about thread termination.
+ static DWORD WINAPI WatcherThreadFunc(LPVOID param) {
+ const ThreadIdAndHandle* tah =
+ reinterpret_cast<const ThreadIdAndHandle*>(param);
+ GTEST_CHECK_(::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0);
+ OnThreadExit(tah->first);
+ ::CloseHandle(tah->second);
+ delete tah;
+ return 0;
+ }
+
+ // Returns map of thread local instances.
+ static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
+ mutex_.AssertHeld();
+#ifdef _MSC_VER
+ MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif // _MSC_VER
+ static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals();
+ return map;
+ }
+
+ // Protects access to GetThreadLocalsMapLocked() and its return value.
+ static Mutex mutex_;
+ // Protects access to GetThreadMapLocked() and its return value.
+ static Mutex thread_map_mutex_;
+};
+
+Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); // NOLINT
+Mutex ThreadLocalRegistryImpl::thread_map_mutex_(
+ Mutex::kStaticMutex); // NOLINT
+
+ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance) {
+ return ThreadLocalRegistryImpl::GetValueOnCurrentThread(
+ thread_local_instance);
+}
+
+void ThreadLocalRegistry::OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance) {
+ ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance);
+}
+
+#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
+
+#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<char*>(pattern_));
+}
+
+// Returns true if and only if 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 if and only if 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 if and only if ch appears anywhere in str (excluding the
+// terminating '\0' character).
+bool IsInSet(char ch, const char* str) {
+ return ch != '\0' && strchr(str, ch) != nullptr;
+}
+
+// Returns true if and only if ch belongs to the given classification.
+// Unlike similar functions in <ctype.h>, 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 if and only if "\\c" is a supported escape sequence.
+bool IsValidEscape(char c) {
+ return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
+}
+
+// Returns true if and only if 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.
+static std::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 == nullptr) {
+ ADD_FAILURE() << "NULL is not a valid simple regular expression.";
+ return false;
+ }
+
+ bool is_valid = true;
+
+ // True if and only if ?, *, 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<size_t>(-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 if and only if 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 if and only if 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 == nullptr || str == nullptr) 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<char*>(pattern_));
+ free(const_cast<char*>(full_pattern_));
+}
+
+// Returns true if and only if 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 if and only if 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_ = nullptr;
+ if (regex != nullptr) {
+ 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<char*>(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 std::string file_name(file == nullptr ? kUnknownFile : file);
+
+ if (line < 0) {
+ return file_name + ":";
+ }
+#ifdef _MSC_VER
+ return file_name + "(" + StreamableToString(line) + "):";
+#else
+ return file_name + ":" + StreamableToString(line) + ":";
+#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 std::string file_name(file == nullptr ? kUnknownFile : file);
+
+ if (line < 0)
+ return file_name;
+ else
+ return file_name + ":" + StreamableToString(line);
+}
+
+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)
+GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
+
+#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.
+ explicit 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 a temporary directory.
+ std::string name_template;
+
+#if GTEST_OS_LINUX_ANDROID
+ // Note: Android applications are expected to call the framework's
+ // Context.getExternalStorageDirectory() method through JNI to get
+ // the location of the world-writable SD Card directory. However,
+ // this requires a Context handle, which cannot be retrieved
+ // globally from native code. Doing so also precludes running the
+ // code as part of a regular standalone executable, which doesn't
+ // run in a Dalvik process (e.g. when running it through 'adb shell').
+ //
+ // The location /data/local/tmp is directly accessible from native code.
+ // '/sdcard' and other variants cannot be relied on, as they are not
+ // guaranteed to be mounted, or may have a delay in mounting.
+ name_template = "/data/local/tmp/";
+#elif GTEST_OS_IOS
+ char user_temp_dir[PATH_MAX + 1];
+
+ // Documented alternative to NSTemporaryDirectory() (for obtaining creating
+ // a temporary directory) at
+ // https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10
+ //
+ // _CS_DARWIN_USER_TEMP_DIR (as well as _CS_DARWIN_USER_CACHE_DIR) is not
+ // documented in the confstr() man page at
+ // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/confstr.3.html#//apple_ref/doc/man/3/confstr
+ // but are still available, according to the WebKit patches at
+ // https://trac.webkit.org/changeset/262004/webkit
+ // https://trac.webkit.org/changeset/263705/webkit
+ //
+ // The confstr() implementation falls back to getenv("TMPDIR"). See
+ // https://opensource.apple.com/source/Libc/Libc-1439.100.3/gen/confstr.c.auto.html
+ ::confstr(_CS_DARWIN_USER_TEMP_DIR, user_temp_dir, sizeof(user_temp_dir));
+
+ name_template = user_temp_dir;
+ if (name_template.back() != GTEST_PATH_SEP_[0])
+ name_template.push_back(GTEST_PATH_SEP_[0]);
+#else
+ name_template = "/tmp/";
+#endif
+ name_template.append("gtest_captured_stream.XXXXXX");
+
+ // mkstemp() modifies the string bytes in place, and does not go beyond the
+ // string's length. This results in well-defined behavior in C++17.
+ //
+ // The const_cast is needed below C++17. The constraints on std::string
+ // implementations in C++11 and above make assumption behind the const_cast
+ // fairly safe.
+ const int captured_fd = ::mkstemp(const_cast<char*>(name_template.data()));
+ if (captured_fd == -1) {
+ GTEST_LOG_(WARNING)
+ << "Failed to create tmp file " << name_template
+ << " for test; does the test have access to the /tmp directory?";
+ }
+ filename_ = std::move(name_template);
+#endif // GTEST_OS_WINDOWS
+ fflush(nullptr);
+ dup2(captured_fd, fd_);
+ close(captured_fd);
+ }
+
+ ~CapturedStream() { remove(filename_.c_str()); }
+
+ std::string GetCapturedString() {
+ if (uncaptured_fd_ != -1) {
+ // Restores the original stream.
+ fflush(nullptr);
+ dup2(uncaptured_fd_, fd_);
+ close(uncaptured_fd_);
+ uncaptured_fd_ = -1;
+ }
+
+ FILE* const file = posix::FOpen(filename_.c_str(), "r");
+ if (file == nullptr) {
+ GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_
+ << " for capturing stream.";
+ }
+ const std::string content = ReadEntireFile(file);
+ posix::FClose(file);
+ return content;
+ }
+
+ private:
+ const int fd_; // A stream to capture.
+ int uncaptured_fd_;
+ // Name of the temporary file holding the stderr output.
+ ::std::string filename_;
+
+ CapturedStream(const CapturedStream&) = delete;
+ CapturedStream& operator=(const CapturedStream&) = delete;
+};
+
+GTEST_DISABLE_MSC_DEPRECATED_POP_()
+
+static CapturedStream* g_captured_stderr = nullptr;
+static CapturedStream* g_captured_stdout = nullptr;
+
+// Starts capturing an output stream (stdout/stderr).
+static void CaptureStream(int fd, const char* stream_name,
+ CapturedStream** stream) {
+ if (*stream != nullptr) {
+ 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.
+static std::string GetCapturedStream(CapturedStream** captured_stream) {
+ const std::string content = (*captured_stream)->GetCapturedString();
+
+ delete *captured_stream;
+ *captured_stream = nullptr;
+
+ return content;
+}
+
+#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 // defined(_MSC_VER) || defined(__BORLANDC__)
+
+// 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.
+std::string GetCapturedStdout() {
+ return GetCapturedStream(&g_captured_stdout);
+}
+
+// Stops capturing stderr and returns the captured string.
+std::string GetCapturedStderr() {
+ return GetCapturedStream(&g_captured_stderr);
+}
+
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+size_t GetFileSize(FILE* file) {
+ fseek(file, 0, SEEK_END);
+ return static_cast<size_t>(ftell(file));
+}
+
+std::string 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 std::string content(buffer, bytes_read);
+ delete[] buffer;
+
+ return content;
+}
+
+#if GTEST_HAS_DEATH_TEST
+static const std::vector<std::string>* g_injected_test_argvs =
+ nullptr; // Owned.
+
+std::vector<std::string> GetInjectableArgvs() {
+ if (g_injected_test_argvs != nullptr) {
+ return *g_injected_test_argvs;
+ }
+ return GetArgvs();
+}
+
+void SetInjectableArgvs(const std::vector<std::string>* new_argvs) {
+ if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs;
+ g_injected_test_argvs = new_argvs;
+}
+
+void SetInjectableArgvs(const std::vector<std::string>& new_argvs) {
+ SetInjectableArgvs(
+ new std::vector<std::string>(new_argvs.begin(), new_argvs.end()));
+}
+
+void ClearInjectableArgvs() {
+ delete g_injected_test_argvs;
+ g_injected_test_argvs = nullptr;
+}
+#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 std::string FlagToEnvVar(const char* flag) {
+ const std::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_t* value) {
+ // Parses the environment variable as a decimal integer.
+ char* end = nullptr;
+ 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_t?
+ const auto result = static_cast<int32_t>(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_t.
+ ) {
+ 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 if and only if it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+#if defined(GTEST_GET_BOOL_FROM_ENV_)
+ return GTEST_GET_BOOL_FROM_ENV_(flag, default_value);
+#else
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ return string_value == nullptr ? default_value
+ : strcmp(string_value, "0") != 0;
+#endif // defined(GTEST_GET_BOOL_FROM_ENV_)
+}
+
+// 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_t Int32FromGTestEnv(const char* flag, int32_t default_value) {
+#if defined(GTEST_GET_INT32_FROM_ENV_)
+ return GTEST_GET_INT32_FROM_ENV_(flag, default_value);
+#else
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ if (string_value == nullptr) {
+ // The environment variable is not set.
+ return default_value;
+ }
+
+ int32_t 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;
+#endif // defined(GTEST_GET_INT32_FROM_ENV_)
+}
+
+// As a special case for the 'output' flag, if GTEST_OUTPUT is not
+// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build
+// system. The value of XML_OUTPUT_FILE is a filename without the
+// "xml:" prefix of GTEST_OUTPUT.
+// Note that this is meant to be called at the call site so it does
+// not check that the flag is 'output'
+// In essence this checks an env variable called XML_OUTPUT_FILE
+// and if it is set we prepend "xml:" to its value, if it not set we return ""
+std::string OutputFlagAlsoCheckEnvVar() {
+ std::string default_value_for_output_flag = "";
+ const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE");
+ if (nullptr != xml_output_file_env) {
+ default_value_for_output_flag = std::string("xml:") + xml_output_file_env;
+ }
+ return default_value_for_output_flag;
+}
+
+// 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) {
+#if defined(GTEST_GET_STRING_FROM_ENV_)
+ return GTEST_GET_STRING_FROM_ENV_(flag, default_value);
+#else
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const value = posix::GetEnv(env_var.c_str());
+ return value == nullptr ? default_value : value;
+#endif // defined(GTEST_GET_STRING_FROM_ENV_)
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-printers.cc b/libs/cpp-httplib/test/gtest/src/gtest-printers.cc
new file mode 100644
index 0000000..f3976d2
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-printers.cc
@@ -0,0 +1,553 @@
+// 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.
+
+// Google Test - The Google C++ Testing and Mocking Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+// void ::testing::internal::UniversalPrinter<T>::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 "gtest/gtest-printers.h"
+
+#include <stdio.h>
+
+#include <cctype>
+#include <cstdint>
+#include <cwchar>
+#include <ostream> // NOLINT
+#include <string>
+#include <type_traits>
+
+#include "gtest/internal/gtest-port.h"
+#include "src/gtest-internal-inl.h"
+
+namespace testing {
+
+namespace {
+
+using ::std::ostream;
+
+// Prints a segment of bytes in the given object.
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+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 << '-';
+ }
+ GTEST_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.
+ 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 << ">";
+}
+
+// Helpers for widening a character to char32_t. Since the standard does not
+// specify if char / wchar_t is signed or unsigned, it is important to first
+// convert it to the unsigned type of the same width before widening it to
+// char32_t.
+template <typename CharType>
+char32_t ToChar32(CharType in) {
+ return static_cast<char32_t>(
+ static_cast<typename std::make_unsigned<CharType>::type>(in));
+}
+
+} // namespace
+
+namespace internal {
+
+// 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);
+}
+
+// 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 hexadecimal 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(char32_t c) { return 0x20 <= c && c <= 0x7E; }
+
+// Prints c (of type char, char8_t, char16_t, char32_t, or wchar_t) as a
+// character literal without the quotes, escaping it when necessary; returns how
+// c was formatted.
+template <typename Char>
+static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
+ const char32_t u_c = ToChar32(c);
+ switch (u_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(u_c)) {
+ *os << static_cast<char>(c);
+ return kAsIs;
+ } else {
+ ostream::fmtflags flags = os->flags();
+ *os << "\\x" << std::hex << std::uppercase << static_cast<int>(u_c);
+ os->flags(flags);
+ return kHexEscape;
+ }
+ }
+ return kSpecialEscape;
+}
+
+// Prints a char32_t c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(char32_t c, ostream* os) {
+ switch (c) {
+ case L'\'':
+ *os << "'";
+ return kAsIs;
+ case L'"':
+ *os << "\\\"";
+ return kSpecialEscape;
+ default:
+ return PrintAsCharLiteralTo(c, os);
+ }
+}
+
+static const char* GetCharWidthPrefix(char) { return ""; }
+
+static const char* GetCharWidthPrefix(signed char) { return ""; }
+
+static const char* GetCharWidthPrefix(unsigned char) { return ""; }
+
+#ifdef __cpp_char8_t
+static const char* GetCharWidthPrefix(char8_t) { return "u8"; }
+#endif
+
+static const char* GetCharWidthPrefix(char16_t) { return "u"; }
+
+static const char* GetCharWidthPrefix(char32_t) { return "U"; }
+
+static const char* GetCharWidthPrefix(wchar_t) { return "L"; }
+
+// Prints a char c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
+ return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+
+#ifdef __cpp_char8_t
+static CharFormat PrintAsStringLiteralTo(char8_t c, ostream* os) {
+ return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+#endif
+
+static CharFormat PrintAsStringLiteralTo(char16_t c, ostream* os) {
+ return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+
+static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
+ return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+
+// Prints a character c (of type char, char8_t, char16_t, char32_t, or wchar_t)
+// and its code. '\0' is printed as "'\\0'", other unprintable characters are
+// also properly escaped using the standard C++ escape sequence.
+template <typename Char>
+void PrintCharAndCodeTo(Char c, ostream* os) {
+ // First, print c as a literal in the most readable form we can find.
+ *os << GetCharWidthPrefix(c) << "'";
+ 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 << " (" << static_cast<int>(c);
+
+ // For more convenience, we print c's code again in hexadecimal,
+ // 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 << ", 0x" << String::FormatHexInt(static_cast<int>(c));
+ }
+ *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); }
+
+// TODO(dcheng): Consider making this delegate to PrintCharAndCodeTo() as well.
+void PrintTo(char32_t c, ::std::ostream* os) {
+ *os << std::hex << "U+" << std::uppercase << std::setfill('0') << std::setw(4)
+ << static_cast<uint32_t>(c);
+}
+
+// gcc/clang __{u,}int128_t
+#if defined(__SIZEOF_INT128__)
+void PrintTo(__uint128_t v, ::std::ostream* os) {
+ if (v == 0) {
+ *os << "0";
+ return;
+ }
+
+ // Buffer large enough for ceil(log10(2^128))==39 and the null terminator
+ char buf[40];
+ char* p = buf + sizeof(buf);
+
+ // Some configurations have a __uint128_t, but no support for built in
+ // division. Do manual long division instead.
+
+ uint64_t high = static_cast<uint64_t>(v >> 64);
+ uint64_t low = static_cast<uint64_t>(v);
+
+ *--p = 0;
+ while (high != 0 || low != 0) {
+ uint64_t high_mod = high % 10;
+ high = high / 10;
+ // This is the long division algorithm specialized for a divisor of 10 and
+ // only two elements.
+ // Notable values:
+ // 2^64 / 10 == 1844674407370955161
+ // 2^64 % 10 == 6
+ const uint64_t carry = 6 * high_mod + low % 10;
+ low = low / 10 + high_mod * 1844674407370955161 + carry / 10;
+
+ char digit = static_cast<char>(carry % 10);
+ *--p = '0' + digit;
+ }
+ *os << p;
+}
+void PrintTo(__int128_t v, ::std::ostream* os) {
+ __uint128_t uv = static_cast<__uint128_t>(v);
+ if (v < 0) {
+ *os << "-";
+ uv = -uv;
+ }
+ PrintTo(uv, os);
+}
+#endif // __SIZEOF_INT128__
+
+// Prints the given array of characters to the ostream. CharType must be either
+// char, char8_t, char16_t, char32_t, or wchar_t.
+// The array starts at begin, the length is len, it may include '\0' characters
+// and may not be NUL-terminated.
+template <typename CharType>
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat
+ PrintCharsAsStringTo(const CharType* begin, size_t len, ostream* os) {
+ const char* const quote_prefix = GetCharWidthPrefix(*begin);
+ *os << quote_prefix << "\"";
+ bool is_previous_hex = false;
+ CharFormat print_format = kAsIs;
+ for (size_t index = 0; index < len; ++index) {
+ const CharType 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 << "\" " << quote_prefix << "\"";
+ }
+ is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
+ // Remember if any characters required hex escaping.
+ if (is_previous_hex) {
+ print_format = kHexEscape;
+ }
+ }
+ *os << "\"";
+ return print_format;
+}
+
+// Prints a (const) char/wchar_t array of 'len' elements, starting at address
+// 'begin'. CharType must be either char or wchar_t.
+template <typename CharType>
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void
+ UniversalPrintCharArray(const CharType* begin, size_t len,
+ ostream* os) {
+ // The code
+ // const char kFoo[] = "foo";
+ // generates an array of 4, not 3, elements, with the last one being '\0'.
+ //
+ // Therefore when printing a char array, we don't print the last element if
+ // it's '\0', such that the output matches the string literal as it's
+ // written in the source code.
+ if (len > 0 && begin[len - 1] == '\0') {
+ PrintCharsAsStringTo(begin, len - 1, os);
+ return;
+ }
+
+ // If, however, the last element in the array is not '\0', e.g.
+ // const char kFoo[] = { 'f', 'o', 'o' };
+ // we must print the entire array. We also print a message to indicate
+ // that the array is not NUL-terminated.
+ PrintCharsAsStringTo(begin, len, os);
+ *os << " (no terminating NUL)";
+}
+
+// Prints a (const) char array of 'len' elements, starting at address 'begin'.
+void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+
+#ifdef __cpp_char8_t
+// Prints a (const) char8_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char8_t* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+#endif
+
+// Prints a (const) char16_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char16_t* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints a (const) char32_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char32_t* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints a (const) wchar_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+
+namespace {
+
+// Prints a null-terminated C-style string to the ostream.
+template <typename Char>
+void PrintCStringTo(const Char* s, ostream* os) {
+ if (s == nullptr) {
+ *os << "NULL";
+ } else {
+ *os << ImplicitCast_<const void*>(s) << " pointing to ";
+ PrintCharsAsStringTo(s, std::char_traits<Char>::length(s), os);
+ }
+}
+
+} // anonymous namespace
+
+void PrintTo(const char* s, ostream* os) { PrintCStringTo(s, os); }
+
+#ifdef __cpp_char8_t
+void PrintTo(const char8_t* s, ostream* os) { PrintCStringTo(s, os); }
+#endif
+
+void PrintTo(const char16_t* s, ostream* os) { PrintCStringTo(s, os); }
+
+void PrintTo(const char32_t* s, ostream* os) { PrintCStringTo(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) { PrintCStringTo(s, os); }
+#endif // wchar_t is native
+
+namespace {
+
+bool ContainsUnprintableControlCodes(const char* str, size_t length) {
+ const unsigned char* s = reinterpret_cast<const unsigned char*>(str);
+
+ for (size_t i = 0; i < length; i++) {
+ unsigned char ch = *s++;
+ if (std::iscntrl(ch)) {
+ switch (ch) {
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ default:
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t <= 0xbf; }
+
+bool IsValidUTF8(const char* str, size_t length) {
+ const unsigned char* s = reinterpret_cast<const unsigned char*>(str);
+
+ for (size_t i = 0; i < length;) {
+ unsigned char lead = s[i++];
+
+ if (lead <= 0x7f) {
+ continue; // single-byte character (ASCII) 0..7F
+ }
+ if (lead < 0xc2) {
+ return false; // trail byte or non-shortest form
+ } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) {
+ ++i; // 2-byte character
+ } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length &&
+ IsUTF8TrailByte(s[i]) && IsUTF8TrailByte(s[i + 1]) &&
+ // check for non-shortest form and surrogate
+ (lead != 0xe0 || s[i] >= 0xa0) &&
+ (lead != 0xed || s[i] < 0xa0)) {
+ i += 2; // 3-byte character
+ } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length &&
+ IsUTF8TrailByte(s[i]) && IsUTF8TrailByte(s[i + 1]) &&
+ IsUTF8TrailByte(s[i + 2]) &&
+ // check for non-shortest form
+ (lead != 0xf0 || s[i] >= 0x90) &&
+ (lead != 0xf4 || s[i] < 0x90)) {
+ i += 3; // 4-byte character
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ConditionalPrintAsText(const char* str, size_t length, ostream* os) {
+ if (!ContainsUnprintableControlCodes(str, length) &&
+ IsValidUTF8(str, length)) {
+ *os << "\n As Text: \"" << str << "\"";
+ }
+}
+
+} // anonymous namespace
+
+void PrintStringTo(const ::std::string& s, ostream* os) {
+ if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) {
+ if (GTEST_FLAG_GET(print_utf8)) {
+ ConditionalPrintAsText(s.data(), s.size(), os);
+ }
+ }
+}
+
+#ifdef __cpp_char8_t
+void PrintU8StringTo(const ::std::u8string& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif
+
+void PrintU16StringTo(const ::std::u16string& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+void PrintU32StringTo(const ::std::u32string& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+#if GTEST_HAS_STD_WSTRING
+void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+} // namespace internal
+
+} // namespace testing
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-test-part.cc b/libs/cpp-httplib/test/gtest/src/gtest-test-part.cc
new file mode 100644
index 0000000..eb7c8d1
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-test-part.cc
@@ -0,0 +1,105 @@
+// 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.
+
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+
+#include "gtest/gtest-test-part.h"
+
+#include "gtest/internal/gtest-port.h"
+#include "src/gtest-internal-inl.h"
+
+namespace testing {
+
+using internal::GetUnitTestImpl;
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+std::string TestPartResult::ExtractSummary(const char* message) {
+ const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+ return stack_trace == nullptr ? message : std::string(message, stack_trace);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+ return os << internal::FormatFileLocation(result.file_name(),
+ result.line_number())
+ << " "
+ << (result.type() == TestPartResult::kSuccess ? "Success"
+ : result.type() == TestPartResult::kSkip ? "Skipped"
+ : 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_[static_cast<size_t>(index)];
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+ return static_cast<int>(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
diff --git a/libs/cpp-httplib/test/gtest/src/gtest-typed-test.cc b/libs/cpp-httplib/test/gtest/src/gtest-typed-test.cc
new file mode 100644
index 0000000..a2828b8
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest-typed-test.cc
@@ -0,0 +1,104 @@
+// 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.
+
+#include "gtest/gtest-typed-test.h"
+
+#include "gtest/gtest.h"
+
+namespace testing {
+namespace internal {
+
+// 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;
+}
+
+static std::vector<std::string> SplitIntoTestNames(const char* src) {
+ std::vector<std::string> name_vec;
+ src = SkipSpaces(src);
+ for (; src != nullptr; src = SkipComma(src)) {
+ name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src)));
+ }
+ return name_vec;
+}
+
+// Verifies that registered_tests match the test names in
+// registered_tests_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestSuitePState::VerifyRegisteredTestNames(
+ const char* test_suite_name, const char* file, int line,
+ const char* registered_tests) {
+ RegisterTypeParameterizedTestSuite(test_suite_name, CodeLocation(file, line));
+
+ typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
+ registered_ = true;
+
+ std::vector<std::string> name_vec = SplitIntoTestNames(registered_tests);
+
+ Message errors;
+
+ std::set<std::string> tests;
+ for (std::vector<std::string>::const_iterator name_it = name_vec.begin();
+ name_it != name_vec.end(); ++name_it) {
+ const std::string& name = *name_it;
+ if (tests.count(name) != 0) {
+ errors << "Test " << name << " is listed more than once.\n";
+ continue;
+ }
+
+ if (registered_tests_.count(name) != 0) {
+ tests.insert(name);
+ } else {
+ errors << "No test named " << name
+ << " can be found in this test suite.\n";
+ }
+ }
+
+ for (RegisteredTestIter it = registered_tests_.begin();
+ it != registered_tests_.end(); ++it) {
+ if (tests.count(it->first) == 0) {
+ errors << "You forgot to list test " << it->first << ".\n";
+ }
+ }
+
+ const std::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;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/libs/cpp-httplib/test/gtest/src/gtest.cc b/libs/cpp-httplib/test/gtest/src/gtest.cc
new file mode 100644
index 0000000..6f31dd2
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest.cc
@@ -0,0 +1,6795 @@
+// 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.
+
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+
+#include "gtest/gtest.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <chrono> // NOLINT
+#include <cmath>
+#include <cstdint>
+#include <initializer_list>
+#include <iomanip>
+#include <iterator>
+#include <limits>
+#include <list>
+#include <map>
+#include <ostream> // NOLINT
+#include <sstream>
+#include <unordered_set>
+#include <vector>
+
+#include "gtest/gtest-assertion-result.h"
+#include "gtest/gtest-spi.h"
+#include "gtest/internal/custom/gtest.h"
+
+#if GTEST_OS_LINUX
+
+#include <fcntl.h> // NOLINT
+#include <limits.h> // NOLINT
+#include <sched.h> // NOLINT
+// Declares vsnprintf(). This header is not available on Windows.
+#include <strings.h> // NOLINT
+#include <sys/mman.h> // NOLINT
+#include <sys/time.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+#include <string>
+
+#elif GTEST_OS_ZOS
+#include <sys/time.h> // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+#include <strings.h> // NOLINT
+
+#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE.
+
+#include <windows.h> // NOLINT
+#undef min
+
+#elif GTEST_OS_WINDOWS // We are on Windows proper.
+
+#include <windows.h> // NOLINT
+#undef min
+
+#ifdef _MSC_VER
+#include <crtdbg.h> // NOLINT
+#endif
+
+#include <io.h> // NOLINT
+#include <sys/stat.h> // NOLINT
+#include <sys/timeb.h> // NOLINT
+#include <sys/types.h> // NOLINT
+
+#if GTEST_OS_WINDOWS_MINGW
+#include <sys/time.h> // NOLINT
+#endif // GTEST_OS_WINDOWS_MINGW
+
+#else
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <sys/time.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+#include <stdexcept>
+#endif
+
+#if GTEST_CAN_STREAM_RESULTS_
+#include <arpa/inet.h> // NOLINT
+#include <netdb.h> // NOLINT
+#include <sys/socket.h> // NOLINT
+#include <sys/types.h> // NOLINT
+#endif
+
+#include "src/gtest-internal-inl.h"
+
+#if GTEST_OS_WINDOWS
+#define vsnprintf _vsnprintf
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_OS_MAC
+#ifndef GTEST_OS_IOS
+#include <crt_externs.h>
+#endif
+#endif
+
+#if GTEST_HAS_ABSL
+#include "absl/debugging/failure_signal_handler.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/usage.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_replace.h"
+#endif // GTEST_HAS_ABSL
+
+namespace testing {
+
+using internal::CountIf;
+using internal::ForEach;
+using internal::GetElementOr;
+using internal::Shuffle;
+
+// Constants.
+
+// A test whose test suite name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test suite whose name matches this filter is considered a death
+// test suite and will be run before test suites whose name doesn't
+// match this filter.
+static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output format.
+static const char kDefaultOutputFormat[] = "xml";
+// The default output file.
+static const char kDefaultOutputFile[] = "test_detail";
+
+// 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 if and only if the --help flag or an equivalent form
+// is specified on the command line.
+bool g_help_flag = false;
+
+// Utility function to Open File for Writing
+static FILE* OpenFileForWriting(const std::string& output_file) {
+ FILE* fileout = nullptr;
+ FilePath output_file_path(output_file);
+ FilePath output_dir(output_file_path.RemoveFileName());
+
+ if (output_dir.CreateDirectoriesRecursively()) {
+ fileout = posix::FOpen(output_file.c_str(), "w");
+ }
+ if (fileout == nullptr) {
+ GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\"";
+ }
+ return fileout;
+}
+
+} // namespace internal
+
+// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY
+// environment variable.
+static const char* GetDefaultFilter() {
+ const char* const testbridge_test_only =
+ internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY");
+ if (testbridge_test_only != nullptr) {
+ return testbridge_test_only;
+ }
+ return kUniversalFilter;
+}
+
+// Bazel passes in the argument to '--test_runner_fail_fast' via the
+// TESTBRIDGE_TEST_RUNNER_FAIL_FAST environment variable.
+static bool GetDefaultFailFast() {
+ const char* const testbridge_test_runner_fail_fast =
+ internal::posix::GetEnv("TESTBRIDGE_TEST_RUNNER_FAIL_FAST");
+ if (testbridge_test_runner_fail_fast != nullptr) {
+ return strcmp(testbridge_test_runner_fail_fast, "1") == 0;
+ }
+ return false;
+}
+
+} // namespace testing
+
+GTEST_DEFINE_bool_(
+ fail_fast,
+ testing::internal::BoolFromGTestEnv("fail_fast",
+ testing::GetDefaultFailFast()),
+ "True if and only if a test failure should stop further test execution.");
+
+GTEST_DEFINE_bool_(
+ also_run_disabled_tests,
+ testing::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,
+ testing::internal::BoolFromGTestEnv("break_on_failure", false),
+ "True if and only if a failed assertion should be a debugger "
+ "break-point.");
+
+GTEST_DEFINE_bool_(catch_exceptions,
+ testing::internal::BoolFromGTestEnv("catch_exceptions",
+ true),
+ "True if and only if " GTEST_NAME_
+ " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+ color, testing::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 a terminal type that supports colors.");
+
+GTEST_DEFINE_string_(
+ filter,
+ testing::internal::StringFromGTestEnv("filter",
+ testing::GetDefaultFilter()),
+ "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_(
+ install_failure_signal_handler,
+ testing::internal::BoolFromGTestEnv("install_failure_signal_handler",
+ false),
+ "If true and supported on the current platform, " GTEST_NAME_
+ " should "
+ "install a signal handler that dumps debugging information when fatal "
+ "signals are raised.");
+
+GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them.");
+
+// The net priority order after flag processing is thus:
+// --gtest_output command line flag
+// GTEST_OUTPUT environment variable
+// XML_OUTPUT_FILE environment variable
+// ''
+GTEST_DEFINE_string_(
+ output,
+ testing::internal::StringFromGTestEnv(
+ "output", testing::internal::OutputFlagAlsoCheckEnvVar().c_str()),
+ "A format (defaults to \"xml\" but can be specified to be \"json\"), "
+ "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_(
+ brief, testing::internal::BoolFromGTestEnv("brief", false),
+ "True if only test failures should be displayed in text output.");
+
+GTEST_DEFINE_bool_(print_time,
+ testing::internal::BoolFromGTestEnv("print_time", true),
+ "True if and only if " GTEST_NAME_
+ " should display elapsed time in text output.");
+
+GTEST_DEFINE_bool_(print_utf8,
+ testing::internal::BoolFromGTestEnv("print_utf8", true),
+ "True if and only if " GTEST_NAME_
+ " prints UTF8 characters as text.");
+
+GTEST_DEFINE_int32_(
+ random_seed, testing::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, testing::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_(
+ recreate_environments_when_repeating,
+ testing::internal::BoolFromGTestEnv("recreate_environments_when_repeating",
+ false),
+ "Controls whether global test environments are recreated for each repeat "
+ "of the tests. If set to false the global test environments are only set "
+ "up once, for the first iteration, and only torn down once, for the last. "
+ "Useful for shaking out flaky tests with stable, expensive test "
+ "environments. If --gtest_repeat is set to a negative number, meaning "
+ "there is no last run, the environments will always be recreated to avoid "
+ "leaks.");
+
+GTEST_DEFINE_bool_(show_internal_stack_frames, false,
+ "True if and only if " GTEST_NAME_
+ " should include internal stack frames when "
+ "printing test failure stack traces.");
+
+GTEST_DEFINE_bool_(shuffle,
+ testing::internal::BoolFromGTestEnv("shuffle", false),
+ "True if and only if " GTEST_NAME_
+ " should randomize tests' order on every run.");
+
+GTEST_DEFINE_int32_(
+ stack_trace_depth,
+ testing::internal::Int32FromGTestEnv("stack_trace_depth",
+ testing::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,
+ testing::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,
+ testing::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. For use with an external test framework.");
+
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+GTEST_DEFINE_string_(
+ flagfile, testing::internal::StringFromGTestEnv("flagfile", ""),
+ "This flag specifies the flagfile to read command-line flags from.");
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
+namespace testing {
+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_t Random::Generate(uint32_t range) {
+ // These constants are the same as are used in glibc's rand(3).
+ // Use wider types than necessary to prevent unsigned overflow diagnostics.
+ state_ = static_cast<uint32_t>(1103515245ULL * 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 if and only if the user has initialized
+// Google Test. Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+static bool GTestIsInitialized() { return GetArgvs().size() > 0; }
+
+// Iterates over a vector of TestSuites, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestSuiteList(const std::vector<TestSuite*>& case_list,
+ int (TestSuite::*method)() const) {
+ int sum = 0;
+ for (size_t i = 0; i < case_list.size(); i++) {
+ sum += (case_list[i]->*method)();
+ }
+ return sum;
+}
+
+// Returns true if and only if the test suite passed.
+static bool TestSuitePassed(const TestSuite* test_suite) {
+ return test_suite->should_run() && test_suite->Passed();
+}
+
+// Returns true if and only if the test suite failed.
+static bool TestSuiteFailed(const TestSuite* test_suite) {
+ return test_suite->should_run() && test_suite->Failed();
+}
+
+// Returns true if and only if test_suite contains at least one test that
+// should run.
+static bool ShouldRunTestSuite(const TestSuite* test_suite) {
+ return test_suite->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
+}
+
+namespace {
+
+// When TEST_P is found without a matching INSTANTIATE_TEST_SUITE_P
+// to creates test cases for it, a synthetic test case is
+// inserted to report ether an error or a log message.
+//
+// This configuration bit will likely be removed at some point.
+constexpr bool kErrorOnUninstantiatedParameterizedTest = true;
+constexpr bool kErrorOnUninstantiatedTypeParameterizedTest = true;
+
+// A test that fails at a given file/line location with a given message.
+class FailureTest : public Test {
+ public:
+ explicit FailureTest(const CodeLocation& loc, std::string error_message,
+ bool as_error)
+ : loc_(loc),
+ error_message_(std::move(error_message)),
+ as_error_(as_error) {}
+
+ void TestBody() override {
+ if (as_error_) {
+ AssertHelper(TestPartResult::kNonFatalFailure, loc_.file.c_str(),
+ loc_.line, "") = Message() << error_message_;
+ } else {
+ std::cout << error_message_ << std::endl;
+ }
+ }
+
+ private:
+ const CodeLocation loc_;
+ const std::string error_message_;
+ const bool as_error_;
+};
+
+} // namespace
+
+std::set<std::string>* GetIgnoredParameterizedTestSuites() {
+ return UnitTest::GetInstance()->impl()->ignored_parameterized_test_suites();
+}
+
+// Add a given test_suit to the list of them allow to go un-instantiated.
+MarkAsIgnored::MarkAsIgnored(const char* test_suite) {
+ GetIgnoredParameterizedTestSuites()->insert(test_suite);
+}
+
+// If this parameterized test suite has no instantiations (and that
+// has not been marked as okay), emit a test case reporting that.
+void InsertSyntheticTestCase(const std::string& name, CodeLocation location,
+ bool has_test_p) {
+ const auto& ignored = *GetIgnoredParameterizedTestSuites();
+ if (ignored.find(name) != ignored.end()) return;
+
+ const char kMissingInstantiation[] = //
+ " is defined via TEST_P, but never instantiated. None of the test cases "
+ "will run. Either no INSTANTIATE_TEST_SUITE_P is provided or the only "
+ "ones provided expand to nothing."
+ "\n\n"
+ "Ideally, TEST_P definitions should only ever be included as part of "
+ "binaries that intend to use them. (As opposed to, for example, being "
+ "placed in a library that may be linked in to get other utilities.)";
+
+ const char kMissingTestCase[] = //
+ " is instantiated via INSTANTIATE_TEST_SUITE_P, but no tests are "
+ "defined via TEST_P . No test cases will run."
+ "\n\n"
+ "Ideally, INSTANTIATE_TEST_SUITE_P should only ever be invoked from "
+ "code that always depend on code that provides TEST_P. Failing to do "
+ "so is often an indication of dead code, e.g. the last TEST_P was "
+ "removed but the rest got left behind.";
+
+ std::string message =
+ "Parameterized test suite " + name +
+ (has_test_p ? kMissingInstantiation : kMissingTestCase) +
+ "\n\n"
+ "To suppress this error for this test suite, insert the following line "
+ "(in a non-header) in the namespace it is defined in:"
+ "\n\n"
+ "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" +
+ name + ");";
+
+ std::string full_name = "UninstantiatedParameterizedTestSuite<" + name + ">";
+ RegisterTest( //
+ "GoogleTestVerification", full_name.c_str(),
+ nullptr, // No type parameter.
+ nullptr, // No value parameter.
+ location.file.c_str(), location.line, [message, location] {
+ return new FailureTest(location, message,
+ kErrorOnUninstantiatedParameterizedTest);
+ });
+}
+
+void RegisterTypeParameterizedTestSuite(const char* test_suite_name,
+ CodeLocation code_location) {
+ GetUnitTestImpl()->type_parameterized_test_registry().RegisterTestSuite(
+ test_suite_name, code_location);
+}
+
+void RegisterTypeParameterizedTestSuiteInstantiation(const char* case_name) {
+ GetUnitTestImpl()->type_parameterized_test_registry().RegisterInstantiation(
+ case_name);
+}
+
+void TypeParameterizedTestSuiteRegistry::RegisterTestSuite(
+ const char* test_suite_name, CodeLocation code_location) {
+ suites_.emplace(std::string(test_suite_name),
+ TypeParameterizedTestSuiteInfo(code_location));
+}
+
+void TypeParameterizedTestSuiteRegistry::RegisterInstantiation(
+ const char* test_suite_name) {
+ auto it = suites_.find(std::string(test_suite_name));
+ if (it != suites_.end()) {
+ it->second.instantiated = true;
+ } else {
+ GTEST_LOG_(ERROR) << "Unknown type parameterized test suit '"
+ << test_suite_name << "'";
+ }
+}
+
+void TypeParameterizedTestSuiteRegistry::CheckForInstantiations() {
+ const auto& ignored = *GetIgnoredParameterizedTestSuites();
+ for (const auto& testcase : suites_) {
+ if (testcase.second.instantiated) continue;
+ if (ignored.find(testcase.first) != ignored.end()) continue;
+
+ std::string message =
+ "Type parameterized test suite " + testcase.first +
+ " is defined via REGISTER_TYPED_TEST_SUITE_P, but never instantiated "
+ "via INSTANTIATE_TYPED_TEST_SUITE_P. None of the test cases will run."
+ "\n\n"
+ "Ideally, TYPED_TEST_P definitions should only ever be included as "
+ "part of binaries that intend to use them. (As opposed to, for "
+ "example, being placed in a library that may be linked in to get other "
+ "utilities.)"
+ "\n\n"
+ "To suppress this error for this test suite, insert the following line "
+ "(in a non-header) in the namespace it is defined in:"
+ "\n\n"
+ "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" +
+ testcase.first + ");";
+
+ std::string full_name =
+ "UninstantiatedTypeParameterizedTestSuite<" + testcase.first + ">";
+ RegisterTest( //
+ "GoogleTestVerification", full_name.c_str(),
+ nullptr, // No type parameter.
+ nullptr, // No value parameter.
+ testcase.second.code_location.file.c_str(),
+ testcase.second.code_location.line, [message, testcase] {
+ return new FailureTest(testcase.second.code_location, message,
+ kErrorOnUninstantiatedTypeParameterizedTest);
+ });
+ }
+}
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+static ::std::vector<std::string> g_argvs;
+
+::std::vector<std::string> GetArgvs() {
+#if defined(GTEST_CUSTOM_GET_ARGVS_)
+ // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or
+ // ::string. This code converts it to the appropriate type.
+ const auto& custom = GTEST_CUSTOM_GET_ARGVS_();
+ return ::std::vector<std::string>(custom.begin(), custom.end());
+#else // defined(GTEST_CUSTOM_GET_ARGVS_)
+ return g_argvs;
+#endif // defined(GTEST_CUSTOM_GET_ARGVS_)
+}
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+ FilePath result;
+
+#if GTEST_OS_WINDOWS || GTEST_OS_OS2
+ result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe"));
+#else
+ result.Set(FilePath(GetArgvs()[0]));
+#endif // GTEST_OS_WINDOWS
+
+ return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+std::string UnitTestOptions::GetOutputFormat() {
+ std::string s = GTEST_FLAG_GET(output);
+ const char* const gtest_output_flag = s.c_str();
+ const char* const colon = strchr(gtest_output_flag, ':');
+ return (colon == nullptr)
+ ? std::string(gtest_output_flag)
+ : std::string(gtest_output_flag,
+ static_cast<size_t>(colon - gtest_output_flag));
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
+ std::string s = GTEST_FLAG_GET(output);
+ const char* const gtest_output_flag = s.c_str();
+
+ std::string format = GetOutputFormat();
+ if (format.empty()) format = std::string(kDefaultOutputFormat);
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ if (colon == nullptr)
+ return internal::FilePath::MakeFileName(
+ internal::FilePath(
+ UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(kDefaultOutputFile), 0, format.c_str())
+ .string();
+
+ internal::FilePath output_name(colon + 1);
+ if (!output_name.IsAbsolutePath())
+ output_name = internal::FilePath::ConcatPaths(
+ internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(colon + 1));
+
+ if (!output_name.IsDirectory()) return output_name.string();
+
+ internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+ output_name, internal::GetCurrentExecutableName(),
+ GetOutputFormat().c_str()));
+ return result.string();
+}
+
+// Returns true if and only if the wildcard pattern matches the string. Each
+// pattern consists of regular characters, single-character wildcards (?), and
+// multi-character wildcards (*).
+//
+// This function implements a linear-time string globbing algorithm based on
+// https://research.swtch.com/glob.
+static bool PatternMatchesString(const std::string& name_str,
+ const char* pattern, const char* pattern_end) {
+ const char* name = name_str.c_str();
+ const char* const name_begin = name;
+ const char* const name_end = name + name_str.size();
+
+ const char* pattern_next = pattern;
+ const char* name_next = name;
+
+ while (pattern < pattern_end || name < name_end) {
+ if (pattern < pattern_end) {
+ switch (*pattern) {
+ default: // Match an ordinary character.
+ if (name < name_end && *name == *pattern) {
+ ++pattern;
+ ++name;
+ continue;
+ }
+ break;
+ case '?': // Match any single character.
+ if (name < name_end) {
+ ++pattern;
+ ++name;
+ continue;
+ }
+ break;
+ case '*':
+ // Match zero or more characters. Start by skipping over the wildcard
+ // and matching zero characters from name. If that fails, restart and
+ // match one more character than the last attempt.
+ pattern_next = pattern;
+ name_next = name + 1;
+ ++pattern;
+ continue;
+ }
+ }
+ // Failed to match a character. Restart if possible.
+ if (name_begin < name_next && name_next <= name_end) {
+ pattern = pattern_next;
+ name = name_next;
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
+
+namespace {
+
+bool IsGlobPattern(const std::string& pattern) {
+ return std::any_of(pattern.begin(), pattern.end(),
+ [](const char c) { return c == '?' || c == '*'; });
+}
+
+class UnitTestFilter {
+ public:
+ UnitTestFilter() = default;
+
+ // Constructs a filter from a string of patterns separated by `:`.
+ explicit UnitTestFilter(const std::string& filter) {
+ // By design "" filter matches "" string.
+ std::vector<std::string> all_patterns;
+ SplitString(filter, ':', &all_patterns);
+ const auto exact_match_patterns_begin = std::partition(
+ all_patterns.begin(), all_patterns.end(), &IsGlobPattern);
+
+ glob_patterns_.reserve(static_cast<size_t>(
+ std::distance(all_patterns.begin(), exact_match_patterns_begin)));
+ std::move(all_patterns.begin(), exact_match_patterns_begin,
+ std::inserter(glob_patterns_, glob_patterns_.begin()));
+ std::move(
+ exact_match_patterns_begin, all_patterns.end(),
+ std::inserter(exact_match_patterns_, exact_match_patterns_.begin()));
+ }
+
+ // Returns true if and only if name matches at least one of the patterns in
+ // the filter.
+ bool MatchesName(const std::string& name) const {
+ return exact_match_patterns_.count(name) > 0 ||
+ std::any_of(glob_patterns_.begin(), glob_patterns_.end(),
+ [&name](const std::string& pattern) {
+ return PatternMatchesString(
+ name, pattern.c_str(),
+ pattern.c_str() + pattern.size());
+ });
+ }
+
+ private:
+ std::vector<std::string> glob_patterns_;
+ std::unordered_set<std::string> exact_match_patterns_;
+};
+
+class PositiveAndNegativeUnitTestFilter {
+ public:
+ // Constructs a positive and a negative filter from a string. The string
+ // contains a positive filter optionally followed by a '-' character and a
+ // negative filter. In case only a negative filter is provided the positive
+ // filter will be assumed "*".
+ // A filter is a list of patterns separated by ':'.
+ explicit PositiveAndNegativeUnitTestFilter(const std::string& filter) {
+ std::vector<std::string> positive_and_negative_filters;
+
+ // NOTE: `SplitString` always returns a non-empty container.
+ SplitString(filter, '-', &positive_and_negative_filters);
+ const auto& positive_filter = positive_and_negative_filters.front();
+
+ if (positive_and_negative_filters.size() > 1) {
+ positive_filter_ = UnitTestFilter(
+ positive_filter.empty() ? kUniversalFilter : positive_filter);
+
+ // TODO(b/214626361): Fail on multiple '-' characters
+ // For the moment to preserve old behavior we concatenate the rest of the
+ // string parts with `-` as separator to generate the negative filter.
+ auto negative_filter_string = positive_and_negative_filters[1];
+ for (std::size_t i = 2; i < positive_and_negative_filters.size(); i++)
+ negative_filter_string =
+ negative_filter_string + '-' + positive_and_negative_filters[i];
+ negative_filter_ = UnitTestFilter(negative_filter_string);
+ } else {
+ // In case we don't have a negative filter and positive filter is ""
+ // we do not use kUniversalFilter by design as opposed to when we have a
+ // negative filter.
+ positive_filter_ = UnitTestFilter(positive_filter);
+ }
+ }
+
+ // Returns true if and only if test name (this is generated by appending test
+ // suit name and test name via a '.' character) matches the positive filter
+ // and does not match the negative filter.
+ bool MatchesTest(const std::string& test_suite_name,
+ const std::string& test_name) const {
+ return MatchesName(test_suite_name + "." + test_name);
+ }
+
+ // Returns true if and only if name matches the positive filter and does not
+ // match the negative filter.
+ bool MatchesName(const std::string& name) const {
+ return positive_filter_.MatchesName(name) &&
+ !negative_filter_.MatchesName(name);
+ }
+
+ private:
+ UnitTestFilter positive_filter_;
+ UnitTestFilter negative_filter_;
+};
+} // namespace
+
+bool UnitTestOptions::MatchesFilter(const std::string& name_str,
+ const char* filter) {
+ return UnitTestFilter(filter).MatchesName(name_str);
+}
+
+// Returns true if and only if the user-specified filter matches the test
+// suite name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name,
+ const std::string& test_name) {
+ // Split --gtest_filter at '-', if there is one, to separate into
+ // positive filter and negative filter portions
+ return PositiveAndNegativeUnitTestFilter(GTEST_FLAG_GET(filter))
+ .MatchesTest(test_suite_name, test_name);
+}
+
+#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_GET(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<Test>(); }
+
+// 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.
+static AssertionResult HasOneFailure(const char* /* results_expr */,
+ const char* /* type_expr */,
+ const char* /* substr_expr */,
+ const TestPartResultArray& results,
+ TestPartResult::Type type,
+ const std::string& substr) {
+ const std::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()) == nullptr) {
+ 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 std::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 suites.
+int UnitTestImpl::successful_test_suite_count() const {
+ return CountIf(test_suites_, TestSuitePassed);
+}
+
+// Gets the number of failed test suites.
+int UnitTestImpl::failed_test_suite_count() const {
+ return CountIf(test_suites_, TestSuiteFailed);
+}
+
+// Gets the number of all test suites.
+int UnitTestImpl::total_test_suite_count() const {
+ return static_cast<int>(test_suites_.size());
+}
+
+// Gets the number of all test suites that contain at least one test
+// that should run.
+int UnitTestImpl::test_suite_to_run_count() const {
+ return CountIf(test_suites_, ShouldRunTestSuite);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count);
+}
+
+// Gets the number of skipped tests.
+int UnitTestImpl::skipped_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTestImpl::reportable_disabled_test_count() const {
+ return SumOverTestSuiteList(test_suites_,
+ &TestSuite::reportable_disabled_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTestImpl::reportable_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count);
+}
+
+// Returns the current OS stack trace as an std::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.
+std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+ return os_stack_trace_getter()->CurrentStackTrace(
+ static_cast<int>(GTEST_FLAG_GET(stack_trace_depth)), skip_count + 1
+ // Skips the user-specified number of frames plus this function
+ // itself.
+ ); // NOLINT
+}
+
+// A helper class for measuring elapsed times.
+class Timer {
+ public:
+ Timer() : start_(std::chrono::steady_clock::now()) {}
+
+ // Return time elapsed in milliseconds since the timer was created.
+ TimeInMillis Elapsed() {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start_)
+ .count();
+ }
+
+ private:
+ std::chrono::steady_clock::time_point start_;
+};
+
+// Returns a timestamp as milliseconds since the epoch. Note this time may jump
+// around subject to adjustments by the system, to measure elapsed time use
+// Timer instead.
+TimeInMillis GetTimeInMillis() {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::system_clock::now() -
+ std::chrono::system_clock::from_time_t(0))
+ .count();
+}
+
+// Utilities
+
+// class String.
+
+#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 nullptr;
+ const int length = strlen(ansi);
+ const int unicode_length =
+ MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 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 nullptr;
+ const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr,
+ 0, nullptr, nullptr);
+ char* ansi = new char[ansi_length + 1];
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr,
+ nullptr);
+ ansi[ansi_length] = 0;
+ return ansi;
+}
+
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Compares two C strings. Returns true if and only if 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 == nullptr) return rhs == nullptr;
+
+ if (rhs == nullptr) return false;
+
+ return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_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) {
+ for (size_t i = 0; i != length;) { // NOLINT
+ if (wstr[i] != L'\0') {
+ *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
+ while (i != length && wstr[i] != L'\0') i++;
+ } else {
+ *msg << '\0';
+ i++;
+ }
+ }
+}
+
+#endif // GTEST_HAS_STD_WSTRING
+
+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);
+}
+
+} // namespace internal
+
+// 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::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<double>::digits10 + 2);
+}
+
+// These two overloads allow streaming a wide C string to a Message
+// using the UTF-8 encoding.
+Message& Message::operator<<(const wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+}
+Message& 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& Message::operator<<(const ::std::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+// Gets the text streamed to this object so far as an std::string.
+// Each '\0' character in the buffer is replaced with "\\0".
+std::string Message::GetString() const {
+ return internal::StringStreamToString(ss_.get());
+}
+
+namespace internal {
+
+namespace edit_distance {
+std::vector<EditType> CalculateOptimalEdits(const std::vector<size_t>& left,
+ const std::vector<size_t>& right) {
+ std::vector<std::vector<double> > costs(
+ left.size() + 1, std::vector<double>(right.size() + 1));
+ std::vector<std::vector<EditType> > best_move(
+ left.size() + 1, std::vector<EditType>(right.size() + 1));
+
+ // Populate for empty right.
+ for (size_t l_i = 0; l_i < costs.size(); ++l_i) {
+ costs[l_i][0] = static_cast<double>(l_i);
+ best_move[l_i][0] = kRemove;
+ }
+ // Populate for empty left.
+ for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) {
+ costs[0][r_i] = static_cast<double>(r_i);
+ best_move[0][r_i] = kAdd;
+ }
+
+ for (size_t l_i = 0; l_i < left.size(); ++l_i) {
+ for (size_t r_i = 0; r_i < right.size(); ++r_i) {
+ if (left[l_i] == right[r_i]) {
+ // Found a match. Consume it.
+ costs[l_i + 1][r_i + 1] = costs[l_i][r_i];
+ best_move[l_i + 1][r_i + 1] = kMatch;
+ continue;
+ }
+
+ const double add = costs[l_i + 1][r_i];
+ const double remove = costs[l_i][r_i + 1];
+ const double replace = costs[l_i][r_i];
+ if (add < remove && add < replace) {
+ costs[l_i + 1][r_i + 1] = add + 1;
+ best_move[l_i + 1][r_i + 1] = kAdd;
+ } else if (remove < add && remove < replace) {
+ costs[l_i + 1][r_i + 1] = remove + 1;
+ best_move[l_i + 1][r_i + 1] = kRemove;
+ } else {
+ // We make replace a little more expensive than add/remove to lower
+ // their priority.
+ costs[l_i + 1][r_i + 1] = replace + 1.00001;
+ best_move[l_i + 1][r_i + 1] = kReplace;
+ }
+ }
+ }
+
+ // Reconstruct the best path. We do it in reverse order.
+ std::vector<EditType> best_path;
+ for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) {
+ EditType move = best_move[l_i][r_i];
+ best_path.push_back(move);
+ l_i -= move != kAdd;
+ r_i -= move != kRemove;
+ }
+ std::reverse(best_path.begin(), best_path.end());
+ return best_path;
+}
+
+namespace {
+
+// Helper class to convert string into ids with deduplication.
+class InternalStrings {
+ public:
+ size_t GetId(const std::string& str) {
+ IdMap::iterator it = ids_.find(str);
+ if (it != ids_.end()) return it->second;
+ size_t id = ids_.size();
+ return ids_[str] = id;
+ }
+
+ private:
+ typedef std::map<std::string, size_t> IdMap;
+ IdMap ids_;
+};
+
+} // namespace
+
+std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<std::string>& left,
+ const std::vector<std::string>& right) {
+ std::vector<size_t> left_ids, right_ids;
+ {
+ InternalStrings intern_table;
+ for (size_t i = 0; i < left.size(); ++i) {
+ left_ids.push_back(intern_table.GetId(left[i]));
+ }
+ for (size_t i = 0; i < right.size(); ++i) {
+ right_ids.push_back(intern_table.GetId(right[i]));
+ }
+ }
+ return CalculateOptimalEdits(left_ids, right_ids);
+}
+
+namespace {
+
+// Helper class that holds the state for one hunk and prints it out to the
+// stream.
+// It reorders adds/removes when possible to group all removes before all
+// adds. It also adds the hunk header before printint into the stream.
+class Hunk {
+ public:
+ Hunk(size_t left_start, size_t right_start)
+ : left_start_(left_start),
+ right_start_(right_start),
+ adds_(),
+ removes_(),
+ common_() {}
+
+ void PushLine(char edit, const char* line) {
+ switch (edit) {
+ case ' ':
+ ++common_;
+ FlushEdits();
+ hunk_.push_back(std::make_pair(' ', line));
+ break;
+ case '-':
+ ++removes_;
+ hunk_removes_.push_back(std::make_pair('-', line));
+ break;
+ case '+':
+ ++adds_;
+ hunk_adds_.push_back(std::make_pair('+', line));
+ break;
+ }
+ }
+
+ void PrintTo(std::ostream* os) {
+ PrintHeader(os);
+ FlushEdits();
+ for (std::list<std::pair<char, const char*> >::const_iterator it =
+ hunk_.begin();
+ it != hunk_.end(); ++it) {
+ *os << it->first << it->second << "\n";
+ }
+ }
+
+ bool has_edits() const { return adds_ || removes_; }
+
+ private:
+ void FlushEdits() {
+ hunk_.splice(hunk_.end(), hunk_removes_);
+ hunk_.splice(hunk_.end(), hunk_adds_);
+ }
+
+ // Print a unified diff header for one hunk.
+ // The format is
+ // "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@"
+ // where the left/right parts are omitted if unnecessary.
+ void PrintHeader(std::ostream* ss) const {
+ *ss << "@@ ";
+ if (removes_) {
+ *ss << "-" << left_start_ << "," << (removes_ + common_);
+ }
+ if (removes_ && adds_) {
+ *ss << " ";
+ }
+ if (adds_) {
+ *ss << "+" << right_start_ << "," << (adds_ + common_);
+ }
+ *ss << " @@\n";
+ }
+
+ size_t left_start_, right_start_;
+ size_t adds_, removes_, common_;
+ std::list<std::pair<char, const char*> > hunk_, hunk_adds_, hunk_removes_;
+};
+
+} // namespace
+
+// Create a list of diff hunks in Unified diff format.
+// Each hunk has a header generated by PrintHeader above plus a body with
+// lines prefixed with ' ' for no change, '-' for deletion and '+' for
+// addition.
+// 'context' represents the desired unchanged prefix/suffix around the diff.
+// If two hunks are close enough that their contexts overlap, then they are
+// joined into one hunk.
+std::string CreateUnifiedDiff(const std::vector<std::string>& left,
+ const std::vector<std::string>& right,
+ size_t context) {
+ const std::vector<EditType> edits = CalculateOptimalEdits(left, right);
+
+ size_t l_i = 0, r_i = 0, edit_i = 0;
+ std::stringstream ss;
+ while (edit_i < edits.size()) {
+ // Find first edit.
+ while (edit_i < edits.size() && edits[edit_i] == kMatch) {
+ ++l_i;
+ ++r_i;
+ ++edit_i;
+ }
+
+ // Find the first line to include in the hunk.
+ const size_t prefix_context = std::min(l_i, context);
+ Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1);
+ for (size_t i = prefix_context; i > 0; --i) {
+ hunk.PushLine(' ', left[l_i - i].c_str());
+ }
+
+ // Iterate the edits until we found enough suffix for the hunk or the input
+ // is over.
+ size_t n_suffix = 0;
+ for (; edit_i < edits.size(); ++edit_i) {
+ if (n_suffix >= context) {
+ // Continue only if the next hunk is very close.
+ auto it = edits.begin() + static_cast<int>(edit_i);
+ while (it != edits.end() && *it == kMatch) ++it;
+ if (it == edits.end() ||
+ static_cast<size_t>(it - edits.begin()) - edit_i >= context) {
+ // There is no next edit or it is too far away.
+ break;
+ }
+ }
+
+ EditType edit = edits[edit_i];
+ // Reset count when a non match is found.
+ n_suffix = edit == kMatch ? n_suffix + 1 : 0;
+
+ if (edit == kMatch || edit == kRemove || edit == kReplace) {
+ hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str());
+ }
+ if (edit == kAdd || edit == kReplace) {
+ hunk.PushLine('+', right[r_i].c_str());
+ }
+
+ // Advance indices, depending on edit type.
+ l_i += edit != kAdd;
+ r_i += edit != kRemove;
+ }
+
+ if (!hunk.has_edits()) {
+ // We are done. We don't want this hunk.
+ break;
+ }
+
+ hunk.PrintTo(&ss);
+ }
+ return ss.str();
+}
+
+} // namespace edit_distance
+
+namespace {
+
+// The string representation of the values received in EqFailure() are already
+// escaped. Split them on escaped '\n' boundaries. Leave all other escaped
+// characters the same.
+std::vector<std::string> SplitEscapedString(const std::string& str) {
+ std::vector<std::string> lines;
+ size_t start = 0, end = str.size();
+ if (end > 2 && str[0] == '"' && str[end - 1] == '"') {
+ ++start;
+ --end;
+ }
+ bool escaped = false;
+ for (size_t i = start; i + 1 < end; ++i) {
+ if (escaped) {
+ escaped = false;
+ if (str[i] == 'n') {
+ lines.push_back(str.substr(start, i - start - 1));
+ start = i + 1;
+ }
+ } else {
+ escaped = str[i] == '\\';
+ }
+ }
+ lines.push_back(str.substr(start, end - start));
+ return lines;
+}
+
+} // namespace
+
+// 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:
+//
+// lhs_expression: "foo"
+// rhs_expression: "bar"
+// lhs_value: "5"
+// rhs_value: "6"
+//
+// The ignoring_case parameter is true if and only if the assertion is a
+// *_STRCASEEQ*. When it's true, the string "Ignoring case" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* lhs_expression,
+ const char* rhs_expression,
+ const std::string& lhs_value,
+ const std::string& rhs_value, bool ignoring_case) {
+ Message msg;
+ msg << "Expected equality of these values:";
+ msg << "\n " << lhs_expression;
+ if (lhs_value != lhs_expression) {
+ msg << "\n Which is: " << lhs_value;
+ }
+ msg << "\n " << rhs_expression;
+ if (rhs_value != rhs_expression) {
+ msg << "\n Which is: " << rhs_value;
+ }
+
+ if (ignoring_case) {
+ msg << "\nIgnoring case";
+ }
+
+ if (!lhs_value.empty() && !rhs_value.empty()) {
+ const std::vector<std::string> lhs_lines = SplitEscapedString(lhs_value);
+ const std::vector<std::string> rhs_lines = SplitEscapedString(rhs_value);
+ if (lhs_lines.size() > 1 || rhs_lines.size() > 1) {
+ msg << "\nWith diff:\n"
+ << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines);
+ }
+ }
+
+ return AssertionFailure() << msg;
+}
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+std::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();
+
+ // Find the value which is closest to zero.
+ const double min_abs = std::min(fabs(val1), fabs(val2));
+ // Find the distance to the next double from that value.
+ const double epsilon =
+ nextafter(min_abs, std::numeric_limits<double>::infinity()) - min_abs;
+ // Detect the case where abs_error is so small that EXPECT_NEAR is
+ // effectively the same as EXPECT_EQUAL, and give an informative error
+ // message so that the situation can be more easily understood without
+ // requiring exotic floating-point knowledge.
+ // Don't do an epsilon check if abs_error is zero because that implies
+ // that an equality check was actually intended.
+ if (!(std::isnan)(val1) && !(std::isnan)(val2) && abs_error > 0 &&
+ abs_error < epsilon) {
+ return AssertionFailure()
+ << "The difference between " << expr1 << " and " << expr2 << " is "
+ << diff << ", where\n"
+ << expr1 << " evaluates to " << val1 << ",\n"
+ << expr2 << " evaluates to " << val2 << ".\nThe abs_error parameter "
+ << abs_error_expr << " evaluates to " << abs_error
+ << " which is smaller than the minimum distance between doubles for "
+ "numbers of this magnitude which is "
+ << epsilon
+ << ", thus making this EXPECT_NEAR check equivalent to "
+ "EXPECT_EQUAL. Consider using EXPECT_DOUBLE_EQ instead.";
+ }
+ 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 <typename RawType>
+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<RawType> 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<RawType>::digits10 + 2)
+ << val1;
+
+ ::std::stringstream val2_ss;
+ val2_ss << std::setprecision(std::numeric_limits<RawType>::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<float>(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<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* lhs_expression,
+ const char* rhs_expression, const char* lhs,
+ const char* rhs) {
+ if (String::CStringEquals(lhs, rhs)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs),
+ PrintToString(rhs), false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression,
+ const char* rhs_expression, const char* lhs,
+ const char* rhs) {
+ if (String::CaseInsensitiveCStringEquals(lhs, rhs)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs),
+ PrintToString(rhs), 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 if and only if needle
+// is a substring of haystack. NULL is considered a substring of
+// itself only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+ if (needle == nullptr || haystack == nullptr) return needle == haystack;
+
+ return strstr(haystack, needle) != nullptr;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+ if (needle == nullptr || haystack == nullptr) return needle == haystack;
+
+ return wcsstr(haystack, needle) != nullptr;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+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 <typename StringType>
+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 || GTEST_OS_WINDOWS_TV_TITLE
+
+ // 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;
+ // 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
+ static_cast<DWORD>(hr), // the error
+ 0, // no line width restrictions
+ error_text, // output buffer
+ kBufSize, // buf size
+ nullptr); // 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 std::string error_hex("0x" + String::FormatHexInt(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 up to 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.
+constexpr uint32_t kMaxCodePoint1 = (static_cast<uint32_t>(1) << 7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+constexpr uint32_t kMaxCodePoint2 = (static_cast<uint32_t>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+constexpr uint32_t kMaxCodePoint3 =
+ (static_cast<uint32_t>(1) << (4 + 2 * 6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+constexpr uint32_t kMaxCodePoint4 =
+ (static_cast<uint32_t>(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_t ChopLowBits(uint32_t* bits, int n) {
+ const uint32_t low_bits = *bits & ((static_cast<uint32_t>(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_t because wchar_t may not be
+// wide enough to contain a code point.
+// 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 converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+std::string CodePointToUtf8(uint32_t code_point) {
+ if (code_point > kMaxCodePoint4) {
+ return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")";
+ }
+
+ char str[5]; // Big enough for the largest valid code point.
+ if (code_point <= kMaxCodePoint1) {
+ str[1] = '\0';
+ str[0] = static_cast<char>(code_point); // 0xxxxxxx
+ } else if (code_point <= kMaxCodePoint2) {
+ str[2] = '\0';
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xC0 | code_point); // 110xxxxx
+ } else if (code_point <= kMaxCodePoint3) {
+ str[3] = '\0';
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xE0 | code_point); // 1110xxxx
+ } else { // code_point <= kMaxCodePoint4
+ str[4] = '\0';
+ str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xF0 | code_point); // 11110xxx
+ }
+ return str;
+}
+
+// The following two functions only make sense if the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin) 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_t CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+ wchar_t second) {
+ const auto first_u = static_cast<uint32_t>(first);
+ const auto second_u = static_cast<uint32_t>(second);
+ const uint32_t mask = (1 << 10) - 1;
+ return (sizeof(wchar_t) == 2)
+ ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000
+ :
+ // This function should not be called when the condition is
+ // false, but we provide a sensible default in case it is.
+ first_u;
+}
+
+// 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)
+// 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.
+std::string WideStringToUtf8(const wchar_t* str, int num_chars) {
+ if (num_chars == -1) num_chars = static_cast<int>(wcslen(str));
+
+ ::std::stringstream stream;
+ for (int i = 0; i < num_chars; ++i) {
+ uint32_t 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<uint32_t>(str[i]);
+ }
+
+ stream << CodePointToUtf8(unicode_code_point);
+ }
+ return StringStreamToString(&stream);
+}
+
+// Converts a wide C string to an std::string using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+std::string String::ShowWideCString(const wchar_t* wide_c_str) {
+ if (wide_c_str == nullptr) return "(null)";
+
+ return internal::WideStringToUtf8(wide_c_str, -1);
+}
+
+// Compares two wide C strings. Returns true if and only if 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 == nullptr) return rhs == nullptr;
+
+ if (rhs == nullptr) return false;
+
+ return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* lhs_expression,
+ const char* rhs_expression, const wchar_t* lhs,
+ const wchar_t* rhs) {
+ if (String::WideCStringEquals(lhs, rhs)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs),
+ PrintToString(rhs), 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: " << PrintToString(s1) << " vs " << PrintToString(s2);
+}
+
+// Compares two C strings, ignoring case. Returns true if and only if 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 == nullptr) return rhs == nullptr;
+ if (rhs == nullptr) return false;
+ return posix::StrCaseCmp(lhs, rhs) == 0;
+}
+
+// Compares two wide C strings, ignoring case. Returns true if and only if 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 == nullptr) return rhs == nullptr;
+
+ if (rhs == nullptr) 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(static_cast<wint_t>(*lhs++));
+ right = towlower(static_cast<wint_t>(*rhs++));
+ } while (left && left == right);
+ return left == right;
+#endif // OS selector
+}
+
+// Returns true if and only if str ends with the given suffix, ignoring case.
+// Any string is considered to end with an empty suffix.
+bool String::EndsWithCaseInsensitive(const std::string& str,
+ const std::string& suffix) {
+ const size_t str_len = str.length();
+ const size_t suffix_len = suffix.length();
+ return (str_len >= suffix_len) &&
+ CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len,
+ suffix.c_str());
+}
+
+// Formats an int value as "%02d".
+std::string String::FormatIntWidth2(int value) {
+ return FormatIntWidthN(value, 2);
+}
+
+// Formats an int value to given width with leading zeros.
+std::string String::FormatIntWidthN(int value, int width) {
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(width) << value;
+ return ss.str();
+}
+
+// Formats an int value as "%X".
+std::string String::FormatHexUInt32(uint32_t value) {
+ std::stringstream ss;
+ ss << std::hex << std::uppercase << value;
+ return ss.str();
+}
+
+// Formats an int value as "%X".
+std::string String::FormatHexInt(int value) {
+ return FormatHexUInt32(static_cast<uint32_t>(value));
+}
+
+// Formats a byte as "%02X".
+std::string String::FormatByte(unsigned char value) {
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase
+ << static_cast<unsigned int>(value);
+ return ss.str();
+}
+
+// Converts the buffer in a stringstream to an std::string, converting NUL
+// bytes to "\\0" along the way.
+std::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();
+
+ std::string result;
+ result.reserve(static_cast<size_t>(2 * (end - start)));
+ for (const char* ch = start; ch != end; ++ch) {
+ if (*ch == '\0') {
+ result += "\\0"; // Replaces NUL with "\\0";
+ } else {
+ result += *ch;
+ }
+ }
+
+ return result;
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+std::string AppendUserMessage(const std::string& gtest_msg,
+ const Message& user_msg) {
+ // Appends the user message if it's non-empty.
+ const std::string user_msg_string = user_msg.GetString();
+ if (user_msg_string.empty()) {
+ return gtest_msg;
+ }
+ if (gtest_msg.empty()) {
+ return user_msg_string;
+ }
+ return gtest_msg + "\n" + user_msg_string;
+}
+
+} // namespace internal
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+ : death_test_count_(0), start_timestamp_(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(static_cast<size_t>(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(static_cast<size_t>(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 std::string& xml_element,
+ const TestProperty& test_property) {
+ if (!ValidateTestProperty(xml_element, test_property)) {
+ return;
+ }
+ internal::MutexLock lock(&test_properties_mutex_);
+ const std::vector<TestProperty>::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());
+}
+
+// The list of reserved attributes used in the <testsuites> element of XML
+// output.
+static const char* const kReservedTestSuitesAttributes[] = {
+ "disabled", "errors", "failures", "name",
+ "random_seed", "tests", "time", "timestamp"};
+
+// The list of reserved attributes used in the <testsuite> element of XML
+// output.
+static const char* const kReservedTestSuiteAttributes[] = {
+ "disabled", "errors", "failures", "name",
+ "tests", "time", "timestamp", "skipped"};
+
+// The list of reserved attributes used in the <testcase> element of XML output.
+static const char* const kReservedTestCaseAttributes[] = {
+ "classname", "name", "status", "time",
+ "type_param", "value_param", "file", "line"};
+
+// Use a slightly different set for allowed output to ensure existing tests can
+// still RecordProperty("result") or "RecordProperty(timestamp")
+static const char* const kReservedOutputTestCaseAttributes[] = {
+ "classname", "name", "status", "time", "type_param",
+ "value_param", "file", "line", "result", "timestamp"};
+
+template <size_t kSize>
+std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
+ return std::vector<std::string>(array, array + kSize);
+}
+
+static std::vector<std::string> GetReservedAttributesForElement(
+ const std::string& xml_element) {
+ if (xml_element == "testsuites") {
+ return ArrayAsVector(kReservedTestSuitesAttributes);
+ } else if (xml_element == "testsuite") {
+ return ArrayAsVector(kReservedTestSuiteAttributes);
+ } else if (xml_element == "testcase") {
+ return ArrayAsVector(kReservedTestCaseAttributes);
+ } else {
+ GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+ }
+ // This code is unreachable but some compilers may not realizes that.
+ return std::vector<std::string>();
+}
+
+// TODO(jdesprez): Merge the two getReserved attributes once skip is improved
+static std::vector<std::string> GetReservedOutputAttributesForElement(
+ const std::string& xml_element) {
+ if (xml_element == "testsuites") {
+ return ArrayAsVector(kReservedTestSuitesAttributes);
+ } else if (xml_element == "testsuite") {
+ return ArrayAsVector(kReservedTestSuiteAttributes);
+ } else if (xml_element == "testcase") {
+ return ArrayAsVector(kReservedOutputTestCaseAttributes);
+ } else {
+ GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+ }
+ // This code is unreachable but some compilers may not realizes that.
+ return std::vector<std::string>();
+}
+
+static std::string FormatWordList(const std::vector<std::string>& words) {
+ Message word_list;
+ for (size_t i = 0; i < words.size(); ++i) {
+ if (i > 0 && words.size() > 2) {
+ word_list << ", ";
+ }
+ if (i == words.size() - 1) {
+ word_list << "and ";
+ }
+ word_list << "'" << words[i] << "'";
+ }
+ return word_list.GetString();
+}
+
+static bool ValidateTestPropertyName(
+ const std::string& property_name,
+ const std::vector<std::string>& reserved_names) {
+ if (std::find(reserved_names.begin(), reserved_names.end(), property_name) !=
+ reserved_names.end()) {
+ ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name
+ << " (" << FormatWordList(reserved_names)
+ << " are reserved by " << GTEST_NAME_ << ")";
+ return false;
+ }
+ return true;
+}
+
+// Adds a failure if the key is a reserved attribute of the element named
+// xml_element. Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const std::string& xml_element,
+ const TestProperty& test_property) {
+ return ValidateTestPropertyName(test_property.key(),
+ GetReservedAttributesForElement(xml_element));
+}
+
+// Clears the object.
+void TestResult::Clear() {
+ test_part_results_.clear();
+ test_properties_.clear();
+ death_test_count_ = 0;
+ elapsed_time_ = 0;
+}
+
+// Returns true off the test part was skipped.
+static bool TestPartSkipped(const TestPartResult& result) {
+ return result.skipped();
+}
+
+// Returns true if and only if the test was skipped.
+bool TestResult::Skipped() const {
+ return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0;
+}
+
+// Returns true if and only if 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 if and only if the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult& result) {
+ return result.fatally_failed();
+}
+
+// Returns true if and only if the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+ return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
+}
+
+// Returns true if and only if the test part non-fatally failed.
+static bool TestPartNonfatallyFailed(const TestPartResult& result) {
+ return result.nonfatally_failed();
+}
+
+// Returns true if and only if 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<int>(test_part_results_.size());
+}
+
+// Returns the number of the test properties.
+int TestResult::test_property_count() const {
+ return static_cast<int>(test_properties_.size());
+}
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the states of all flags.
+Test::Test() : gtest_flag_saver_(new GTEST_FLAG_SAVER_) {}
+
+// The d'tor restores the states of all flags. The actual work is
+// done by the d'tor of the gtest_flag_saver_ field, and thus not
+// visible here.
+Test::~Test() {}
+
+// 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 std::string& key, const std::string& value) {
+ UnitTest::GetInstance()->RecordProperty(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& 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 std::string& message) {
+ // This function is a friend of UnitTest and as such has access to
+ // AddTestPartResult.
+ UnitTest::GetInstance()->AddTestPartResult(
+ result_type,
+ nullptr, // No info about the source file where the exception occurred.
+ -1, // We have no info on which line caused the exception.
+ message,
+ ""); // No stack trace, either.
+}
+
+} // namespace internal
+
+// Google Test requires all tests in the same test suite 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 suite. 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 TestSuite* const test_suite = impl->current_test_suite();
+
+ // Info about the first test in the current test suite.
+ const TestInfo* const first_test_info = test_suite->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) {
+ // Both TEST and TEST_F appear in same test suite, which is incorrect.
+ // Tell the user how to fix this.
+
+ // 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 suite must use the same test fixture\n"
+ << "class, so mixing TEST_F and TEST in the same test suite is\n"
+ << "illegal. In test suite " << this_test_info->test_suite_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 {
+ // Two fixture classes with the same name appear in two different
+ // namespaces, which is not allowed. Tell the user how to fix this.
+ ADD_FAILURE()
+ << "All tests in the same test suite must use the same test fixture\n"
+ << "class. However, in test suite "
+ << this_test_info->test_suite_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 suites.";
+ }
+ 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 std::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 std::string(message.GetString());
+}
+
+#endif // GTEST_HAS_SEH
+
+namespace internal {
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Adds an "exception thrown" fatal failure to the current test.
+static std::string FormatCxxExceptionMessage(const char* description,
+ const char* location) {
+ Message message;
+ if (description != nullptr) {
+ message << "C++ exception with description \"" << description << "\"";
+ } else {
+ message << "Unknown C++ exception";
+ }
+ message << " thrown in " << location << ".";
+
+ return message.GetString();
+}
+
+static std::string PrintTestPartResultToString(
+ const TestPartResult& test_part_result);
+
+GoogleTestFailureException::GoogleTestFailureException(
+ const TestPartResult& failure)
+ : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// 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 <class T, typename Result>
+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).
+ std::string* exception_message =
+ FormatSehExceptionMessage(GetExceptionCode(), location);
+ internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
+ *exception_message);
+ delete exception_message;
+ return static_cast<Result>(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 <class T, typename Result>
+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_GET(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 AssertionException&) { // NOLINT
+ // This failure was reported already.
+ } catch (const internal::GoogleTestFailureException&) { // NOLINT
+ // This exception type can only be thrown by a failed Google
+ // Test assertion with the intention of letting another testing
+ // framework catch it. Therefore we just re-throw it.
+ throw;
+ } catch (const std::exception& e) { // NOLINT
+ internal::ReportFailureInUnknownLocation(
+ TestPartResult::kFatalFailure,
+ FormatCxxExceptionMessage(e.what(), location));
+ } catch (...) { // NOLINT
+ internal::ReportFailureInUnknownLocation(
+ TestPartResult::kFatalFailure,
+ FormatCxxExceptionMessage(nullptr, location));
+ }
+ return static_cast<Result>(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 and didn't call
+ // GTEST_SKIP().
+ if (!HasFatalFailure() && !IsSkipped()) {
+ 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 if and only if the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// Returns true if and only if the current test has a non-fatal failure.
+bool Test::HasNonfatalFailure() {
+ return internal::GetUnitTestImpl()
+ ->current_test_result()
+ ->HasNonfatalFailure();
+}
+
+// Returns true if and only if the current test was skipped.
+bool Test::IsSkipped() {
+ return internal::GetUnitTestImpl()->current_test_result()->Skipped();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object.
+TestInfo::TestInfo(const std::string& a_test_suite_name,
+ const std::string& a_name, const char* a_type_param,
+ const char* a_value_param,
+ internal::CodeLocation a_code_location,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory)
+ : test_suite_name_(a_test_suite_name),
+ name_(a_name),
+ type_param_(a_type_param ? new std::string(a_type_param) : nullptr),
+ value_param_(a_value_param ? new std::string(a_value_param) : nullptr),
+ location_(a_code_location),
+ fixture_class_id_(fixture_class_id),
+ should_run_(false),
+ is_disabled_(false),
+ matches_filter_(false),
+ is_in_another_shard_(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_suite_name: name of the test suite
+// 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.
+// code_location: code location where the test is defined
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+// 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_suite_name, const char* name, const char* type_param,
+ const char* value_param, CodeLocation code_location,
+ TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
+ TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) {
+ TestInfo* const test_info =
+ new TestInfo(test_suite_name, name, type_param, value_param,
+ code_location, fixture_class_id, factory);
+ GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+ return test_info;
+}
+
+void ReportInvalidTestSuiteType(const char* test_suite_name,
+ CodeLocation code_location) {
+ Message errors;
+ errors
+ << "Attempted redefinition of test suite " << test_suite_name << ".\n"
+ << "All tests in the same test suite must use the same test fixture\n"
+ << "class. However, in test suite " << test_suite_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 suites.";
+
+ GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(),
+ code_location.line)
+ << " " << errors.GetString();
+}
+} // namespace internal
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestSuite 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 if and only if the test name of test_info matches name_.
+ bool operator()(const TestInfo* test_info) const {
+ return test_info && test_info->name() == name_;
+ }
+
+ private:
+ std::string name_;
+};
+
+} // namespace
+
+namespace internal {
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_SUITE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests() {
+ if (!parameterized_tests_registered_) {
+ parameterized_test_registry_.RegisterTests();
+ type_parameterized_test_registry_.CheckForInstantiations();
+ parameterized_tests_registered_ = true;
+ }
+}
+
+} // namespace internal
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfo::Run() {
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+ if (!should_run_) {
+ if (is_disabled_ && matches_filter_) repeater->OnTestDisabled(*this);
+ return;
+ }
+
+ // Tells UnitTest where to store test result.
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_info(this);
+
+ // Notifies the unit test event listeners that a test is about to start.
+ repeater->OnTestStart(*this);
+ result_.set_start_timestamp(internal::GetTimeInMillis());
+ internal::Timer timer;
+ 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 if the constructor didn't generate a fatal failure or invoke
+ // GTEST_SKIP().
+ // Note that the object will not be null
+ if (!Test::HasFatalFailure() && !Test::IsSkipped()) {
+ // This doesn't throw as all user code that can throw are wrapped into
+ // exception handling code.
+ test->Run();
+ }
+
+ if (test != nullptr) {
+ // Deletes the test object.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ test, &Test::DeleteSelf_, "the test fixture's destructor");
+ }
+
+ result_.set_elapsed_time(timer.Elapsed());
+
+ // 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(nullptr);
+}
+
+// Skip and records a skipped test result for this object.
+void TestInfo::Skip() {
+ if (!should_run_) return;
+
+ 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 TestPartResult test_part_result =
+ TestPartResult(TestPartResult::kSkip, this->file(), this->line(), "");
+ impl->GetTestPartResultReporterForCurrentThread()->ReportTestPartResult(
+ test_part_result);
+
+ // Notifies the unit test event listener that a test has just finished.
+ repeater->OnTestEnd(*this);
+ impl->set_current_test_info(nullptr);
+}
+
+// class TestSuite
+
+// Gets the number of successful tests in this test suite.
+int TestSuite::successful_test_count() const {
+ return CountIf(test_info_list_, TestPassed);
+}
+
+// Gets the number of successful tests in this test suite.
+int TestSuite::skipped_test_count() const {
+ return CountIf(test_info_list_, TestSkipped);
+}
+
+// Gets the number of failed tests in this test suite.
+int TestSuite::failed_test_count() const {
+ return CountIf(test_info_list_, TestFailed);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int TestSuite::reportable_disabled_test_count() const {
+ return CountIf(test_info_list_, TestReportableDisabled);
+}
+
+// Gets the number of disabled tests in this test suite.
+int TestSuite::disabled_test_count() const {
+ return CountIf(test_info_list_, TestDisabled);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int TestSuite::reportable_test_count() const {
+ return CountIf(test_info_list_, TestReportable);
+}
+
+// Get the number of tests in this test suite that should run.
+int TestSuite::test_to_run_count() const {
+ return CountIf(test_info_list_, ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestSuite::total_test_count() const {
+ return static_cast<int>(test_info_list_.size());
+}
+
+// Creates a TestSuite with the given name.
+//
+// Arguments:
+//
+// a_name: name of the test suite
+// a_type_param: the name of the test suite's type parameter, or NULL if
+// this is not a typed or a type-parameterized test suite.
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+TestSuite::TestSuite(const char* a_name, const char* a_type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc)
+ : name_(a_name),
+ type_param_(a_type_param ? new std::string(a_type_param) : nullptr),
+ set_up_tc_(set_up_tc),
+ tear_down_tc_(tear_down_tc),
+ should_run_(false),
+ start_timestamp_(0),
+ elapsed_time_(0) {}
+
+// Destructor of TestSuite.
+TestSuite::~TestSuite() {
+ // Deletes every Test in the collection.
+ ForEach(test_info_list_, internal::Delete<TestInfo>);
+}
+
+// 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* TestSuite::GetTestInfo(int i) const {
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(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* TestSuite::GetMutableTestInfo(int i) {
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)];
+}
+
+// Adds a test to this test suite. Will delete the test upon
+// destruction of the TestSuite object.
+void TestSuite::AddTestInfo(TestInfo* test_info) {
+ test_info_list_.push_back(test_info);
+ test_indices_.push_back(static_cast<int>(test_indices_.size()));
+}
+
+// Runs every test in this TestSuite.
+void TestSuite::Run() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_suite(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Call both legacy and the new API
+ repeater->OnTestSuiteStart(*this);
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ repeater->OnTestCaseStart(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()");
+
+ const bool skip_all = ad_hoc_test_result().Failed();
+
+ start_timestamp_ = internal::GetTimeInMillis();
+ internal::Timer timer;
+ for (int i = 0; i < total_test_count(); i++) {
+ if (skip_all) {
+ GetMutableTestInfo(i)->Skip();
+ } else {
+ GetMutableTestInfo(i)->Run();
+ }
+ if (GTEST_FLAG_GET(fail_fast) &&
+ GetMutableTestInfo(i)->result()->Failed()) {
+ for (int j = i + 1; j < total_test_count(); j++) {
+ GetMutableTestInfo(j)->Skip();
+ }
+ break;
+ }
+ }
+ elapsed_time_ = timer.Elapsed();
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()");
+
+ // Call both legacy and the new API
+ repeater->OnTestSuiteEnd(*this);
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ repeater->OnTestCaseEnd(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ impl->set_current_test_suite(nullptr);
+}
+
+// Skips all tests under this TestSuite.
+void TestSuite::Skip() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_suite(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Call both legacy and the new API
+ repeater->OnTestSuiteStart(*this);
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ repeater->OnTestCaseStart(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ for (int i = 0; i < total_test_count(); i++) {
+ GetMutableTestInfo(i)->Skip();
+ }
+
+ // Call both legacy and the new API
+ repeater->OnTestSuiteEnd(*this);
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ repeater->OnTestCaseEnd(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ impl->set_current_test_suite(nullptr);
+}
+
+// Clears the results of all tests in this test suite.
+void TestSuite::ClearResult() {
+ ad_hoc_test_result_.Clear();
+ ForEach(test_info_list_, TestInfo::ClearTestResult);
+}
+
+// Shuffles the tests in this test suite.
+void TestSuite::ShuffleTests(internal::Random* random) {
+ Shuffle(random, &test_indices_);
+}
+
+// Restores the test order to before the first shuffle.
+void TestSuite::UnshuffleTests() {
+ for (size_t i = 0; i < test_indices_.size(); i++) {
+ test_indices_[i] = static_cast<int>(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 std::string FormatCountableNoun(int count, const char* singular_form,
+ const char* plural_form) {
+ return internal::StreamableToString(count) + " " +
+ (count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static std::string FormatTestCount(int test_count) {
+ return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test suites.
+static std::string FormatTestSuiteCount(int test_suite_count) {
+ return FormatCountableNoun(test_suite_count, "test suite", "test suites");
+}
+
+// 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::kSkip:
+ return "Skipped\n";
+ 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";
+ }
+}
+
+namespace internal {
+namespace {
+enum class GTestColor { kDefault, kRed, kGreen, kYellow };
+} // namespace
+
+// Prints a TestPartResult to an std::string.
+static std::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 std::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
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && \
+ !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW
+
+// Returns the character attribute for the given color.
+static WORD GetColorAttribute(GTestColor color) {
+ switch (color) {
+ case GTestColor::kRed:
+ return FOREGROUND_RED;
+ case GTestColor::kGreen:
+ return FOREGROUND_GREEN;
+ case GTestColor::kYellow:
+ return FOREGROUND_RED | FOREGROUND_GREEN;
+ default:
+ return 0;
+ }
+}
+
+static int GetBitOffset(WORD color_mask) {
+ if (color_mask == 0) return 0;
+
+ int bitOffset = 0;
+ while ((color_mask & 1) == 0) {
+ color_mask >>= 1;
+ ++bitOffset;
+ }
+ return bitOffset;
+}
+
+static WORD GetNewColor(GTestColor color, WORD old_color_attrs) {
+ // Let's reuse the BG
+ static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
+ BACKGROUND_RED | BACKGROUND_INTENSITY;
+ static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
+ FOREGROUND_RED | FOREGROUND_INTENSITY;
+ const WORD existing_bg = old_color_attrs & background_mask;
+
+ WORD new_color =
+ GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY;
+ static const int bg_bitOffset = GetBitOffset(background_mask);
+ static const int fg_bitOffset = GetBitOffset(foreground_mask);
+
+ if (((new_color & background_mask) >> bg_bitOffset) ==
+ ((new_color & foreground_mask) >> fg_bitOffset)) {
+ new_color ^= FOREGROUND_INTENSITY; // invert intensity
+ }
+ return new_color;
+}
+
+#else
+
+// Returns the ANSI color code for the given color. GTestColor::kDefault is
+// an invalid input.
+static const char* GetAnsiColorCode(GTestColor color) {
+ switch (color) {
+ case GTestColor::kRed:
+ return "1";
+ case GTestColor::kGreen:
+ return "2";
+ case GTestColor::kYellow:
+ return "3";
+ default:
+ return nullptr;
+ }
+}
+
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns true if and only if Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+ std::string c = GTEST_FLAG_GET(color);
+ const char* const gtest_color = c.c_str();
+
+ if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+ // 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, "screen-256color") ||
+ String::CStringEquals(term, "tmux") ||
+ String::CStringEquals(term, "tmux-256color") ||
+ String::CStringEquals(term, "rxvt-unicode") ||
+ String::CStringEquals(term, "rxvt-unicode-256color") ||
+ 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.
+
+GTEST_ATTRIBUTE_PRINTF_(2, 3)
+static void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+ static const bool in_color_mode =
+ ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
+ const bool use_color = in_color_mode && (color != GTestColor::kDefault);
+
+ if (!use_color) {
+ vprintf(fmt, args);
+ va_end(args);
+ return;
+ }
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && \
+ !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW
+ 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;
+ const WORD new_color = GetNewColor(color, old_color_attrs);
+
+ // 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, new_color);
+
+ 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);
+}
+
+// Text printed in Google Test's text output and --gtest_list_tests
+// output to label the type parameter and value parameter for a test.
+static const char kTypeParamLabel[] = "TypeParam";
+static const char kValueParamLabel[] = "GetParam()";
+
+static 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 != nullptr || value_param != nullptr) {
+ printf(", where ");
+ if (type_param != nullptr) {
+ printf("%s = %s", kTypeParamLabel, type_param);
+ if (value_param != nullptr) printf(" and ");
+ }
+ if (value_param != nullptr) {
+ printf("%s = %s", kValueParamLabel, value_param);
+ }
+ }
+}
+
+// This class implements the TestEventListener interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public TestEventListener {
+ public:
+ PrettyUnitTestResultPrinter() {}
+ static void PrintTestName(const char* test_suite, const char* test) {
+ printf("%s.%s", test_suite, test);
+ }
+
+ // The following methods override what's in the TestEventListener class.
+ void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationStart(const UnitTest& unit_test, int iteration) override;
+ void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestCase& test_case) override;
+#else
+ void OnTestSuiteStart(const TestSuite& test_suite) override;
+#endif // OnTestCaseStart
+
+ void OnTestStart(const TestInfo& test_info) override;
+ void OnTestDisabled(const TestInfo& test_info) override;
+
+ void OnTestPartResult(const TestPartResult& result) override;
+ void OnTestEnd(const TestInfo& test_info) override;
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& test_case) override;
+#else
+ void OnTestSuiteEnd(const TestSuite& test_suite) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
+
+ private:
+ static void PrintFailedTests(const UnitTest& unit_test);
+ static void PrintFailedTestSuites(const UnitTest& unit_test);
+ static void PrintSkippedTests(const UnitTest& unit_test);
+};
+
+// Fired before each iteration of tests starts.
+void PrettyUnitTestResultPrinter::OnTestIterationStart(
+ const UnitTest& unit_test, int iteration) {
+ if (GTEST_FLAG_GET(repeat) != 1)
+ printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);
+
+ std::string f = GTEST_FLAG_GET(filter);
+ const char* const filter = f.c_str();
+
+ // Prints the filter if it's not *. This reminds the user that some
+ // tests may be skipped.
+ if (!String::CStringEquals(filter, kUniversalFilter)) {
+ ColoredPrintf(GTestColor::kYellow, "Note: %s filter = %s\n", GTEST_NAME_,
+ filter);
+ }
+
+ if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
+ const int32_t shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
+ ColoredPrintf(GTestColor::kYellow, "Note: This is test shard %d of %s.\n",
+ static_cast<int>(shard_index) + 1,
+ internal::posix::GetEnv(kTestTotalShards));
+ }
+
+ if (GTEST_FLAG_GET(shuffle)) {
+ ColoredPrintf(GTestColor::kYellow,
+ "Note: Randomizing tests' orders with a seed of %d .\n",
+ unit_test.random_seed());
+ }
+
+ ColoredPrintf(GTestColor::kGreen, "[==========] ");
+ printf("Running %s from %s.\n",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
+ const UnitTest& /*unit_test*/) {
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("Global test environment set-up.\n");
+ fflush(stdout);
+}
+
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
+ const std::string counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_case.name());
+ if (test_case.type_param() == nullptr) {
+ printf("\n");
+ } else {
+ printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
+ }
+ fflush(stdout);
+}
+#else
+void PrettyUnitTestResultPrinter::OnTestSuiteStart(
+ const TestSuite& test_suite) {
+ const std::string counts =
+ FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests");
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_suite.name());
+ if (test_suite.type_param() == nullptr) {
+ printf("\n");
+ } else {
+ printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param());
+ }
+ fflush(stdout);
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
+ ColoredPrintf(GTestColor::kGreen, "[ RUN ] ");
+ PrintTestName(test_info.test_suite_name(), test_info.name());
+ printf("\n");
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestDisabled(const TestInfo& test_info) {
+ ColoredPrintf(GTestColor::kYellow, "[ DISABLED ] ");
+ PrintTestName(test_info.test_suite_name(), test_info.name());
+ printf("\n");
+ fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnTestPartResult(
+ const TestPartResult& result) {
+ switch (result.type()) {
+ // If the test part succeeded, we don't need to do anything.
+ case TestPartResult::kSuccess:
+ return;
+ default:
+ // 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(GTestColor::kGreen, "[ OK ] ");
+ } else if (test_info.result()->Skipped()) {
+ ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] ");
+ } else {
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ }
+ PrintTestName(test_info.test_suite_name(), test_info.name());
+ if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info);
+
+ if (GTEST_FLAG_GET(print_time)) {
+ printf(" (%s ms)\n",
+ internal::StreamableToString(test_info.result()->elapsed_time())
+ .c_str());
+ } else {
+ printf("\n");
+ }
+ fflush(stdout);
+}
+
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
+ if (!GTEST_FLAG_GET(print_time)) return;
+
+ const std::string counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(),
+ internal::StreamableToString(test_case.elapsed_time()).c_str());
+ fflush(stdout);
+}
+#else
+void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) {
+ if (!GTEST_FLAG_GET(print_time)) return;
+
+ const std::string counts =
+ FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests");
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(),
+ internal::StreamableToString(test_suite.elapsed_time()).c_str());
+ fflush(stdout);
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
+ const UnitTest& /*unit_test*/) {
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ 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();
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+ if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) {
+ continue;
+ }
+ for (int j = 0; j < test_suite.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_suite.GetTestInfo(j);
+ if (!test_info.should_run() || !test_info.result()->Failed()) {
+ continue;
+ }
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ printf("%s.%s", test_suite.name(), test_info.name());
+ PrintFullTestCommentIfPresent(test_info);
+ printf("\n");
+ }
+ }
+ printf("\n%2d FAILED %s\n", failed_test_count,
+ failed_test_count == 1 ? "TEST" : "TESTS");
+}
+
+// Internal helper for printing the list of test suite failures not covered by
+// PrintFailedTests.
+void PrettyUnitTestResultPrinter::PrintFailedTestSuites(
+ const UnitTest& unit_test) {
+ int suite_failure_count = 0;
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+ if (!test_suite.should_run()) {
+ continue;
+ }
+ if (test_suite.ad_hoc_test_result().Failed()) {
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ printf("%s: SetUpTestSuite or TearDownTestSuite\n", test_suite.name());
+ ++suite_failure_count;
+ }
+ }
+ if (suite_failure_count > 0) {
+ printf("\n%2d FAILED TEST %s\n", suite_failure_count,
+ suite_failure_count == 1 ? "SUITE" : "SUITES");
+ }
+}
+
+// Internal helper for printing the list of skipped tests.
+void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) {
+ const int skipped_test_count = unit_test.skipped_test_count();
+ if (skipped_test_count == 0) {
+ return;
+ }
+
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+ if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) {
+ continue;
+ }
+ for (int j = 0; j < test_suite.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_suite.GetTestInfo(j);
+ if (!test_info.should_run() || !test_info.result()->Skipped()) {
+ continue;
+ }
+ ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] ");
+ printf("%s.%s", test_suite.name(), test_info.name());
+ printf("\n");
+ }
+ }
+}
+
+void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ ColoredPrintf(GTestColor::kGreen, "[==========] ");
+ printf("%s from %s ran.",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
+ if (GTEST_FLAG_GET(print_time)) {
+ printf(" (%s ms total)",
+ internal::StreamableToString(unit_test.elapsed_time()).c_str());
+ }
+ printf("\n");
+ ColoredPrintf(GTestColor::kGreen, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+ const int skipped_test_count = unit_test.skipped_test_count();
+ if (skipped_test_count > 0) {
+ ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] ");
+ printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str());
+ PrintSkippedTests(unit_test);
+ }
+
+ if (!unit_test.Passed()) {
+ PrintFailedTests(unit_test);
+ PrintFailedTestSuites(unit_test);
+ }
+
+ int num_disabled = unit_test.reportable_disabled_test_count();
+ if (num_disabled && !GTEST_FLAG_GET(also_run_disabled_tests)) {
+ if (unit_test.Passed()) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(GTestColor::kYellow, " 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
+
+// This class implements the TestEventListener interface.
+//
+// Class BriefUnitTestResultPrinter is copyable.
+class BriefUnitTestResultPrinter : public TestEventListener {
+ public:
+ BriefUnitTestResultPrinter() {}
+ static void PrintTestName(const char* test_suite, const char* test) {
+ printf("%s.%s", test_suite, test);
+ }
+
+ // The following methods override what's in the TestEventListener class.
+ void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) override {}
+ void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestCase& /*test_case*/) override {}
+#else
+ void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {}
+#endif // OnTestCaseStart
+
+ void OnTestStart(const TestInfo& /*test_info*/) override {}
+ void OnTestDisabled(const TestInfo& /*test_info*/) override {}
+
+ void OnTestPartResult(const TestPartResult& result) override;
+ void OnTestEnd(const TestInfo& test_info) override;
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& /*test_case*/) override {}
+#else
+ void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
+};
+
+// Called after an assertion failure.
+void BriefUnitTestResultPrinter::OnTestPartResult(
+ const TestPartResult& result) {
+ switch (result.type()) {
+ // If the test part succeeded, we don't need to do anything.
+ case TestPartResult::kSuccess:
+ return;
+ default:
+ // Print failure message from the assertion
+ // (e.g. expected this and got that).
+ PrintTestPartResult(result);
+ fflush(stdout);
+ }
+}
+
+void BriefUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
+ if (test_info.result()->Failed()) {
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ PrintTestName(test_info.test_suite_name(), test_info.name());
+ PrintFullTestCommentIfPresent(test_info);
+
+ if (GTEST_FLAG_GET(print_time)) {
+ printf(" (%s ms)\n",
+ internal::StreamableToString(test_info.result()->elapsed_time())
+ .c_str());
+ } else {
+ printf("\n");
+ }
+ fflush(stdout);
+ }
+}
+
+void BriefUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ ColoredPrintf(GTestColor::kGreen, "[==========] ");
+ printf("%s from %s ran.",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
+ if (GTEST_FLAG_GET(print_time)) {
+ printf(" (%s ms total)",
+ internal::StreamableToString(unit_test.elapsed_time()).c_str());
+ }
+ printf("\n");
+ ColoredPrintf(GTestColor::kGreen, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+ const int skipped_test_count = unit_test.skipped_test_count();
+ if (skipped_test_count > 0) {
+ ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] ");
+ printf("%s.\n", FormatTestCount(skipped_test_count).c_str());
+ }
+
+ int num_disabled = unit_test.reportable_disabled_test_count();
+ if (num_disabled && !GTEST_FLAG_GET(also_run_disabled_tests)) {
+ if (unit_test.Passed()) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(GTestColor::kYellow, " 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 BriefUnitTestResultPrinter
+
+// class TestEventRepeater
+//
+// This class forwards events to other event listeners.
+class TestEventRepeater : public TestEventListener {
+ public:
+ TestEventRepeater() : forwarding_enabled_(true) {}
+ ~TestEventRepeater() override;
+ 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; }
+
+ void OnTestProgramStart(const UnitTest& unit_test) override;
+ void OnTestIterationStart(const UnitTest& unit_test, int iteration) override;
+ void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override;
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestSuite& parameter) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestSuiteStart(const TestSuite& parameter) override;
+ void OnTestStart(const TestInfo& test_info) override;
+ void OnTestDisabled(const TestInfo& test_info) override;
+ void OnTestPartResult(const TestPartResult& result) override;
+ void OnTestEnd(const TestInfo& test_info) override;
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& parameter) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestSuiteEnd(const TestSuite& parameter) override;
+ void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override;
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void OnTestProgramEnd(const UnitTest& unit_test) override;
+
+ 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<TestEventListener*> listeners_;
+
+ TestEventRepeater(const TestEventRepeater&) = delete;
+ TestEventRepeater& operator=(const TestEventRepeater&) = delete;
+};
+
+TestEventRepeater::~TestEventRepeater() {
+ ForEach(listeners_, Delete<TestEventListener>);
+}
+
+void TestEventRepeater::Append(TestEventListener* listener) {
+ listeners_.push_back(listener);
+}
+
+TestEventListener* TestEventRepeater::Release(TestEventListener* listener) {
+ for (size_t i = 0; i < listeners_.size(); ++i) {
+ if (listeners_[i] == listener) {
+ listeners_.erase(listeners_.begin() + static_cast<int>(i));
+ return listener;
+ }
+ }
+
+ return nullptr;
+}
+
+// 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 (size_t i = listeners_.size(); i != 0; i--) { \
+ listeners_[i - 1]->Name(parameter); \
+ } \
+ } \
+ }
+
+GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite)
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestDisabled, 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)
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite)
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite)
+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 (size_t i = listeners_.size(); i > 0; i--) {
+ listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration);
+ }
+ }
+}
+
+// End TestEventRepeater
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+ explicit XmlUnitTestResultPrinter(const char* output_file);
+
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void ListTestsMatchingFilter(const std::vector<TestSuite*>& test_suites);
+
+ // Prints an XML summary of all unit tests.
+ static void PrintXmlTestsList(std::ostream* stream,
+ const std::vector<TestSuite*>& test_suites);
+
+ private:
+ // Is c a whitespace character that is normalized to a space character
+ // when it appears in an XML attribute value?
+ static bool IsNormalizableWhitespace(unsigned char c) {
+ return c == '\t' || c == '\n' || c == '\r';
+ }
+
+ // May c appear in a well-formed XML document?
+ // https://www.w3.org/TR/REC-xml/#charsets
+ static bool IsValidXmlCharacter(unsigned 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 std::string EscapeXml(const std::string& str, bool is_attribute);
+
+ // Returns the given string with all characters invalid in XML removed.
+ static std::string RemoveInvalidXmlCharacters(const std::string& str);
+
+ // Convenience wrapper around EscapeXml when str is an attribute value.
+ static std::string EscapeXmlAttribute(const std::string& str) {
+ return EscapeXml(str, true);
+ }
+
+ // Convenience wrapper around EscapeXml when str is not an attribute value.
+ static std::string EscapeXmlText(const char* str) {
+ return EscapeXml(str, false);
+ }
+
+ // Verifies that the given attribute belongs to the given element and
+ // streams the attribute as XML.
+ static void OutputXmlAttribute(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value);
+
+ // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+ static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
+
+ // Streams a test suite XML stanza containing the given test result.
+ //
+ // Requires: result.Failed()
+ static void OutputXmlTestSuiteForTestResult(::std::ostream* stream,
+ const TestResult& result);
+
+ // Streams an XML representation of a TestResult object.
+ static void OutputXmlTestResult(::std::ostream* stream,
+ const TestResult& result);
+
+ // Streams an XML representation of a TestInfo object.
+ static void OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info);
+
+ // Prints an XML representation of a TestSuite object
+ static void PrintXmlTestSuite(::std::ostream* stream,
+ const TestSuite& test_suite);
+
+ // Prints an XML summary of unit_test to output stream out.
+ static void PrintXmlUnitTest(::std::ostream* stream,
+ 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 std::string is not empty, it includes a space at the beginning,
+ // to delimit this attribute from prior attributes.
+ static std::string TestPropertiesAsXmlAttributes(const TestResult& result);
+
+ // Streams an XML representation of the test properties of a TestResult
+ // object.
+ static void OutputXmlTestProperties(std::ostream* stream,
+ const TestResult& result);
+
+ // The output file.
+ const std::string output_file_;
+
+ XmlUnitTestResultPrinter(const XmlUnitTestResultPrinter&) = delete;
+ XmlUnitTestResultPrinter& operator=(const XmlUnitTestResultPrinter&) = delete;
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.empty()) {
+ GTEST_LOG_(FATAL) << "XML output file may not be null";
+ }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ FILE* xmlout = OpenFileForWriting(output_file_);
+ std::stringstream stream;
+ PrintXmlUnitTest(&stream, unit_test);
+ fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
+ fclose(xmlout);
+}
+
+void XmlUnitTestResultPrinter::ListTestsMatchingFilter(
+ const std::vector<TestSuite*>& test_suites) {
+ FILE* xmlout = OpenFileForWriting(output_file_);
+ std::stringstream stream;
+ PrintXmlTestsList(&stream, test_suites);
+ fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
+ 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.
+std::string XmlUnitTestResultPrinter::EscapeXml(const std::string& str,
+ bool is_attribute) {
+ Message m;
+
+ for (size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ switch (ch) {
+ case '<':
+ m << "&lt;";
+ break;
+ case '>':
+ m << "&gt;";
+ break;
+ case '&':
+ m << "&amp;";
+ break;
+ case '\'':
+ if (is_attribute)
+ m << "&apos;";
+ else
+ m << '\'';
+ break;
+ case '"':
+ if (is_attribute)
+ m << "&quot;";
+ else
+ m << '"';
+ break;
+ default:
+ if (IsValidXmlCharacter(static_cast<unsigned char>(ch))) {
+ if (is_attribute &&
+ IsNormalizableWhitespace(static_cast<unsigned char>(ch)))
+ m << "&#x" << String::FormatByte(static_cast<unsigned char>(ch))
+ << ";";
+ else
+ m << ch;
+ }
+ 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 ?.
+std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
+ const std::string& str) {
+ std::string output;
+ output.reserve(str.size());
+ for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
+ if (IsValidXmlCharacter(static_cast<unsigned char>(*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:
+//
+// <testsuites name="AllTests"> <-- corresponds to a UnitTest object
+// <testsuite name="testcase-name"> <-- corresponds to a TestSuite object
+// <testcase name="test-name"> <-- corresponds to a TestInfo object
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <-- individual assertion failures
+// </testcase>
+// </testsuite>
+// </testsuites>
+
+// Formats the given time in milliseconds as seconds.
+std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
+ ::std::stringstream ss;
+ ss << (static_cast<double>(ms) * 1e-3);
+ return ss.str();
+}
+
+static bool PortableLocaltime(time_t seconds, struct tm* out) {
+#if defined(_MSC_VER)
+ return localtime_s(out, &seconds) == 0;
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+ // MINGW <time.h> provides neither localtime_r nor localtime_s, but uses
+ // Windows' localtime(), which has a thread-local tm buffer.
+ struct tm* tm_ptr = localtime(&seconds); // NOLINT
+ if (tm_ptr == nullptr) return false;
+ *out = *tm_ptr;
+ return true;
+#elif defined(__STDC_LIB_EXT1__)
+ // Uses localtime_s when available as localtime_r is only available from
+ // C23 standard.
+ return localtime_s(&seconds, out) != nullptr;
+#else
+ return localtime_r(&seconds, out) != nullptr;
+#endif
+}
+
+// Converts the given epoch time in milliseconds to a date string in the ISO
+// 8601 format, without the timezone information.
+std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
+ struct tm time_struct;
+ if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct))
+ return "";
+ // YYYY-MM-DDThh:mm:ss.sss
+ return StreamableToString(time_struct.tm_year + 1900) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mday) + "T" +
+ String::FormatIntWidth2(time_struct.tm_hour) + ":" +
+ String::FormatIntWidth2(time_struct.tm_min) + ":" +
+ String::FormatIntWidth2(time_struct.tm_sec) + "." +
+ String::FormatIntWidthN(static_cast<int>(ms % 1000), 3);
+}
+
+// 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 << "<![CDATA[";
+ for (;;) {
+ const char* const next_segment = strstr(segment, "]]>");
+ if (next_segment != nullptr) {
+ stream->write(segment,
+ static_cast<std::streamsize>(next_segment - segment));
+ *stream << "]]>]]&gt;<![CDATA[";
+ segment = next_segment + strlen("]]>");
+ } else {
+ *stream << segment;
+ break;
+ }
+ }
+ *stream << "]]>";
+}
+
+void XmlUnitTestResultPrinter::OutputXmlAttribute(
+ std::ostream* stream, const std::string& element_name,
+ const std::string& name, const std::string& value) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedOutputAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Attribute " << name << " is not allowed for element <" << element_name
+ << ">.";
+
+ *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\"";
+}
+
+// Streams a test suite XML stanza containing the given test result.
+void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult(
+ ::std::ostream* stream, const TestResult& result) {
+ // Output the boilerplate for a minimal test suite with one test.
+ *stream << " <testsuite";
+ OutputXmlAttribute(stream, "testsuite", "name", "NonTestSuiteFailure");
+ OutputXmlAttribute(stream, "testsuite", "tests", "1");
+ OutputXmlAttribute(stream, "testsuite", "failures", "1");
+ OutputXmlAttribute(stream, "testsuite", "disabled", "0");
+ OutputXmlAttribute(stream, "testsuite", "skipped", "0");
+ OutputXmlAttribute(stream, "testsuite", "errors", "0");
+ OutputXmlAttribute(stream, "testsuite", "time",
+ FormatTimeInMillisAsSeconds(result.elapsed_time()));
+ OutputXmlAttribute(
+ stream, "testsuite", "timestamp",
+ FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+ *stream << ">";
+
+ // Output the boilerplate for a minimal test case with a single test.
+ *stream << " <testcase";
+ OutputXmlAttribute(stream, "testcase", "name", "");
+ OutputXmlAttribute(stream, "testcase", "status", "run");
+ OutputXmlAttribute(stream, "testcase", "result", "completed");
+ OutputXmlAttribute(stream, "testcase", "classname", "");
+ OutputXmlAttribute(stream, "testcase", "time",
+ FormatTimeInMillisAsSeconds(result.elapsed_time()));
+ OutputXmlAttribute(
+ stream, "testcase", "timestamp",
+ FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+
+ // Output the actual test result.
+ OutputXmlTestResult(stream, result);
+
+ // Complete the test suite.
+ *stream << " </testsuite>\n";
+}
+
+// Prints an XML representation of a TestInfo object.
+void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info) {
+ const TestResult& result = *test_info.result();
+ const std::string kTestsuite = "testcase";
+
+ if (test_info.is_in_another_shard()) {
+ return;
+ }
+
+ *stream << " <testcase";
+ OutputXmlAttribute(stream, kTestsuite, "name", test_info.name());
+
+ if (test_info.value_param() != nullptr) {
+ OutputXmlAttribute(stream, kTestsuite, "value_param",
+ test_info.value_param());
+ }
+ if (test_info.type_param() != nullptr) {
+ OutputXmlAttribute(stream, kTestsuite, "type_param",
+ test_info.type_param());
+ }
+
+ OutputXmlAttribute(stream, kTestsuite, "file", test_info.file());
+ OutputXmlAttribute(stream, kTestsuite, "line",
+ StreamableToString(test_info.line()));
+ if (GTEST_FLAG_GET(list_tests)) {
+ *stream << " />\n";
+ return;
+ }
+
+ OutputXmlAttribute(stream, kTestsuite, "status",
+ test_info.should_run() ? "run" : "notrun");
+ OutputXmlAttribute(stream, kTestsuite, "result",
+ test_info.should_run()
+ ? (result.Skipped() ? "skipped" : "completed")
+ : "suppressed");
+ OutputXmlAttribute(stream, kTestsuite, "time",
+ FormatTimeInMillisAsSeconds(result.elapsed_time()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+ OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name);
+
+ OutputXmlTestResult(stream, result);
+}
+
+void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream,
+ const TestResult& result) {
+ int failures = 0;
+ int skips = 0;
+ for (int i = 0; i < result.total_part_count(); ++i) {
+ const TestPartResult& part = result.GetTestPartResult(i);
+ if (part.failed()) {
+ if (++failures == 1 && skips == 0) {
+ *stream << ">\n";
+ }
+ const std::string location =
+ internal::FormatCompilerIndependentFileLocation(part.file_name(),
+ part.line_number());
+ const std::string summary = location + "\n" + part.summary();
+ *stream << " <failure message=\"" << EscapeXmlAttribute(summary)
+ << "\" type=\"\">";
+ const std::string detail = location + "\n" + part.message();
+ OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
+ *stream << "</failure>\n";
+ } else if (part.skipped()) {
+ if (++skips == 1 && failures == 0) {
+ *stream << ">\n";
+ }
+ const std::string location =
+ internal::FormatCompilerIndependentFileLocation(part.file_name(),
+ part.line_number());
+ const std::string summary = location + "\n" + part.summary();
+ *stream << " <skipped message=\""
+ << EscapeXmlAttribute(summary.c_str()) << "\">";
+ const std::string detail = location + "\n" + part.message();
+ OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
+ *stream << "</skipped>\n";
+ }
+ }
+
+ if (failures == 0 && skips == 0 && result.test_property_count() == 0) {
+ *stream << " />\n";
+ } else {
+ if (failures == 0 && skips == 0) {
+ *stream << ">\n";
+ }
+ OutputXmlTestProperties(stream, result);
+ *stream << " </testcase>\n";
+ }
+}
+
+// Prints an XML representation of a TestSuite object
+void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream,
+ const TestSuite& test_suite) {
+ const std::string kTestsuite = "testsuite";
+ *stream << " <" << kTestsuite;
+ OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name());
+ OutputXmlAttribute(stream, kTestsuite, "tests",
+ StreamableToString(test_suite.reportable_test_count()));
+ if (!GTEST_FLAG_GET(list_tests)) {
+ OutputXmlAttribute(stream, kTestsuite, "failures",
+ StreamableToString(test_suite.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "disabled",
+ StreamableToString(test_suite.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuite, "skipped",
+ StreamableToString(test_suite.skipped_test_count()));
+
+ OutputXmlAttribute(stream, kTestsuite, "errors", "0");
+
+ OutputXmlAttribute(stream, kTestsuite, "time",
+ FormatTimeInMillisAsSeconds(test_suite.elapsed_time()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp()));
+ *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result());
+ }
+ *stream << ">\n";
+ for (int i = 0; i < test_suite.total_test_count(); ++i) {
+ if (test_suite.GetTestInfo(i)->is_reportable())
+ OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i));
+ }
+ *stream << " </" << kTestsuite << ">\n";
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
+ const UnitTest& unit_test) {
+ const std::string kTestsuites = "testsuites";
+
+ *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ *stream << "<" << kTestsuites;
+
+ OutputXmlAttribute(stream, kTestsuites, "tests",
+ StreamableToString(unit_test.reportable_test_count()));
+ OutputXmlAttribute(stream, kTestsuites, "failures",
+ StreamableToString(unit_test.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuites, "disabled",
+ StreamableToString(unit_test.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuites, "errors", "0");
+ OutputXmlAttribute(stream, kTestsuites, "time",
+ FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
+ OutputXmlAttribute(
+ stream, kTestsuites, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
+
+ if (GTEST_FLAG_GET(shuffle)) {
+ OutputXmlAttribute(stream, kTestsuites, "random_seed",
+ StreamableToString(unit_test.random_seed()));
+ }
+ *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());
+
+ OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+ *stream << ">\n";
+
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ if (unit_test.GetTestSuite(i)->reportable_test_count() > 0)
+ PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i));
+ }
+
+ // If there was a test failure outside of one of the test suites (like in a
+ // test environment) include that in the output.
+ if (unit_test.ad_hoc_test_result().Failed()) {
+ OutputXmlTestSuiteForTestResult(stream, unit_test.ad_hoc_test_result());
+ }
+
+ *stream << "</" << kTestsuites << ">\n";
+}
+
+void XmlUnitTestResultPrinter::PrintXmlTestsList(
+ std::ostream* stream, const std::vector<TestSuite*>& test_suites) {
+ const std::string kTestsuites = "testsuites";
+
+ *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ *stream << "<" << kTestsuites;
+
+ int total_tests = 0;
+ for (auto test_suite : test_suites) {
+ total_tests += test_suite->total_test_count();
+ }
+ OutputXmlAttribute(stream, kTestsuites, "tests",
+ StreamableToString(total_tests));
+ OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+ *stream << ">\n";
+
+ for (auto test_suite : test_suites) {
+ PrintXmlTestSuite(stream, *test_suite);
+ }
+ *stream << "</" << kTestsuites << ">\n";
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+std::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();
+}
+
+void XmlUnitTestResultPrinter::OutputXmlTestProperties(
+ std::ostream* stream, const TestResult& result) {
+ const std::string kProperties = "properties";
+ const std::string kProperty = "property";
+
+ if (result.test_property_count() <= 0) {
+ return;
+ }
+
+ *stream << " <" << kProperties << ">\n";
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ *stream << " <" << kProperty;
+ *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\"";
+ *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\"";
+ *stream << "/>\n";
+ }
+ *stream << " </" << kProperties << ">\n";
+}
+
+// End XmlUnitTestResultPrinter
+
+// This class generates an JSON output file.
+class JsonUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+ explicit JsonUnitTestResultPrinter(const char* output_file);
+
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+
+ // Prints an JSON summary of all unit tests.
+ static void PrintJsonTestList(::std::ostream* stream,
+ const std::vector<TestSuite*>& test_suites);
+
+ private:
+ // Returns an JSON-escaped copy of the input string str.
+ static std::string EscapeJson(const std::string& str);
+
+ //// Verifies that the given attribute belongs to the given element and
+ //// streams the attribute as JSON.
+ static void OutputJsonKey(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name, const std::string& value,
+ const std::string& indent, bool comma = true);
+ static void OutputJsonKey(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name, int value,
+ const std::string& indent, bool comma = true);
+
+ // Streams a test suite JSON stanza containing the given test result.
+ //
+ // Requires: result.Failed()
+ static void OutputJsonTestSuiteForTestResult(::std::ostream* stream,
+ const TestResult& result);
+
+ // Streams a JSON representation of a TestResult object.
+ static void OutputJsonTestResult(::std::ostream* stream,
+ const TestResult& result);
+
+ // Streams a JSON representation of a TestInfo object.
+ static void OutputJsonTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info);
+
+ // Prints a JSON representation of a TestSuite object
+ static void PrintJsonTestSuite(::std::ostream* stream,
+ const TestSuite& test_suite);
+
+ // Prints a JSON summary of unit_test to output stream out.
+ static void PrintJsonUnitTest(::std::ostream* stream,
+ const UnitTest& unit_test);
+
+ // Produces a string representing the test properties in a result as
+ // a JSON dictionary.
+ static std::string TestPropertiesAsJson(const TestResult& result,
+ const std::string& indent);
+
+ // The output file.
+ const std::string output_file_;
+
+ JsonUnitTestResultPrinter(const JsonUnitTestResultPrinter&) = delete;
+ JsonUnitTestResultPrinter& operator=(const JsonUnitTestResultPrinter&) =
+ delete;
+};
+
+// Creates a new JsonUnitTestResultPrinter.
+JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.empty()) {
+ GTEST_LOG_(FATAL) << "JSON output file may not be null";
+ }
+}
+
+void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ FILE* jsonout = OpenFileForWriting(output_file_);
+ std::stringstream stream;
+ PrintJsonUnitTest(&stream, unit_test);
+ fprintf(jsonout, "%s", StringStreamToString(&stream).c_str());
+ fclose(jsonout);
+}
+
+// Returns an JSON-escaped copy of the input string str.
+std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) {
+ Message m;
+
+ for (size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ switch (ch) {
+ case '\\':
+ case '"':
+ case '/':
+ m << '\\' << ch;
+ break;
+ case '\b':
+ m << "\\b";
+ break;
+ case '\t':
+ m << "\\t";
+ break;
+ case '\n':
+ m << "\\n";
+ break;
+ case '\f':
+ m << "\\f";
+ break;
+ case '\r':
+ m << "\\r";
+ break;
+ default:
+ if (ch < ' ') {
+ m << "\\u00" << String::FormatByte(static_cast<unsigned char>(ch));
+ } else {
+ m << ch;
+ }
+ break;
+ }
+ }
+
+ return m.GetString();
+}
+
+// The following routines generate an JSON representation of a UnitTest
+// object.
+
+// Formats the given time in milliseconds as seconds.
+static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) {
+ ::std::stringstream ss;
+ ss << (static_cast<double>(ms) * 1e-3) << "s";
+ return ss.str();
+}
+
+// Converts the given epoch time in milliseconds to a date string in the
+// RFC3339 format, without the timezone information.
+static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) {
+ struct tm time_struct;
+ if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct))
+ return "";
+ // YYYY-MM-DDThh:mm:ss
+ return StreamableToString(time_struct.tm_year + 1900) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mday) + "T" +
+ String::FormatIntWidth2(time_struct.tm_hour) + ":" +
+ String::FormatIntWidth2(time_struct.tm_min) + ":" +
+ String::FormatIntWidth2(time_struct.tm_sec) + "Z";
+}
+
+static inline std::string Indent(size_t width) {
+ return std::string(width, ' ');
+}
+
+void JsonUnitTestResultPrinter::OutputJsonKey(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value,
+ const std::string& indent,
+ bool comma) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedOutputAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Key \"" << name << "\" is not allowed for value \"" << element_name
+ << "\".";
+
+ *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\"";
+ if (comma) *stream << ",\n";
+}
+
+void JsonUnitTestResultPrinter::OutputJsonKey(
+ std::ostream* stream, const std::string& element_name,
+ const std::string& name, int value, const std::string& indent, bool comma) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedOutputAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Key \"" << name << "\" is not allowed for value \"" << element_name
+ << "\".";
+
+ *stream << indent << "\"" << name << "\": " << StreamableToString(value);
+ if (comma) *stream << ",\n";
+}
+
+// Streams a test suite JSON stanza containing the given test result.
+void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult(
+ ::std::ostream* stream, const TestResult& result) {
+ // Output the boilerplate for a new test suite.
+ *stream << Indent(4) << "{\n";
+ OutputJsonKey(stream, "testsuite", "name", "NonTestSuiteFailure", Indent(6));
+ OutputJsonKey(stream, "testsuite", "tests", 1, Indent(6));
+ if (!GTEST_FLAG_GET(list_tests)) {
+ OutputJsonKey(stream, "testsuite", "failures", 1, Indent(6));
+ OutputJsonKey(stream, "testsuite", "disabled", 0, Indent(6));
+ OutputJsonKey(stream, "testsuite", "skipped", 0, Indent(6));
+ OutputJsonKey(stream, "testsuite", "errors", 0, Indent(6));
+ OutputJsonKey(stream, "testsuite", "time",
+ FormatTimeInMillisAsDuration(result.elapsed_time()),
+ Indent(6));
+ OutputJsonKey(stream, "testsuite", "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+ Indent(6));
+ }
+ *stream << Indent(6) << "\"testsuite\": [\n";
+
+ // Output the boilerplate for a new test case.
+ *stream << Indent(8) << "{\n";
+ OutputJsonKey(stream, "testcase", "name", "", Indent(10));
+ OutputJsonKey(stream, "testcase", "status", "RUN", Indent(10));
+ OutputJsonKey(stream, "testcase", "result", "COMPLETED", Indent(10));
+ OutputJsonKey(stream, "testcase", "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+ Indent(10));
+ OutputJsonKey(stream, "testcase", "time",
+ FormatTimeInMillisAsDuration(result.elapsed_time()),
+ Indent(10));
+ OutputJsonKey(stream, "testcase", "classname", "", Indent(10), false);
+ *stream << TestPropertiesAsJson(result, Indent(10));
+
+ // Output the actual test result.
+ OutputJsonTestResult(stream, result);
+
+ // Finish the test suite.
+ *stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}";
+}
+
+// Prints a JSON representation of a TestInfo object.
+void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info) {
+ const TestResult& result = *test_info.result();
+ const std::string kTestsuite = "testcase";
+ const std::string kIndent = Indent(10);
+
+ *stream << Indent(8) << "{\n";
+ OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent);
+
+ if (test_info.value_param() != nullptr) {
+ OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(),
+ kIndent);
+ }
+ if (test_info.type_param() != nullptr) {
+ OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(),
+ kIndent);
+ }
+
+ OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false);
+ if (GTEST_FLAG_GET(list_tests)) {
+ *stream << "\n" << Indent(8) << "}";
+ return;
+ } else {
+ *stream << ",\n";
+ }
+
+ OutputJsonKey(stream, kTestsuite, "status",
+ test_info.should_run() ? "RUN" : "NOTRUN", kIndent);
+ OutputJsonKey(stream, kTestsuite, "result",
+ test_info.should_run()
+ ? (result.Skipped() ? "SKIPPED" : "COMPLETED")
+ : "SUPPRESSED",
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "time",
+ FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent);
+ OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent,
+ false);
+ *stream << TestPropertiesAsJson(result, kIndent);
+
+ OutputJsonTestResult(stream, result);
+}
+
+void JsonUnitTestResultPrinter::OutputJsonTestResult(::std::ostream* stream,
+ const TestResult& result) {
+ const std::string kIndent = Indent(10);
+
+ int failures = 0;
+ for (int i = 0; i < result.total_part_count(); ++i) {
+ const TestPartResult& part = result.GetTestPartResult(i);
+ if (part.failed()) {
+ *stream << ",\n";
+ if (++failures == 1) {
+ *stream << kIndent << "\""
+ << "failures"
+ << "\": [\n";
+ }
+ const std::string location =
+ internal::FormatCompilerIndependentFileLocation(part.file_name(),
+ part.line_number());
+ const std::string message = EscapeJson(location + "\n" + part.message());
+ *stream << kIndent << " {\n"
+ << kIndent << " \"failure\": \"" << message << "\",\n"
+ << kIndent << " \"type\": \"\"\n"
+ << kIndent << " }";
+ }
+ }
+
+ if (failures > 0) *stream << "\n" << kIndent << "]";
+ *stream << "\n" << Indent(8) << "}";
+}
+
+// Prints an JSON representation of a TestSuite object
+void JsonUnitTestResultPrinter::PrintJsonTestSuite(
+ std::ostream* stream, const TestSuite& test_suite) {
+ const std::string kTestsuite = "testsuite";
+ const std::string kIndent = Indent(6);
+
+ *stream << Indent(4) << "{\n";
+ OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(),
+ kIndent);
+ if (!GTEST_FLAG_GET(list_tests)) {
+ OutputJsonKey(stream, kTestsuite, "failures",
+ test_suite.failed_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "disabled",
+ test_suite.reportable_disabled_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent);
+ OutputJsonKey(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "time",
+ FormatTimeInMillisAsDuration(test_suite.elapsed_time()),
+ kIndent, false);
+ *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent)
+ << ",\n";
+ }
+
+ *stream << kIndent << "\"" << kTestsuite << "\": [\n";
+
+ bool comma = false;
+ for (int i = 0; i < test_suite.total_test_count(); ++i) {
+ if (test_suite.GetTestInfo(i)->is_reportable()) {
+ if (comma) {
+ *stream << ",\n";
+ } else {
+ comma = true;
+ }
+ OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i));
+ }
+ }
+ *stream << "\n" << kIndent << "]\n" << Indent(4) << "}";
+}
+
+// Prints a JSON summary of unit_test to output stream out.
+void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream,
+ const UnitTest& unit_test) {
+ const std::string kTestsuites = "testsuites";
+ const std::string kIndent = Indent(2);
+ *stream << "{\n";
+
+ OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "disabled",
+ unit_test.reportable_disabled_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent);
+ if (GTEST_FLAG_GET(shuffle)) {
+ OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(),
+ kIndent);
+ }
+ OutputJsonKey(stream, kTestsuites, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "time",
+ FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent,
+ false);
+
+ *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent)
+ << ",\n";
+
+ OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent);
+ *stream << kIndent << "\"" << kTestsuites << "\": [\n";
+
+ bool comma = false;
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) {
+ if (comma) {
+ *stream << ",\n";
+ } else {
+ comma = true;
+ }
+ PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i));
+ }
+ }
+
+ // If there was a test failure outside of one of the test suites (like in a
+ // test environment) include that in the output.
+ if (unit_test.ad_hoc_test_result().Failed()) {
+ OutputJsonTestSuiteForTestResult(stream, unit_test.ad_hoc_test_result());
+ }
+
+ *stream << "\n"
+ << kIndent << "]\n"
+ << "}\n";
+}
+
+void JsonUnitTestResultPrinter::PrintJsonTestList(
+ std::ostream* stream, const std::vector<TestSuite*>& test_suites) {
+ const std::string kTestsuites = "testsuites";
+ const std::string kIndent = Indent(2);
+ *stream << "{\n";
+ int total_tests = 0;
+ for (auto test_suite : test_suites) {
+ total_tests += test_suite->total_test_count();
+ }
+ OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent);
+
+ OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent);
+ *stream << kIndent << "\"" << kTestsuites << "\": [\n";
+
+ for (size_t i = 0; i < test_suites.size(); ++i) {
+ if (i != 0) {
+ *stream << ",\n";
+ }
+ PrintJsonTestSuite(stream, *test_suites[i]);
+ }
+
+ *stream << "\n"
+ << kIndent << "]\n"
+ << "}\n";
+}
+// Produces a string representing the test properties in a result as
+// a JSON dictionary.
+std::string JsonUnitTestResultPrinter::TestPropertiesAsJson(
+ const TestResult& result, const std::string& indent) {
+ Message attributes;
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ attributes << ",\n"
+ << indent << "\"" << property.key() << "\": "
+ << "\"" << EscapeJson(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+// End JsonUnitTestResultPrinter
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// 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.
+std::string StreamingListener::UrlEncode(const char* str) {
+ std::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::FormatByte(static_cast<unsigned char>(ch)));
+ break;
+ default:
+ result.push_back(ch);
+ break;
+ }
+ }
+ return result;
+}
+
+void StreamingListener::SocketWriter::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 = nullptr;
+
+ // 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 != nullptr;
+ 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 OsStackTraceGetter
+
+const char* const OsStackTraceGetterInterface::kElidedFramesMarker =
+ "... " GTEST_NAME_ " internal frames ...";
+
+std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count)
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+#if GTEST_HAS_ABSL
+ std::string result;
+
+ if (max_depth <= 0) {
+ return result;
+ }
+
+ max_depth = std::min(max_depth, kMaxStackTraceDepth);
+
+ std::vector<void*> raw_stack(max_depth);
+ // Skips the frames requested by the caller, plus this function.
+ const int raw_stack_size =
+ absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1);
+
+ void* caller_frame = nullptr;
+ {
+ MutexLock lock(&mutex_);
+ caller_frame = caller_frame_;
+ }
+
+ for (int i = 0; i < raw_stack_size; ++i) {
+ if (raw_stack[i] == caller_frame &&
+ !GTEST_FLAG_GET(show_internal_stack_frames)) {
+ // Add a marker to the trace and stop adding frames.
+ absl::StrAppend(&result, kElidedFramesMarker, "\n");
+ break;
+ }
+
+ char tmp[1024];
+ const char* symbol = "(unknown)";
+ if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) {
+ symbol = tmp;
+ }
+
+ char line[1024];
+ snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol);
+ result += line;
+ }
+
+ return result;
+
+#else // !GTEST_HAS_ABSL
+ static_cast<void>(max_depth);
+ static_cast<void>(skip_count);
+ return "";
+#endif // GTEST_HAS_ABSL
+}
+
+void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) {
+#if GTEST_HAS_ABSL
+ void* caller_frame = nullptr;
+ if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) {
+ caller_frame = nullptr;
+ }
+
+ MutexLock lock(&mutex_);
+ caller_frame_ = caller_frame;
+#endif // GTEST_HAS_ABSL
+}
+
+// A helper class that creates the premature-exit file in its
+// constructor and deletes the file in its destructor.
+class ScopedPrematureExitFile {
+ public:
+ explicit ScopedPrematureExitFile(const char* premature_exit_filepath)
+ : premature_exit_filepath_(
+ premature_exit_filepath ? premature_exit_filepath : "") {
+ // If a path to the premature-exit file is specified...
+ if (!premature_exit_filepath_.empty()) {
+ // create the file with a single "0" character in it. I/O
+ // errors are ignored as there's nothing better we can do and we
+ // don't want to fail the test because of this.
+ FILE* pfile = posix::FOpen(premature_exit_filepath_.c_str(), "w");
+ fwrite("0", 1, 1, pfile);
+ fclose(pfile);
+ }
+ }
+
+ ~ScopedPrematureExitFile() {
+#if !defined GTEST_OS_ESP8266
+ if (!premature_exit_filepath_.empty()) {
+ int retval = remove(premature_exit_filepath_.c_str());
+ if (retval) {
+ GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \""
+ << premature_exit_filepath_ << "\" with error "
+ << retval;
+ }
+ }
+#endif
+ }
+
+ private:
+ const std::string premature_exit_filepath_;
+
+ ScopedPrematureExitFile(const ScopedPrematureExitFile&) = delete;
+ ScopedPrematureExitFile& operator=(const ScopedPrematureExitFile&) = delete;
+};
+
+} // namespace internal
+
+// class TestEventListeners
+
+TestEventListeners::TestEventListeners()
+ : repeater_(new internal::TestEventRepeater()),
+ default_result_printer_(nullptr),
+ default_xml_generator_(nullptr) {}
+
+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_ = nullptr;
+ else if (listener == default_xml_generator_)
+ default_xml_generator_ = nullptr;
+ 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 != nullptr) 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 != nullptr) 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() {
+ // CodeGear C++Builder insists on a public destructor for the
+ // default implementation. Use this implementation to keep good OO
+ // design with private destructor.
+
+#if defined(__BORLANDC__)
+ static UnitTest* const instance = new UnitTest;
+ return instance;
+#else
+ static UnitTest instance;
+ return &instance;
+#endif // defined(__BORLANDC__)
+}
+
+// Gets the number of successful test suites.
+int UnitTest::successful_test_suite_count() const {
+ return impl()->successful_test_suite_count();
+}
+
+// Gets the number of failed test suites.
+int UnitTest::failed_test_suite_count() const {
+ return impl()->failed_test_suite_count();
+}
+
+// Gets the number of all test suites.
+int UnitTest::total_test_suite_count() const {
+ return impl()->total_test_suite_count();
+}
+
+// Gets the number of all test suites that contain at least one test
+// that should run.
+int UnitTest::test_suite_to_run_count() const {
+ return impl()->test_suite_to_run_count();
+}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+int UnitTest::successful_test_case_count() const {
+ return impl()->successful_test_suite_count();
+}
+int UnitTest::failed_test_case_count() const {
+ return impl()->failed_test_suite_count();
+}
+int UnitTest::total_test_case_count() const {
+ return impl()->total_test_suite_count();
+}
+int UnitTest::test_case_to_run_count() const {
+ return impl()->test_suite_to_run_count();
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+// Gets the number of successful tests.
+int UnitTest::successful_test_count() const {
+ return impl()->successful_test_count();
+}
+
+// Gets the number of skipped tests.
+int UnitTest::skipped_test_count() const {
+ return impl()->skipped_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 that will be reported in the XML report.
+int UnitTest::reportable_disabled_test_count() const {
+ return impl()->reportable_disabled_test_count();
+}
+
+// Gets the number of disabled tests.
+int UnitTest::disabled_test_count() const {
+ return impl()->disabled_test_count();
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTest::reportable_test_count() const {
+ return impl()->reportable_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 time of the test program start, in ms from the start of the
+// UNIX epoch.
+internal::TimeInMillis UnitTest::start_timestamp() const {
+ return impl()->start_timestamp();
+}
+
+// Gets the elapsed time, in milliseconds.
+internal::TimeInMillis UnitTest::elapsed_time() const {
+ return impl()->elapsed_time();
+}
+
+// Returns true if and only if the unit test passed (i.e. all test suites
+// passed).
+bool UnitTest::Passed() const { return impl()->Passed(); }
+
+// Returns true if and only if the unit test failed (i.e. some test suite
+// failed or something outside of all tests failed).
+bool UnitTest::Failed() const { return impl()->Failed(); }
+
+// Gets the i-th test suite among all the test suites. i can range from 0 to
+// total_test_suite_count() - 1. If i is not in that range, returns NULL.
+const TestSuite* UnitTest::GetTestSuite(int i) const {
+ return impl()->GetTestSuite(i);
+}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+const TestCase* UnitTest::GetTestCase(int i) const {
+ return impl()->GetTestCase(i);
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+// Returns the TestResult containing information on test failures and
+// properties logged outside of individual test suites.
+const TestResult& UnitTest::ad_hoc_test_result() const {
+ return *impl()->ad_hoc_test_result();
+}
+
+// Gets the i-th test suite among all the test suites. i can range from 0 to
+// total_test_suite_count() - 1. If i is not in that range, returns NULL.
+TestSuite* UnitTest::GetMutableTestSuite(int i) {
+ return impl()->GetMutableSuiteCase(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 == nullptr) {
+ return nullptr;
+ }
+
+ 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.
+void UnitTest::AddTestPartResult(TestPartResult::Type result_type,
+ const char* file_name, int line_number,
+ const std::string& message,
+ const std::string& os_stack_trace)
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ Message msg;
+ msg << message;
+
+ internal::MutexLock lock(&mutex_);
+ if (impl_->gtest_trace_stack().size() > 0) {
+ msg << "\n" << GTEST_NAME_ << " trace:";
+
+ for (size_t i = 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() != nullptr && !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 &&
+ result_type != TestPartResult::kSkip) {
+ // 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_GET(break_on_failure)) {
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+ // 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();
+#elif (!defined(__native_client__)) && \
+ ((defined(__clang__) || defined(__GNUC__)) && \
+ (defined(__x86_64__) || defined(__i386__)))
+ // with clang/gcc we can achieve the same effect on x86 by invoking int3
+ asm("int3");
+#else
+ // Dereference nullptr through a volatile pointer to prevent the compiler
+ // from removing. We use this rather than abort() or __builtin_trap() for
+ // portability: some debuggers don't correctly trap abort().
+ *static_cast<volatile int*>(nullptr) = 1;
+#endif // GTEST_OS_WINDOWS
+ } else if (GTEST_FLAG_GET(throw_on_failure)) {
+#if GTEST_HAS_EXCEPTIONS
+ throw internal::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
+ }
+ }
+}
+
+// Adds a TestProperty to the current TestResult object when invoked from
+// inside a test, to current TestSuite's ad_hoc_test_result_ when invoked
+// from SetUpTestSuite or TearDownTestSuite, or to the global property set
+// when invoked elsewhere. If the result already contains a property with
+// the same key, the value will be updated.
+void UnitTest::RecordProperty(const std::string& key,
+ const std::string& value) {
+ impl_->RecordProperty(TestProperty(key, value));
+}
+
+// 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() {
+ const bool in_death_test_child_process =
+ GTEST_FLAG_GET(internal_run_death_test).length() > 0;
+
+ // Google Test implements this protocol for catching that a test
+ // program exits before returning control to Google Test:
+ //
+ // 1. Upon start, Google Test creates a file whose absolute path
+ // is specified by the environment variable
+ // TEST_PREMATURE_EXIT_FILE.
+ // 2. When Google Test has finished its work, it deletes the file.
+ //
+ // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before
+ // running a Google-Test-based test program and check the existence
+ // of the file at the end of the test execution to see if it has
+ // exited prematurely.
+
+ // If we are in the child process of a death test, don't
+ // create/delete the premature exit file, as doing so is unnecessary
+ // and will confuse the parent process. Otherwise, create/delete
+ // the file upon entering/leaving this function. If the program
+ // somehow exits before this function has a chance to return, the
+ // premature-exit file will be left undeleted, causing a test runner
+ // that understands the premature-exit-file protocol to report the
+ // test as having failed.
+ const internal::ScopedPrematureExitFile premature_exit_file(
+ in_death_test_child_process
+ ? nullptr
+ : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));
+
+ // 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_GET(catch_exceptions));
+
+#if GTEST_OS_WINDOWS
+ // 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 && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+ // 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 defined(_MSC_VER) && !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.
+ if (!GTEST_FLAG_GET(break_on_failure))
+ _set_abort_behavior(
+ 0x0, // Clear the following flags:
+ _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
+
+ // In debug mode, the Windows CRT can crash with an assertion over invalid
+ // input (e.g. passing an invalid file descriptor). The default handling
+ // for these assertions is to pop up a dialog and wait for user input.
+ // Instead ask the CRT to dump such assertions to stderr non-interactively.
+ if (!IsDebuggerPresent()) {
+ (void)_CrtSetReportMode(_CRT_ASSERT,
+ _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ }
+#endif
+ }
+#endif // GTEST_OS_WINDOWS
+
+ 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 TestSuite object for the test that's currently running,
+// or NULL if no test is running.
+const TestSuite* UnitTest::current_test_suite() const
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_suite();
+}
+
+// Legacy API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+const TestCase* UnitTest::current_test_case() const
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_suite();
+}
+#endif
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+const TestInfo* UnitTest::current_test_info() const
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ 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(); }
+
+// Returns ParameterizedTestSuiteRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+internal::ParameterizedTestSuiteRegistry&
+UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) {
+ return impl_->parameterized_test_registry();
+}
+
+// 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.
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace)
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().push_back(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().pop_back();
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+ : parent_(parent),
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */)
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+ GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_(
+ &default_global_test_part_result_reporter_),
+ per_thread_test_part_result_reporter_(
+ &default_per_thread_test_part_result_reporter_),
+ parameterized_test_registry_(),
+ parameterized_tests_registered_(false),
+ last_death_test_suite_(-1),
+ current_test_suite_(nullptr),
+ current_test_info_(nullptr),
+ ad_hoc_test_result_(),
+ os_stack_trace_getter_(nullptr),
+ 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.
+ start_timestamp_(0),
+ elapsed_time_(0),
+#if GTEST_HAS_DEATH_TEST
+ 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 TestSuite.
+ ForEach(test_suites_, internal::Delete<TestSuite>);
+
+ // Deletes every Environment.
+ ForEach(environments_, internal::Delete<Environment>);
+
+ delete os_stack_trace_getter_;
+}
+
+// Adds a TestProperty to the current TestResult object when invoked in a
+// context of a test, to current test suite's ad_hoc_test_result when invoke
+// from SetUpTestSuite/TearDownTestSuite, or to the global property set
+// otherwise. If the result already contains a property with the same key,
+// the value will be updated.
+void UnitTestImpl::RecordProperty(const TestProperty& test_property) {
+ std::string xml_element;
+ TestResult* test_result; // TestResult appropriate for property recording.
+
+ if (current_test_info_ != nullptr) {
+ xml_element = "testcase";
+ test_result = &(current_test_info_->result_);
+ } else if (current_test_suite_ != nullptr) {
+ xml_element = "testsuite";
+ test_result = &(current_test_suite_->ad_hoc_test_result_);
+ } else {
+ xml_element = "testsuites";
+ test_result = &ad_hoc_test_result_;
+ }
+ test_result->RecordProperty(xml_element, test_property);
+}
+
+#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() != nullptr)
+ 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 std::string& output_format = UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml") {
+ listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+ } else if (output_format == "json") {
+ listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+ } else if (output_format != "") {
+ GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \""
+ << output_format << "\" ignored.";
+ }
+}
+
+#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 std::string& target = GTEST_FLAG_GET(stream_result_to);
+ if (!target.empty()) {
+ const size_t pos = target.find(':');
+ if (pos != std::string::npos) {
+ listeners()->Append(
+ new StreamingListener(target.substr(0, pos), target.substr(pos + 1)));
+ } else {
+ GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target
+ << "\" ignored.";
+ }
+ }
+}
+#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 defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_)
+ // Register to send notifications about key process state changes.
+ listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_());
+#endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_)
+
+#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_FLAG_GET(brief)) {
+ listeners()->SetDefaultResultPrinter(new BriefUnitTestResultPrinter);
+ }
+
+#if GTEST_CAN_STREAM_RESULTS_
+ // Configures listeners for streaming test results to the specified server.
+ ConfigureStreamingOutput();
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+#if GTEST_HAS_ABSL
+ if (GTEST_FLAG_GET(install_failure_signal_handler)) {
+ absl::FailureSignalHandlerOptions options;
+ absl::InstallFailureSignalHandler(options);
+ }
+#endif // GTEST_HAS_ABSL
+ }
+}
+
+// A predicate that checks the name of a TestSuite 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.
+//
+// TestSuiteNameIs is copyable.
+class TestSuiteNameIs {
+ public:
+ // Constructor.
+ explicit TestSuiteNameIs(const std::string& name) : name_(name) {}
+
+ // Returns true if and only if the name of test_suite matches name_.
+ bool operator()(const TestSuite* test_suite) const {
+ return test_suite != nullptr &&
+ strcmp(test_suite->name(), name_.c_str()) == 0;
+ }
+
+ private:
+ std::string name_;
+};
+
+// Finds and returns a TestSuite 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_suite_name: name of the test suite
+// type_param: the name of the test suite's type parameter, or NULL if
+// this is not a typed or a type-parameterized test suite.
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+TestSuite* UnitTestImpl::GetTestSuite(
+ const char* test_suite_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc) {
+ // Can we find a TestSuite with the given name?
+ const auto test_suite =
+ std::find_if(test_suites_.rbegin(), test_suites_.rend(),
+ TestSuiteNameIs(test_suite_name));
+
+ if (test_suite != test_suites_.rend()) return *test_suite;
+
+ // No. Let's create one.
+ auto* const new_test_suite =
+ new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc);
+
+ const UnitTestFilter death_test_suite_filter(kDeathTestSuiteFilter);
+ // Is this a death test suite?
+ if (death_test_suite_filter.MatchesName(test_suite_name)) {
+ // Yes. Inserts the test suite after the last death test suite
+ // defined so far. This only works when the test suites haven't
+ // been shuffled. Otherwise we may end up running a death test
+ // after a non-death test.
+ ++last_death_test_suite_;
+ test_suites_.insert(test_suites_.begin() + last_death_test_suite_,
+ new_test_suite);
+ } else {
+ // No. Appends to the end of the list.
+ test_suites_.push_back(new_test_suite);
+ }
+
+ test_suite_indices_.push_back(static_cast<int>(test_suite_indices_.size()));
+ return new_test_suite;
+}
+
+// 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() {
+ // True if and only if Google Test is initialized before RUN_ALL_TESTS() is
+ // called.
+ const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized();
+
+ // 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 if and only if 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() != nullptr);
+#if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
+ if (in_subprocess_for_death_test) {
+ GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_();
+ }
+#endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
+#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_GET(list_tests)) {
+ // This must be called *after* FilterTests() has been called.
+ ListTestsMatchingFilter();
+ return true;
+ }
+
+ random_seed_ = GetRandomSeedFromFlag(GTEST_FLAG_GET(random_seed));
+
+ // True if and only if at least one test has failed.
+ bool failed = false;
+
+ TestEventListener* repeater = listeners()->repeater();
+
+ start_timestamp_ = GetTimeInMillis();
+ 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_GET(repeat);
+
+ // Repeats forever if the repeat count is negative.
+ const bool gtest_repeat_forever = repeat < 0;
+
+ // Should test environments be set up and torn down for each repeat, or only
+ // set up on the first and torn down on the last iteration? If there is no
+ // "last" iteration because the tests will repeat forever, always recreate the
+ // environments to avoid leaks in case one of the environments is using
+ // resources that are external to this process. Without this check there would
+ // be no way to clean up those external resources automatically.
+ const bool recreate_environments_when_repeating =
+ GTEST_FLAG_GET(recreate_environments_when_repeating) ||
+ gtest_repeat_forever;
+
+ for (int i = 0; gtest_repeat_forever || i != repeat; i++) {
+ // We want to preserve failures generated by ad-hoc test
+ // assertions executed before RUN_ALL_TESTS().
+ ClearNonAdHocTestResult();
+
+ Timer timer;
+
+ // Shuffles test suites and tests if requested.
+ if (has_tests_to_run && GTEST_FLAG_GET(shuffle)) {
+ random()->Reseed(static_cast<uint32_t>(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 suite if there is at least one test to run.
+ if (has_tests_to_run) {
+ // Sets up all environments beforehand. If test environments aren't
+ // recreated for each iteration, only do so on the first iteration.
+ if (i == 0 || recreate_environments_when_repeating) {
+ repeater->OnEnvironmentsSetUpStart(*parent_);
+ ForEach(environments_, SetUpEnvironment);
+ repeater->OnEnvironmentsSetUpEnd(*parent_);
+ }
+
+ // Runs the tests only if there was no fatal failure or skip triggered
+ // during global set-up.
+ if (Test::IsSkipped()) {
+ // Emit diagnostics when global set-up calls skip, as it will not be
+ // emitted by default.
+ TestResult& test_result =
+ *internal::GetUnitTestImpl()->current_test_result();
+ for (int j = 0; j < test_result.total_part_count(); ++j) {
+ const TestPartResult& test_part_result =
+ test_result.GetTestPartResult(j);
+ if (test_part_result.type() == TestPartResult::kSkip) {
+ const std::string& result = test_part_result.message();
+ printf("%s\n", result.c_str());
+ }
+ }
+ fflush(stdout);
+ } else if (!Test::HasFatalFailure()) {
+ for (int test_index = 0; test_index < total_test_suite_count();
+ test_index++) {
+ GetMutableSuiteCase(test_index)->Run();
+ if (GTEST_FLAG_GET(fail_fast) &&
+ GetMutableSuiteCase(test_index)->Failed()) {
+ for (int j = test_index + 1; j < total_test_suite_count(); j++) {
+ GetMutableSuiteCase(j)->Skip();
+ }
+ break;
+ }
+ }
+ } else if (Test::HasFatalFailure()) {
+ // If there was a fatal failure during the global setup then we know we
+ // aren't going to run any tests. Explicitly mark all of the tests as
+ // skipped to make this obvious in the output.
+ for (int test_index = 0; test_index < total_test_suite_count();
+ test_index++) {
+ GetMutableSuiteCase(test_index)->Skip();
+ }
+ }
+
+ // Tears down all environments in reverse order afterwards. If test
+ // environments aren't recreated for each iteration, only do so on the
+ // last iteration.
+ if (i == repeat - 1 || recreate_environments_when_repeating) {
+ repeater->OnEnvironmentsTearDownStart(*parent_);
+ std::for_each(environments_.rbegin(), environments_.rend(),
+ TearDownEnvironment);
+ repeater->OnEnvironmentsTearDownEnd(*parent_);
+ }
+ }
+
+ elapsed_time_ = timer.Elapsed();
+
+ // 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_GET(shuffle)) {
+ // Picks a new random seed for each iteration.
+ random_seed_ = GetNextRandomSeed(random_seed_);
+ }
+ }
+
+ repeater->OnTestProgramEnd(*parent_);
+
+ if (!gtest_is_initialized_before_run_all_tests) {
+ ColoredPrintf(
+ GTestColor::kRed,
+ "\nIMPORTANT NOTICE - DO NOT IGNORE:\n"
+ "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_
+ "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_
+ " will start to enforce the valid usage. "
+ "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT
+#if GTEST_FOR_GOOGLE_
+ ColoredPrintf(GTestColor::kRed,
+ "For more details, see http://wiki/Main/ValidGUnitMain.\n");
+#endif // GTEST_FOR_GOOGLE_
+ }
+
+ 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 != nullptr) {
+ FILE* const file = posix::FOpen(test_shard_file, "w");
+ if (file == nullptr) {
+ ColoredPrintf(GTestColor::kRed,
+ "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_t total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+ const int32_t 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(GTestColor::kRed, "%s", 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(GTestColor::kRed, "%s", 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(GTestColor::kRed, "%s", 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_t Int32FromEnvOrDie(const char* var, int32_t default_val) {
+ const char* str_val = posix::GetEnv(var);
+ if (str_val == nullptr) {
+ return default_val;
+ }
+
+ int32_t 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 if and only if 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 TestSuite and TestInfo object.
+// If shard_tests == true, further filters tests based on sharding
+// variables in the environment - see
+// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md
+// . Returns the number of tests that should run.
+int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
+ const int32_t total_shards = shard_tests == HONOR_SHARDING_PROTOCOL
+ ? Int32FromEnvOrDie(kTestTotalShards, -1)
+ : -1;
+ const int32_t shard_index = shard_tests == HONOR_SHARDING_PROTOCOL
+ ? Int32FromEnvOrDie(kTestShardIndex, -1)
+ : -1;
+
+ const PositiveAndNegativeUnitTestFilter gtest_flag_filter(
+ GTEST_FLAG_GET(filter));
+ const UnitTestFilter disable_test_filter(kDisableTestFilter);
+ // 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 (auto* test_suite : test_suites_) {
+ const std::string& test_suite_name = test_suite->name();
+ test_suite->set_should_run(false);
+
+ for (size_t j = 0; j < test_suite->test_info_list().size(); j++) {
+ TestInfo* const test_info = test_suite->test_info_list()[j];
+ const std::string test_name(test_info->name());
+ // A test is disabled if test suite name or test name matches
+ // kDisableTestFilter.
+ const bool is_disabled =
+ disable_test_filter.MatchesName(test_suite_name) ||
+ disable_test_filter.MatchesName(test_name);
+ test_info->is_disabled_ = is_disabled;
+
+ const bool matches_filter =
+ gtest_flag_filter.MatchesTest(test_suite_name, test_name);
+ test_info->matches_filter_ = matches_filter;
+
+ const bool is_runnable =
+ (GTEST_FLAG_GET(also_run_disabled_tests) || !is_disabled) &&
+ matches_filter;
+
+ const bool is_in_another_shard =
+ shard_tests != IGNORE_SHARDING_PROTOCOL &&
+ !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests);
+ test_info->is_in_another_shard_ = is_in_another_shard;
+ const bool is_selected = is_runnable && !is_in_another_shard;
+
+ num_runnable_tests += is_runnable;
+ num_selected_tests += is_selected;
+
+ test_info->should_run_ = is_selected;
+ test_suite->set_should_run(test_suite->should_run() || is_selected);
+ }
+ }
+ return num_selected_tests;
+}
+
+// Prints the given C-string on a single line by replacing all '\n'
+// characters with string "\\n". If the output takes more than
+// max_length characters, only prints the first max_length characters
+// and "...".
+static void PrintOnOneLine(const char* str, int max_length) {
+ if (str != nullptr) {
+ for (int i = 0; *str != '\0'; ++str) {
+ if (i >= max_length) {
+ printf("...");
+ break;
+ }
+ if (*str == '\n') {
+ printf("\\n");
+ i += 2;
+ } else {
+ printf("%c", *str);
+ ++i;
+ }
+ }
+ }
+}
+
+// Prints the names of the tests matching the user-specified filter flag.
+void UnitTestImpl::ListTestsMatchingFilter() {
+ // Print at most this many characters for each type/value parameter.
+ const int kMaxParamLength = 250;
+
+ for (auto* test_suite : test_suites_) {
+ bool printed_test_suite_name = false;
+
+ for (size_t j = 0; j < test_suite->test_info_list().size(); j++) {
+ const TestInfo* const test_info = test_suite->test_info_list()[j];
+ if (test_info->matches_filter_) {
+ if (!printed_test_suite_name) {
+ printed_test_suite_name = true;
+ printf("%s.", test_suite->name());
+ if (test_suite->type_param() != nullptr) {
+ printf(" # %s = ", kTypeParamLabel);
+ // We print the type parameter on a single line to make
+ // the output easy to parse by a program.
+ PrintOnOneLine(test_suite->type_param(), kMaxParamLength);
+ }
+ printf("\n");
+ }
+ printf(" %s", test_info->name());
+ if (test_info->value_param() != nullptr) {
+ printf(" # %s = ", kValueParamLabel);
+ // We print the value parameter on a single line to make the
+ // output easy to parse by a program.
+ PrintOnOneLine(test_info->value_param(), kMaxParamLength);
+ }
+ printf("\n");
+ }
+ }
+ }
+ fflush(stdout);
+ const std::string& output_format = UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml" || output_format == "json") {
+ FILE* fileout = OpenFileForWriting(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+ std::stringstream stream;
+ if (output_format == "xml") {
+ XmlUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str())
+ .PrintXmlTestsList(&stream, test_suites_);
+ } else if (output_format == "json") {
+ JsonUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str())
+ .PrintJsonTestList(&stream, test_suites_);
+ }
+ fprintf(fileout, "%s", StringStreamToString(&stream).c_str());
+ fclose(fileout);
+ }
+}
+
+// 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_ == nullptr) {
+#ifdef GTEST_OS_STACK_TRACE_GETTER_
+ os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_;
+#else
+ os_stack_trace_getter_ = new OsStackTraceGetter;
+#endif // GTEST_OS_STACK_TRACE_GETTER_
+ }
+
+ return os_stack_trace_getter_;
+}
+
+// Returns the most specific TestResult currently running.
+TestResult* UnitTestImpl::current_test_result() {
+ if (current_test_info_ != nullptr) {
+ return &current_test_info_->result_;
+ }
+ if (current_test_suite_ != nullptr) {
+ return &current_test_suite_->ad_hoc_test_result_;
+ }
+ return &ad_hoc_test_result_;
+}
+
+// Shuffles all test suites, and the tests within each test suite,
+// making sure that death tests are still run first.
+void UnitTestImpl::ShuffleTests() {
+ // Shuffles the death test suites.
+ ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_);
+
+ // Shuffles the non-death test suites.
+ ShuffleRange(random(), last_death_test_suite_ + 1,
+ static_cast<int>(test_suites_.size()), &test_suite_indices_);
+
+ // Shuffles the tests inside each test suite.
+ for (auto& test_suite : test_suites_) {
+ test_suite->ShuffleTests(random());
+ }
+}
+
+// Restores the test suites and tests to their order before the first shuffle.
+void UnitTestImpl::UnshuffleTests() {
+ for (size_t i = 0; i < test_suites_.size(); i++) {
+ // Unshuffles the tests in each test suite.
+ test_suites_[i]->UnshuffleTests();
+ // Resets the index of each test suite.
+ test_suite_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// Returns the current OS stack trace as an std::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_NO_INLINE_ GTEST_NO_TAIL_CALL_ std::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 {};
+} // namespace
+
+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.
+static const char* ParseFlagValue(const char* str, const char* flag_name,
+ bool def_optional) {
+ // str and flag must not be NULL.
+ if (str == nullptr || flag_name == nullptr) return nullptr;
+
+ // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
+ const std::string flag_str =
+ std::string("--") + GTEST_FLAG_PREFIX_ + flag_name;
+ const size_t flag_len = flag_str.length();
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr;
+
+ // 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 nullptr;
+
+ // 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.
+static bool ParseFlag(const char* str, const char* flag_name, bool* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag_name, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == nullptr) 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_t 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 ParseFlag(const char* str, const char* flag_name, int32_t* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag_name, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == nullptr) return false;
+
+ // Sets *value to the value of the flag.
+ return ParseInt32(Message() << "The value of flag --" << flag_name, 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.
+template <typename String>
+static bool ParseFlag(const char* str, const char* flag_name, String* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag_name, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == nullptr) 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.
+//
+static void PrintColorEncoded(const char* str) {
+ GTestColor color = GTestColor::kDefault; // 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 == nullptr) {
+ ColoredPrintf(color, "%s", str);
+ return;
+ }
+
+ ColoredPrintf(color, "%s", std::string(str, p).c_str());
+
+ const char ch = p[1];
+ str = p + 2;
+ if (ch == '@') {
+ ColoredPrintf(color, "@");
+ } else if (ch == 'D') {
+ color = GTestColor::kDefault;
+ } else if (ch == 'R') {
+ color = GTestColor::kRed;
+ } else if (ch == 'G') {
+ color = GTestColor::kGreen;
+ } else if (ch == 'Y') {
+ color = GTestColor::kYellow;
+ } 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=@YPOSITIVE_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"
+ " @G--" GTEST_FLAG_PREFIX_
+ "recreate_environments_when_repeating@D\n"
+ " Sets up and tears down the global test environment on each repeat\n"
+ " of the test.\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_
+ "brief=1@D\n"
+ " Only print test failures.\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=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_
+ "@Y|@G:@YFILE_PATH]@D\n"
+ " Generate a JSON or XML report in the given directory or with the "
+ "given\n"
+ " file name. @YFILE_PATH@D defaults to @Gtest_detail.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 for use by an external\n"
+ " test framework.\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";
+
+static bool ParseGoogleTestFlag(const char* const arg) {
+#define GTEST_INTERNAL_PARSE_FLAG(flag_name) \
+ do { \
+ auto value = GTEST_FLAG_GET(flag_name); \
+ if (ParseFlag(arg, #flag_name, &value)) { \
+ GTEST_FLAG_SET(flag_name, value); \
+ return true; \
+ } \
+ } while (false)
+
+ GTEST_INTERNAL_PARSE_FLAG(also_run_disabled_tests);
+ GTEST_INTERNAL_PARSE_FLAG(break_on_failure);
+ GTEST_INTERNAL_PARSE_FLAG(catch_exceptions);
+ GTEST_INTERNAL_PARSE_FLAG(color);
+ GTEST_INTERNAL_PARSE_FLAG(death_test_style);
+ GTEST_INTERNAL_PARSE_FLAG(death_test_use_fork);
+ GTEST_INTERNAL_PARSE_FLAG(fail_fast);
+ GTEST_INTERNAL_PARSE_FLAG(filter);
+ GTEST_INTERNAL_PARSE_FLAG(internal_run_death_test);
+ GTEST_INTERNAL_PARSE_FLAG(list_tests);
+ GTEST_INTERNAL_PARSE_FLAG(output);
+ GTEST_INTERNAL_PARSE_FLAG(brief);
+ GTEST_INTERNAL_PARSE_FLAG(print_time);
+ GTEST_INTERNAL_PARSE_FLAG(print_utf8);
+ GTEST_INTERNAL_PARSE_FLAG(random_seed);
+ GTEST_INTERNAL_PARSE_FLAG(repeat);
+ GTEST_INTERNAL_PARSE_FLAG(recreate_environments_when_repeating);
+ GTEST_INTERNAL_PARSE_FLAG(shuffle);
+ GTEST_INTERNAL_PARSE_FLAG(stack_trace_depth);
+ GTEST_INTERNAL_PARSE_FLAG(stream_result_to);
+ GTEST_INTERNAL_PARSE_FLAG(throw_on_failure);
+ return false;
+}
+
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+static void LoadFlagsFromFile(const std::string& path) {
+ FILE* flagfile = posix::FOpen(path.c_str(), "r");
+ if (!flagfile) {
+ GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG_GET(flagfile)
+ << "\"";
+ }
+ std::string contents(ReadEntireFile(flagfile));
+ posix::FClose(flagfile);
+ std::vector<std::string> lines;
+ SplitString(contents, '\n', &lines);
+ for (size_t i = 0; i < lines.size(); ++i) {
+ if (lines[i].empty()) continue;
+ if (!ParseGoogleTestFlag(lines[i].c_str())) g_help_flag = true;
+ }
+}
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
+// 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 <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
+ std::string flagfile_value;
+ for (int i = 1; i < *argc; i++) {
+ const std::string arg_string = StreamableToString(argv[i]);
+ const char* const arg = arg_string.c_str();
+
+ using internal::ParseFlag;
+
+ bool remove_flag = false;
+ if (ParseGoogleTestFlag(arg)) {
+ remove_flag = true;
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+ } else if (ParseFlag(arg, "flagfile", &flagfile_value)) {
+ GTEST_FLAG_SET(flagfile, flagfile_value);
+ LoadFlagsFromFile(flagfile_value);
+ remove_flag = true;
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+ } else if (arg_string == "--help" || HasGoogleTestFlagPrefix(arg)) {
+ // Both help flag and unrecognized Google Test flags (excluding
+ // internal ones) trigger help display.
+ g_help_flag = true;
+ }
+
+ if (remove_flag) {
+ // 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--;
+ }
+ }
+
+ 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) {
+#if GTEST_HAS_ABSL
+ if (*argc > 0) {
+ // absl::ParseCommandLine() requires *argc > 0.
+ auto positional_args = absl::flags_internal::ParseCommandLineImpl(
+ *argc, argv, absl::flags_internal::ArgvListAction::kRemoveParsedArgs,
+ absl::flags_internal::UsageFlagsAction::kHandleUsage,
+ absl::flags_internal::OnUndefinedFlag::kReportUndefined);
+ // Any command-line positional arguments not part of any command-line flag
+ // (or arguments to a flag) are copied back out to argv, with the program
+ // invocation name at position 0, and argc is resized. This includes
+ // positional arguments after the flag-terminating delimiter '--'.
+ // See https://abseil.io/docs/cpp/guides/flags.
+ std::copy(positional_args.begin(), positional_args.end(), argv);
+ if (static_cast<int>(positional_args.size()) < *argc) {
+ argv[positional_args.size()] = nullptr;
+ *argc = static_cast<int>(positional_args.size());
+ }
+ }
+#else
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+#endif
+
+ // Fix the value of *_NSGetArgc() on macOS, but if and only if
+ // *_NSGetArgv() == argv
+ // Only applicable to char** version of argv
+#if GTEST_OS_MAC
+#ifndef GTEST_OS_IOS
+ if (*_NSGetArgv() == argv) {
+ *_NSGetArgc() = *argc;
+ }
+#endif
+#endif
+}
+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 <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv) {
+ // We don't want to run the initialization code twice.
+ if (GTestIsInitialized()) return;
+
+ if (*argc <= 0) return;
+
+ g_argvs.clear();
+ for (int i = 0; i != *argc; i++) {
+ g_argvs.push_back(StreamableToString(argv[i]));
+ }
+
+#if GTEST_HAS_ABSL
+ absl::InitializeSymbolizer(g_argvs[0].c_str());
+
+ // When using the Abseil Flags library, set the program usage message to the
+ // help message, but remove the color-encoding from the message first.
+ absl::SetProgramUsageMessage(absl::StrReplaceAll(
+ kColorEncodedHelpMessage,
+ {{"@D", ""}, {"@R", ""}, {"@G", ""}, {"@Y", ""}, {"@@", "@"}}));
+#endif // GTEST_HAS_ABSL
+
+ 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) {
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ internal::InitGoogleTestImpl(argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv) {
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ internal::InitGoogleTestImpl(argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+}
+
+// This overloaded version can be used on Arduino/embedded platforms where
+// there is no argc/argv.
+void InitGoogleTest() {
+ // Since Arduino doesn't have a command line, fake out the argc/argv arguments
+ int argc = 1;
+ const auto arg0 = "dummy";
+ char* argv0 = const_cast<char*>(arg0);
+ char** argv = &argv0;
+
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ internal::InitGoogleTestImpl(&argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+}
+
+#if !defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_)
+// Return value of first environment variable that is set and contains
+// a non-empty string. If there are none, return the "fallback" string.
+// Since we like the temporary directory to have a directory separator suffix,
+// add it if not provided in the environment variable value.
+static std::string GetTempDirFromEnv(
+ std::initializer_list<const char*> environment_variables,
+ const char* fallback, char separator) {
+ for (const char* variable_name : environment_variables) {
+ const char* value = internal::posix::GetEnv(variable_name);
+ if (value != nullptr && value[0] != '\0') {
+ if (value[strlen(value) - 1] != separator) {
+ return std::string(value).append(1, separator);
+ }
+ return value;
+ }
+ }
+ return fallback;
+}
+#endif
+
+std::string TempDir() {
+#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_)
+ return GTEST_CUSTOM_TEMPDIR_FUNCTION_();
+#elif GTEST_OS_WINDOWS || GTEST_OS_WINDOWS_MOBILE
+ return GetTempDirFromEnv({"TEST_TMPDIR", "TEMP"}, "\\temp\\", '\\');
+#elif GTEST_OS_LINUX_ANDROID
+ return GetTempDirFromEnv({"TEST_TMPDIR", "TMPDIR"}, "/data/local/tmp/", '/');
+#else
+ return GetTempDirFromEnv({"TEST_TMPDIR", "TMPDIR"}, "/tmp/", '/');
+#endif
+}
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+void ScopedTrace::PushTrace(const char* file, int line, std::string message) {
+ internal::TraceInfo trace;
+ trace.file = file;
+ trace.line = line;
+ trace.message.swap(message);
+
+ UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+ScopedTrace::~ScopedTrace() GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
+ UnitTest::GetInstance()->PopGTestTrace();
+}
+
+} // namespace testing
diff --git a/libs/cpp-httplib/test/gtest/src/gtest_main.cc b/libs/cpp-httplib/test/gtest/src/gtest_main.cc
new file mode 100644
index 0000000..4497637
--- /dev/null
+++ b/libs/cpp-httplib/test/gtest/src/gtest_main.cc
@@ -0,0 +1,53 @@
+// 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 <cstdio>
+
+#include "gtest/gtest.h"
+
+#if GTEST_OS_ESP8266 || GTEST_OS_ESP32
+#if GTEST_OS_ESP8266
+extern "C" {
+#endif
+void setup() { testing::InitGoogleTest(); }
+
+void loop() { RUN_ALL_TESTS(); }
+
+#if GTEST_OS_ESP8266
+}
+#endif
+
+#else
+
+GTEST_API_ int main(int argc, char **argv) {
+ printf("Running main() from %s\n", __FILE__);
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/libs/cpp-httplib/test/image.jpg b/libs/cpp-httplib/test/image.jpg
new file mode 100644
index 0000000..f74b495
--- /dev/null
+++ b/libs/cpp-httplib/test/image.jpg
Binary files differ
diff --git a/libs/cpp-httplib/test/include_httplib.cc b/libs/cpp-httplib/test/include_httplib.cc
new file mode 100644
index 0000000..fd38cb8
--- /dev/null
+++ b/libs/cpp-httplib/test/include_httplib.cc
@@ -0,0 +1,5 @@
+// The sole purpose of this file is to include httplib.h in a separate
+// compilation unit, thus verifying that inline keywords have not been forgotten
+// when linked together with test.cc.
+
+#include <httplib.h>
diff --git a/libs/cpp-httplib/test/include_windows_h.cc b/libs/cpp-httplib/test/include_windows_h.cc
new file mode 100644
index 0000000..44f541f
--- /dev/null
+++ b/libs/cpp-httplib/test/include_windows_h.cc
@@ -0,0 +1,6 @@
+// Test if including windows.h conflicts with httplib.h
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <httplib.h>
diff --git a/libs/cpp-httplib/test/make-shared-library.sh b/libs/cpp-httplib/test/make-shared-library.sh
new file mode 100644
index 0000000..04f2fc0
--- /dev/null
+++ b/libs/cpp-httplib/test/make-shared-library.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+if [ "$#" -ne 1 ]; then
+ echo "Usage: $0 build_dir"
+ exit 1
+fi
+
+BUILD_DIR=$1
+
+# Make the build directory
+rm -rf $BUILD_DIR
+mkdir -p $BUILD_DIR/out
+
+cd $BUILD_DIR
+
+# Build the version
+git checkout $BUILD_DIR -q
+
+cmake \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DCMAKE_CXX_FLAGS="-g -Og" \
+ -DBUILD_SHARED_LIBS=ON \
+ -DHTTPLIB_COMPILE=ON \
+ -DCMAKE_INSTALL_PREFIX=./out \
+ ../..
+
+cmake --build . --target install
+cmake --build . --target clean
+
diff --git a/libs/cpp-httplib/test/meson.build b/libs/cpp-httplib/test/meson.build
new file mode 100644
index 0000000..745236b
--- /dev/null
+++ b/libs/cpp-httplib/test/meson.build
@@ -0,0 +1,146 @@
+# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+gtest_dep = dependency('gtest', main: true)
+libcurl_dep = dependency('libcurl')
+openssl = find_program('openssl')
+test_conf = files('test.conf')
+req_x509_flag = openssl.version().version_compare('>=3.2.0') ? '-x509v1' : '-x509'
+
+key_pem = custom_target(
+ 'key_pem',
+ output: 'key.pem',
+ command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
+)
+
+temp_req = custom_target(
+ 'temp_req',
+ input: key_pem,
+ output: 'temp_req',
+ command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-out', '@OUTPUT@']
+)
+
+cert_pem = custom_target(
+ 'cert_pem',
+ input: [temp_req, key_pem],
+ output: 'cert.pem',
+ command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '3650', '-req', '-signkey', '@INPUT1@', '-out', '@OUTPUT@']
+)
+
+cert2_pem = custom_target(
+ 'cert2_pem',
+ input: key_pem,
+ output: 'cert2.pem',
+ command: [openssl, 'req', req_x509_flag, '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
+)
+
+key_encrypted_pem = custom_target(
+ 'key_encrypted_pem',
+ output: 'key_encrypted.pem',
+ command: [openssl, 'genrsa', '-passout', 'pass:test123!', '-out', '@OUTPUT@', '2048']
+)
+
+cert_encrypted_pem = custom_target(
+ 'cert_encrypted_pem',
+ input: key_encrypted_pem,
+ output: 'cert_encrypted.pem',
+ command: [openssl, 'req', req_x509_flag, '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
+)
+
+rootca_key_pem = custom_target(
+ 'rootca_key_pem',
+ output: 'rootCA.key.pem',
+ command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
+)
+
+rootca_cert_pem = custom_target(
+ 'rootca_cert_pem',
+ input: rootca_key_pem,
+ output: 'rootCA.cert.pem',
+ command: [openssl, 'req', req_x509_flag, '-new', '-batch', '-config', files('test.rootCA.conf'), '-key', '@INPUT@', '-days', '1024', '-out', '@OUTPUT@']
+)
+
+client_key_pem = custom_target(
+ 'client_key_pem',
+ output: 'client.key.pem',
+ command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
+)
+
+client_temp_req = custom_target(
+ 'client_temp_req',
+ input: client_key_pem,
+ output: 'client_temp_req',
+ command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-out', '@OUTPUT@']
+)
+
+client_cert_pem = custom_target(
+ 'client_cert_pem',
+ input: [client_temp_req, rootca_cert_pem, rootca_key_pem],
+ output: 'client.cert.pem',
+ command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '370', '-req', '-CA', '@INPUT1@', '-CAkey', '@INPUT2@', '-CAcreateserial', '-out', '@OUTPUT@']
+)
+
+client_encrypted_key_pem = custom_target(
+ 'client_encrypted_key_pem',
+ output: 'client_encrypted.key.pem',
+ command: [openssl, 'genrsa', '-aes256', '-passout', 'pass:test012!', '-out', '@OUTPUT@', '2048']
+)
+
+client_encrypted_temp_req = custom_target(
+ 'client_encrypted_temp_req',
+ input: client_encrypted_key_pem,
+ output: 'client_encrypted_temp_req',
+ command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-passin', 'pass:test012!', '-out', '@OUTPUT@']
+)
+
+client_encrypted_cert_pem = custom_target(
+ 'client_encrypted_cert_pem',
+ input: [client_encrypted_temp_req, rootca_cert_pem, rootca_key_pem],
+ output: 'client_encrypted.cert.pem',
+ command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '370', '-req', '-CA', '@INPUT1@', '-CAkey', '@INPUT2@', '-CAcreateserial', '-out', '@OUTPUT@']
+)
+
+# Copy test files to the build directory
+configure_file(input: 'ca-bundle.crt', output: 'ca-bundle.crt', copy: true)
+configure_file(input: 'image.jpg', output: 'image.jpg', copy: true)
+subdir('www')
+subdir('www2'/'dir')
+subdir('www3'/'dir')
+
+# New GoogleTest versions require new C++ standards
+test_options = []
+if gtest_dep.version().version_compare('>=1.17.0')
+ test_options += 'cpp_std=c++17'
+elif gtest_dep.version().version_compare('>=1.13.0')
+ test_options += 'cpp_std=c++14'
+endif
+
+test(
+ 'main',
+ executable(
+ 'main',
+ 'test.cc',
+ dependencies: [
+ cpp_httplib_dep,
+ gtest_dep,
+ libcurl_dep
+ ],
+ override_options: test_options
+ ),
+ depends: [
+ key_pem,
+ cert_pem,
+ cert2_pem,
+ key_encrypted_pem,
+ cert_encrypted_pem,
+ rootca_key_pem,
+ rootca_cert_pem,
+ client_key_pem,
+ client_cert_pem,
+ client_encrypted_key_pem,
+ client_encrypted_cert_pem
+ ],
+ workdir: meson.current_build_dir(),
+ timeout: 300
+)
diff --git a/libs/cpp-httplib/test/proxy/Dockerfile b/libs/cpp-httplib/test/proxy/Dockerfile
new file mode 100644
index 0000000..2f39159
--- /dev/null
+++ b/libs/cpp-httplib/test/proxy/Dockerfile
@@ -0,0 +1,13 @@
+FROM alpine:latest
+
+ARG auth="basic"
+ARG port="3128"
+
+RUN apk update && apk add --no-cache squid
+
+COPY ./${auth}_squid.conf /etc/squid/squid.conf
+COPY ./${auth}_passwd /etc/squid/passwd
+
+EXPOSE ${port}
+
+CMD ["/usr/sbin/squid", "-N"]
diff --git a/libs/cpp-httplib/test/proxy/basic_passwd b/libs/cpp-httplib/test/proxy/basic_passwd
new file mode 100644
index 0000000..bb1b709
--- /dev/null
+++ b/libs/cpp-httplib/test/proxy/basic_passwd
@@ -0,0 +1 @@
+hello:$apr1$O6S28OBL$8dr3ixl4Mohf97hgsYvLy/
diff --git a/libs/cpp-httplib/test/proxy/basic_squid.conf b/libs/cpp-httplib/test/proxy/basic_squid.conf
new file mode 100644
index 0000000..e9d1aeb
--- /dev/null
+++ b/libs/cpp-httplib/test/proxy/basic_squid.conf
@@ -0,0 +1,81 @@
+#
+# Recommended minimum configuration:
+#
+
+# Example rule allowing access from your local networks.
+# Adapt to list your (internal) IP networks from where browsing
+# should be allowed
+acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
+acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
+acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
+acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
+acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
+acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
+acl localnet src fc00::/7 # RFC 4193 local private network range
+acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
+
+acl SSL_ports port 443
+acl Safe_ports port 80 # http
+acl Safe_ports port 21 # ftp
+acl Safe_ports port 443 # https
+acl Safe_ports port 70 # gopher
+acl Safe_ports port 210 # wais
+acl Safe_ports port 1025-65535 # unregistered ports
+acl Safe_ports port 280 # http-mgmt
+acl Safe_ports port 488 # gss-http
+acl Safe_ports port 591 # filemaker
+acl Safe_ports port 777 # multiling http
+acl CONNECT method CONNECT
+
+auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwd
+auth_param basic realm proxy
+acl authenticated proxy_auth REQUIRED
+http_access allow authenticated
+
+#
+# Recommended minimum Access Permission configuration:
+#
+# Deny requests to certain unsafe ports
+http_access deny !Safe_ports
+
+# Deny CONNECT to other than secure SSL ports
+http_access deny CONNECT !SSL_ports
+
+# Only allow cachemgr access from localhost
+http_access allow localhost manager
+http_access deny manager
+
+# We strongly recommend the following be uncommented to protect innocent
+# web applications running on the proxy server who think the only
+# one who can access services on "localhost" is a local user
+#http_access deny to_localhost
+
+#
+# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
+#
+
+# Example rule allowing access from your local networks.
+# Adapt localnet in the ACL section to list your (internal) IP networks
+# from where browsing should be allowed
+http_access allow localnet
+http_access allow localhost
+
+# And finally deny all other access to this proxy
+http_access deny all
+
+# Squid normally listens to port 3128
+http_port 3128
+
+# Uncomment and adjust the following to add a disk cache directory.
+#cache_dir ufs /var/spool/squid 100 16 256
+
+# Leave coredumps in the first cache dir
+coredump_dir /var/spool/squid
+
+#
+# Add any of your own refresh_pattern entries above these.
+#
+refresh_pattern ^ftp: 1440 20% 10080
+refresh_pattern ^gopher: 1440 0% 1440
+refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
+refresh_pattern . 0 20% 4320
diff --git a/libs/cpp-httplib/test/proxy/digest_passwd b/libs/cpp-httplib/test/proxy/digest_passwd
new file mode 100644
index 0000000..d45615f
--- /dev/null
+++ b/libs/cpp-httplib/test/proxy/digest_passwd
@@ -0,0 +1 @@
+hello:world
diff --git a/libs/cpp-httplib/test/proxy/digest_squid.conf b/libs/cpp-httplib/test/proxy/digest_squid.conf
new file mode 100644
index 0000000..f38135f
--- /dev/null
+++ b/libs/cpp-httplib/test/proxy/digest_squid.conf
@@ -0,0 +1,81 @@
+#
+# Recommended minimum configuration:
+#
+
+# Example rule allowing access from your local networks.
+# Adapt to list your (internal) IP networks from where browsing
+# should be allowed
+acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
+acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
+acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
+acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
+acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
+acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
+acl localnet src fc00::/7 # RFC 4193 local private network range
+acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
+
+acl SSL_ports port 443
+acl Safe_ports port 80 # http
+acl Safe_ports port 21 # ftp
+acl Safe_ports port 443 # https
+acl Safe_ports port 70 # gopher
+acl Safe_ports port 210 # wais
+acl Safe_ports port 1025-65535 # unregistered ports
+acl Safe_ports port 280 # http-mgmt
+acl Safe_ports port 488 # gss-http
+acl Safe_ports port 591 # filemaker
+acl Safe_ports port 777 # multiling http
+acl CONNECT method CONNECT
+
+auth_param digest program /usr/lib/squid/digest_file_auth /etc/squid/passwd
+auth_param digest realm proxy
+acl authenticated proxy_auth REQUIRED
+http_access allow authenticated
+
+#
+# Recommended minimum Access Permission configuration:
+#
+# Deny requests to certain unsafe ports
+http_access deny !Safe_ports
+
+# Deny CONNECT to other than secure SSL ports
+http_access deny CONNECT !SSL_ports
+
+# Only allow cachemgr access from localhost
+http_access allow localhost manager
+http_access deny manager
+
+# We strongly recommend the following be uncommented to protect innocent
+# web applications running on the proxy server who think the only
+# one who can access services on "localhost" is a local user
+#http_access deny to_localhost
+
+#
+# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
+#
+
+# Example rule allowing access from your local networks.
+# Adapt localnet in the ACL section to list your (internal) IP networks
+# from where browsing should be allowed
+http_access allow localnet
+http_access allow localhost
+
+# And finally deny all other access to this proxy
+http_access deny all
+
+# Squid normally listens to port 3128
+http_port 3129
+
+# Uncomment and adjust the following to add a disk cache directory.
+#cache_dir ufs /var/spool/squid 100 16 256
+
+# Leave coredumps in the first cache dir
+coredump_dir /var/spool/squid
+
+#
+# Add any of your own refresh_pattern entries above these.
+#
+refresh_pattern ^ftp: 1440 20% 10080
+refresh_pattern ^gopher: 1440 0% 1440
+refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
+refresh_pattern . 0 20% 4320
diff --git a/libs/cpp-httplib/test/proxy/docker-compose.yml b/libs/cpp-httplib/test/proxy/docker-compose.yml
new file mode 100644
index 0000000..8ffe81e
--- /dev/null
+++ b/libs/cpp-httplib/test/proxy/docker-compose.yml
@@ -0,0 +1,20 @@
+services:
+ squid_basic:
+ image: squid_basic
+ restart: always
+ ports:
+ - "3128:3128"
+ build:
+ context: ./
+ args:
+ auth: basic
+
+ squid_digest:
+ image: squid_digest
+ restart: always
+ ports:
+ - "3129:3129"
+ build:
+ context: ./
+ args:
+ auth: digest
diff --git a/libs/cpp-httplib/test/test.cc b/libs/cpp-httplib/test/test.cc
new file mode 100644
index 0000000..a9ac0d1
--- /dev/null
+++ b/libs/cpp-httplib/test/test.cc
@@ -0,0 +1,10830 @@
+// NOTE: This file should be saved as UTF-8 w/ BOM
+#include <httplib.h>
+#include <signal.h>
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#include <curl/curl.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+#include <gtest/gtest.h>
+
+#include <atomic>
+#include <chrono>
+#include <fstream>
+#include <future>
+#include <limits>
+#include <memory>
+#include <sstream>
+#include <stdexcept>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#define SERVER_CERT_FILE "./cert.pem"
+#define SERVER_CERT2_FILE "./cert2.pem"
+#define SERVER_PRIVATE_KEY_FILE "./key.pem"
+#define CA_CERT_FILE "./ca-bundle.crt"
+#define CLIENT_CA_CERT_FILE "./rootCA.cert.pem"
+#define CLIENT_CA_CERT_DIR "."
+#define CLIENT_CERT_FILE "./client.cert.pem"
+#define CLIENT_PRIVATE_KEY_FILE "./client.key.pem"
+#define CLIENT_ENCRYPTED_CERT_FILE "./client_encrypted.cert.pem"
+#define CLIENT_ENCRYPTED_PRIVATE_KEY_FILE "./client_encrypted.key.pem"
+#define CLIENT_ENCRYPTED_PRIVATE_KEY_PASS "test012!"
+#define SERVER_ENCRYPTED_CERT_FILE "./cert_encrypted.pem"
+#define SERVER_ENCRYPTED_PRIVATE_KEY_FILE "./key_encrypted.pem"
+#define SERVER_ENCRYPTED_PRIVATE_KEY_PASS "test123!"
+
+using namespace std;
+using namespace httplib;
+
+const char *HOST = "localhost";
+const int PORT = 1234;
+
+const string LONG_QUERY_VALUE = string(25000, '@');
+const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE;
+
+const string TOO_LONG_QUERY_VALUE = string(35000, '@');
+const string TOO_LONG_QUERY_URL =
+ "/too-long-query-value?key=" + TOO_LONG_QUERY_VALUE;
+
+const std::string JSON_DATA = "{\"hello\":\"world\"}";
+
+const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
+
+FormData &get_file_value(std::vector<FormData> &items, const char *key) {
+ auto it = std::find_if(items.begin(), items.end(), [&](const FormData &file) {
+ return file.name == key;
+ });
+#ifdef CPPHTTPLIB_NO_EXCEPTIONS
+ return *it;
+#else
+ if (it != items.end()) { return *it; }
+ throw std::runtime_error("invalid multipart form data name error");
+#endif
+}
+
+static void read_file(const std::string &path, std::string &out) {
+ std::ifstream fs(path, std::ios_base::binary);
+ if (!fs) throw std::runtime_error("File not found: " + path);
+ fs.seekg(0, std::ios_base::end);
+ auto size = fs.tellg();
+ fs.seekg(0);
+ out.resize(static_cast<size_t>(size));
+ fs.read(&out[0], static_cast<std::streamsize>(size));
+}
+
+class UnixSocketTest : public ::testing::Test {
+protected:
+ void TearDown() override { std::remove(pathname_.c_str()); }
+
+ void client_GET(const std::string &addr) {
+ httplib::Client cli{addr};
+ cli.set_address_family(AF_UNIX);
+ ASSERT_TRUE(cli.is_valid());
+
+ const auto &result = cli.Get(pattern_);
+ ASSERT_TRUE(result) << "error: " << result.error();
+
+ const auto &resp = result.value();
+ EXPECT_EQ(resp.status, StatusCode::OK_200);
+ EXPECT_EQ(resp.body, content_);
+ }
+
+ const std::string pathname_{"./httplib-server.sock"};
+ const std::string pattern_{"/hi"};
+ const std::string content_{"Hello World!"};
+};
+
+TEST_F(UnixSocketTest, pathname) {
+ httplib::Server svr;
+ svr.Get(pattern_, [&](const httplib::Request &, httplib::Response &res) {
+ res.set_content(content_, "text/plain");
+ });
+
+ std::thread t{[&] {
+ ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80));
+ }};
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+ ASSERT_TRUE(svr.is_running());
+
+ client_GET(pathname_);
+}
+
+#if defined(__linux__) || \
+ /* __APPLE__ */ (defined(SOL_LOCAL) && defined(SO_PEERPID))
+TEST_F(UnixSocketTest, PeerPid) {
+ httplib::Server svr;
+ std::string remote_port_val;
+ svr.Get(pattern_, [&](const httplib::Request &req, httplib::Response &res) {
+ res.set_content(content_, "text/plain");
+ remote_port_val = req.get_header_value("REMOTE_PORT");
+ });
+
+ std::thread t{[&] {
+ ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80));
+ }};
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+ ASSERT_TRUE(svr.is_running());
+
+ client_GET(pathname_);
+ EXPECT_EQ(std::to_string(getpid()), remote_port_val);
+}
+#endif
+
+#ifdef __linux__
+TEST_F(UnixSocketTest, abstract) {
+ constexpr char svr_path[]{"\x00httplib-server.sock"};
+ const std::string abstract_addr{svr_path, sizeof(svr_path) - 1};
+
+ httplib::Server svr;
+ svr.Get(pattern_, [&](const httplib::Request &, httplib::Response &res) {
+ res.set_content(content_, "text/plain");
+ });
+
+ std::thread t{[&] {
+ ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(abstract_addr, 80));
+ }};
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+ ASSERT_TRUE(svr.is_running());
+
+ client_GET(abstract_addr);
+}
+#endif
+
+TEST_F(UnixSocketTest, HostHeaderAutoSet) {
+ httplib::Server svr;
+ std::string received_host_header;
+
+ svr.Get(pattern_, [&](const httplib::Request &req, httplib::Response &res) {
+ // Capture the Host header sent by the client
+ auto host_iter = req.headers.find("Host");
+ if (host_iter != req.headers.end()) {
+ received_host_header = host_iter->second;
+ }
+ res.set_content(content_, "text/plain");
+ });
+
+ std::thread t{[&] {
+ ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80));
+ }};
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+ ASSERT_TRUE(svr.is_running());
+
+ // Test that Host header is automatically set to "localhost" for Unix socket
+ // connections
+ httplib::Client cli{pathname_};
+ cli.set_address_family(AF_UNIX);
+ ASSERT_TRUE(cli.is_valid());
+
+ const auto &result = cli.Get(pattern_);
+ ASSERT_TRUE(result) << "error: " << result.error();
+
+ const auto &resp = result.value();
+ EXPECT_EQ(resp.status, StatusCode::OK_200);
+ EXPECT_EQ(resp.body, content_);
+
+ // Verify that Host header was automatically set to "localhost"
+ EXPECT_EQ(received_host_header, "localhost");
+}
+
+#ifndef _WIN32
+TEST(SocketStream, wait_writable_UNIX) {
+ int fds[2];
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
+
+ const auto asSocketStream = [&](socket_t fd,
+ std::function<bool(Stream &)> func) {
+ return detail::process_client_socket(
+ fd, 0, 0, 0, 0, 0, std::chrono::steady_clock::time_point::min(), func);
+ };
+ asSocketStream(fds[0], [&](Stream &s0) {
+ EXPECT_EQ(s0.socket(), fds[0]);
+ EXPECT_TRUE(s0.wait_writable());
+
+ EXPECT_EQ(0, close(fds[1]));
+ EXPECT_FALSE(s0.wait_writable());
+
+ return true;
+ });
+ EXPECT_EQ(0, close(fds[0]));
+}
+
+TEST(SocketStream, wait_writable_INET) {
+ sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(PORT + 1);
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ int disconnected_svr_sock = -1;
+ std::thread svr{[&] {
+ const int s = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_LE(0, s);
+ ASSERT_EQ(0, ::bind(s, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)));
+ ASSERT_EQ(0, listen(s, 1));
+ ASSERT_LE(0, disconnected_svr_sock = accept(s, nullptr, nullptr));
+ ASSERT_EQ(0, close(s));
+ }};
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ std::thread cli{[&] {
+ const int s = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_LE(0, s);
+ ASSERT_EQ(0, connect(s, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)));
+ ASSERT_EQ(0, close(s));
+ }};
+ cli.join();
+ svr.join();
+ ASSERT_NE(disconnected_svr_sock, -1);
+
+ const auto asSocketStream = [&](socket_t fd,
+ std::function<bool(Stream &)> func) {
+ return detail::process_client_socket(
+ fd, 0, 0, 0, 0, 0, std::chrono::steady_clock::time_point::min(), func);
+ };
+ asSocketStream(disconnected_svr_sock, [&](Stream &ss) {
+ EXPECT_EQ(ss.socket(), disconnected_svr_sock);
+ EXPECT_FALSE(ss.wait_writable());
+
+ return true;
+ });
+
+ ASSERT_EQ(0, close(disconnected_svr_sock));
+}
+#endif // #ifndef _WIN32
+
+TEST(ClientTest, MoveConstructible) {
+ EXPECT_FALSE(std::is_copy_constructible<Client>::value);
+ EXPECT_TRUE(std::is_nothrow_move_constructible<Client>::value);
+}
+
+TEST(ClientTest, MoveAssignable) {
+ EXPECT_FALSE(std::is_copy_assignable<Client>::value);
+ EXPECT_TRUE(std::is_nothrow_move_assignable<Client>::value);
+}
+
+#ifdef _WIN32
+TEST(StartupTest, WSAStartup) {
+ WSADATA wsaData;
+ int ret = WSAStartup(0x0002, &wsaData);
+ ASSERT_EQ(0, ret);
+}
+#endif
+
+TEST(DecodePathTest, PercentCharacter) {
+ EXPECT_EQ(
+ decode_path_component(
+ R"(descrip=Gastos%20%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA%C3%B1%C3%91%206)"),
+ u8"descrip=Gastos áéíóúñÑ 6");
+}
+
+TEST(DecodePathTest, PercentCharacterNUL) {
+ string expected;
+ expected.push_back('x');
+ expected.push_back('\0');
+ expected.push_back('x');
+
+ EXPECT_EQ(decode_path_component("x%00x"), expected);
+}
+
+TEST(EncodeQueryParamTest, ParseUnescapedChararactersTest) {
+ string unescapedCharacters = "-_.!~*'()";
+
+ EXPECT_EQ(httplib::encode_uri_component(unescapedCharacters), "-_.!~*'()");
+}
+
+TEST(EncodeQueryParamTest, ParseReservedCharactersTest) {
+ string reservedCharacters = ";,/?:@&=+$";
+
+ EXPECT_EQ(httplib::encode_uri_component(reservedCharacters),
+ "%3B%2C%2F%3F%3A%40%26%3D%2B%24");
+}
+
+TEST(EncodeQueryParamTest, TestUTF8Characters) {
+ string chineseCharacters = u8"中国語";
+ string russianCharacters = u8"дом";
+ string brazilianCharacters = u8"óculos";
+
+ EXPECT_EQ(httplib::encode_uri_component(chineseCharacters),
+ "%E4%B8%AD%E5%9B%BD%E8%AA%9E");
+
+ EXPECT_EQ(httplib::encode_uri_component(russianCharacters),
+ "%D0%B4%D0%BE%D0%BC");
+
+ EXPECT_EQ(httplib::encode_uri_component(brazilianCharacters), "%C3%B3culos");
+}
+
+TEST(EncodeUriComponentTest, ParseUnescapedChararactersTest) {
+ string unescapedCharacters = "-_.!~*'()";
+
+ EXPECT_EQ(httplib::encode_uri_component(unescapedCharacters), "-_.!~*'()");
+}
+
+TEST(EncodeUriComponentTest, ParseReservedCharactersTest) {
+ string reservedCharacters = ";,/?:@&=+$";
+
+ EXPECT_EQ(httplib::encode_uri_component(reservedCharacters),
+ "%3B%2C%2F%3F%3A%40%26%3D%2B%24");
+}
+
+TEST(EncodeUriComponentTest, TestUTF8Characters) {
+ string chineseCharacters = u8"中国語";
+ string russianCharacters = u8"дом";
+ string brazilianCharacters = u8"óculos";
+
+ EXPECT_EQ(httplib::encode_uri_component(chineseCharacters),
+ "%E4%B8%AD%E5%9B%BD%E8%AA%9E");
+
+ EXPECT_EQ(httplib::encode_uri_component(russianCharacters),
+ "%D0%B4%D0%BE%D0%BC");
+
+ EXPECT_EQ(httplib::encode_uri_component(brazilianCharacters), "%C3%B3culos");
+}
+
+TEST(EncodeUriComponentTest, TestPathComponentEncoding) {
+ // Issue #2082 use case: encoding path component with ampersand
+ string pathWithAmpersand = "Piri Tommy Villiers - on & on";
+
+ EXPECT_EQ(httplib::encode_uri_component(pathWithAmpersand),
+ "Piri%20Tommy%20Villiers%20-%20on%20%26%20on");
+}
+
+TEST(EncodeUriTest, ParseUnescapedChararactersTest) {
+ string unescapedCharacters = "-_.!~*'()";
+
+ EXPECT_EQ(httplib::encode_uri(unescapedCharacters), "-_.!~*'()");
+}
+
+TEST(EncodeUriTest, ParseReservedCharactersTest) {
+ string reservedCharacters = ";,/?:@&=+$#";
+
+ EXPECT_EQ(httplib::encode_uri(reservedCharacters), ";,/?:@&=+$#");
+}
+
+TEST(EncodeUriTest, TestUTF8Characters) {
+ string chineseCharacters = u8"中国語";
+ string russianCharacters = u8"дом";
+ string brazilianCharacters = u8"óculos";
+
+ EXPECT_EQ(httplib::encode_uri(chineseCharacters),
+ "%E4%B8%AD%E5%9B%BD%E8%AA%9E");
+
+ EXPECT_EQ(httplib::encode_uri(russianCharacters), "%D0%B4%D0%BE%D0%BC");
+
+ EXPECT_EQ(httplib::encode_uri(brazilianCharacters), "%C3%B3culos");
+}
+
+TEST(EncodeUriTest, TestCompleteUri) {
+ string uri =
+ "https://example.com/path/to/resource?query=value&param=test#fragment";
+
+ EXPECT_EQ(
+ httplib::encode_uri(uri),
+ "https://example.com/path/to/resource?query=value&param=test#fragment");
+}
+
+TEST(EncodeUriTest, TestUriWithSpacesAndSpecialChars) {
+ string uri =
+ "https://example.com/path with spaces/file name.html?q=hello world";
+
+ EXPECT_EQ(httplib::encode_uri(uri),
+ "https://example.com/path%20with%20spaces/"
+ "file%20name.html?q=hello%20world");
+}
+
+TEST(DecodeUriComponentTest, ParseEncodedChararactersTest) {
+ string encodedString = "%3B%2C%2F%3F%3A%40%26%3D%2B%24";
+
+ EXPECT_EQ(httplib::decode_uri_component(encodedString), ";,/?:@&=+$");
+}
+
+TEST(DecodeUriComponentTest, ParseUnescapedChararactersTest) {
+ string unescapedCharacters = "-_.!~*'()";
+
+ EXPECT_EQ(httplib::decode_uri_component(unescapedCharacters), "-_.!~*'()");
+}
+
+TEST(DecodeUriComponentTest, TestUTF8Characters) {
+ string encodedChinese = "%E4%B8%AD%E5%9B%BD%E8%AA%9E";
+ string encodedRussian = "%D0%B4%D0%BE%D0%BC";
+ string encodedBrazilian = "%C3%B3culos";
+
+ EXPECT_EQ(httplib::decode_uri_component(encodedChinese), u8"中国語");
+ EXPECT_EQ(httplib::decode_uri_component(encodedRussian), u8"дом");
+ EXPECT_EQ(httplib::decode_uri_component(encodedBrazilian), u8"óculos");
+}
+
+TEST(DecodeUriComponentTest, TestPathComponentDecoding) {
+ string encodedPath = "Piri%20Tommy%20Villiers%20-%20on%20%26%20on";
+
+ EXPECT_EQ(httplib::decode_uri_component(encodedPath),
+ "Piri Tommy Villiers - on & on");
+}
+
+TEST(DecodeUriTest, ParseEncodedChararactersTest) {
+ string encodedString = "%20%22%3C%3E%5C%5E%60%7B%7D%7C";
+
+ EXPECT_EQ(httplib::decode_uri(encodedString), " \"<>\\^`{}|");
+}
+
+TEST(DecodeUriTest, ParseUnescapedChararactersTest) {
+ string unescapedCharacters = "-_.!~*'();,/?:@&=+$#";
+
+ EXPECT_EQ(httplib::decode_uri(unescapedCharacters), "-_.!~*'();,/?:@&=+$#");
+}
+
+TEST(DecodeUriTest, TestUTF8Characters) {
+ string encodedChinese = "%E4%B8%AD%E5%9B%BD%E8%AA%9E";
+ string encodedRussian = "%D0%B4%D0%BE%D0%BC";
+ string encodedBrazilian = "%C3%B3culos";
+
+ EXPECT_EQ(httplib::decode_uri(encodedChinese), u8"中国語");
+ EXPECT_EQ(httplib::decode_uri(encodedRussian), u8"дом");
+ EXPECT_EQ(httplib::decode_uri(encodedBrazilian), u8"óculos");
+}
+
+TEST(DecodeUriTest, TestCompleteUri) {
+ string encodedUri = "https://example.com/path%20with%20spaces/"
+ "file%20name.html?q=hello%20world";
+
+ EXPECT_EQ(
+ httplib::decode_uri(encodedUri),
+ "https://example.com/path with spaces/file name.html?q=hello world");
+}
+
+TEST(DecodeUriTest, TestRoundTripWithEncodeUri) {
+ string original =
+ "https://example.com/path with spaces/file name.html?q=hello world";
+ string encoded = httplib::encode_uri(original);
+ string decoded = httplib::decode_uri(encoded);
+
+ EXPECT_EQ(decoded, original);
+}
+
+TEST(DecodeUriComponentTest, TestRoundTripWithEncodeUriComponent) {
+ string original = "Piri Tommy Villiers - on & on";
+ string encoded = httplib::encode_uri_component(original);
+ string decoded = httplib::decode_uri_component(encoded);
+
+ EXPECT_EQ(decoded, original);
+}
+
+TEST(TrimTests, TrimStringTests) {
+ EXPECT_EQ("abc", detail::trim_copy("abc"));
+ EXPECT_EQ("abc", detail::trim_copy(" abc "));
+ EXPECT_TRUE(detail::trim_copy("").empty());
+}
+
+TEST(ParseAcceptHeaderTest, BasicAcceptParsing) {
+ // Simple case without quality values
+ std::vector<std::string> result1;
+ EXPECT_TRUE(detail::parse_accept_header(
+ "text/html,application/json,text/plain", result1));
+ EXPECT_EQ(result1.size(), 3U);
+ EXPECT_EQ(result1[0], "text/html");
+ EXPECT_EQ(result1[1], "application/json");
+ EXPECT_EQ(result1[2], "text/plain");
+
+ // With quality values
+ std::vector<std::string> result2;
+ EXPECT_TRUE(detail::parse_accept_header(
+ "text/html;q=0.9,application/json;q=1.0,text/plain;q=0.8", result2));
+ EXPECT_EQ(result2.size(), 3U);
+ EXPECT_EQ(result2[0], "application/json"); // highest q value
+ EXPECT_EQ(result2[1], "text/html");
+ EXPECT_EQ(result2[2], "text/plain"); // lowest q value
+}
+
+TEST(ParseAcceptHeaderTest, MixedQualityValues) {
+ // Mixed with and without quality values
+ std::vector<std::string> result;
+ EXPECT_TRUE(detail::parse_accept_header(
+ "text/html,application/json;q=0.5,text/plain;q=0.8", result));
+ EXPECT_EQ(result.size(), 3U);
+ EXPECT_EQ(result[0], "text/html"); // no q value means 1.0
+ EXPECT_EQ(result[1], "text/plain"); // q=0.8
+ EXPECT_EQ(result[2], "application/json"); // q=0.5
+}
+
+TEST(ParseAcceptHeaderTest, EdgeCases) {
+ // Empty header
+ std::vector<std::string> empty_result;
+ EXPECT_TRUE(detail::parse_accept_header("", empty_result));
+ EXPECT_TRUE(empty_result.empty());
+
+ // Single type
+ std::vector<std::string> single_result;
+ EXPECT_TRUE(detail::parse_accept_header("application/json", single_result));
+ EXPECT_EQ(single_result.size(), 1U);
+ EXPECT_EQ(single_result[0], "application/json");
+
+ // Wildcard types
+ std::vector<std::string> wildcard_result;
+ EXPECT_TRUE(detail::parse_accept_header(
+ "text/*;q=0.5,*/*;q=0.1,application/json", wildcard_result));
+ EXPECT_EQ(wildcard_result.size(), 3U);
+ EXPECT_EQ(wildcard_result[0], "application/json");
+ EXPECT_EQ(wildcard_result[1], "text/*");
+ EXPECT_EQ(wildcard_result[2], "*/*");
+}
+
+TEST(ParseAcceptHeaderTest, RealWorldExamples) {
+ // Common browser Accept header
+ std::vector<std::string> browser_result;
+ EXPECT_TRUE(
+ detail::parse_accept_header("text/html,application/xhtml+xml,application/"
+ "xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
+ browser_result));
+ EXPECT_EQ(browser_result.size(), 6U);
+ EXPECT_EQ(browser_result[0], "text/html"); // q=1.0 (default)
+ EXPECT_EQ(browser_result[1], "application/xhtml+xml"); // q=1.0 (default)
+ EXPECT_EQ(browser_result[2], "image/webp"); // q=1.0 (default)
+ EXPECT_EQ(browser_result[3], "image/apng"); // q=1.0 (default)
+ EXPECT_EQ(browser_result[4], "application/xml"); // q=0.9
+ EXPECT_EQ(browser_result[5], "*/*"); // q=0.8
+
+ // API client header
+ std::vector<std::string> api_result;
+ EXPECT_TRUE(detail::parse_accept_header(
+ "application/json;q=0.9,application/xml;q=0.8,text/plain;q=0.1",
+ api_result));
+ EXPECT_EQ(api_result.size(), 3U);
+ EXPECT_EQ(api_result[0], "application/json");
+ EXPECT_EQ(api_result[1], "application/xml");
+ EXPECT_EQ(api_result[2], "text/plain");
+}
+
+TEST(ParseAcceptHeaderTest, SpecialCases) {
+ // Quality value with 3 decimal places
+ std::vector<std::string> decimal_result;
+ EXPECT_TRUE(detail::parse_accept_header(
+ "text/html;q=0.123,application/json;q=0.456", decimal_result));
+ EXPECT_EQ(decimal_result.size(), 2U);
+ EXPECT_EQ(decimal_result[0], "application/json"); // Higher q value
+ EXPECT_EQ(decimal_result[1], "text/html");
+
+ // Zero quality (should still be included but with lowest priority)
+ std::vector<std::string> zero_q_result;
+ EXPECT_TRUE(detail::parse_accept_header("text/html;q=0,application/json;q=1",
+ zero_q_result));
+ EXPECT_EQ(zero_q_result.size(), 2U);
+ EXPECT_EQ(zero_q_result[0], "application/json"); // q=1
+ EXPECT_EQ(zero_q_result[1], "text/html"); // q=0
+
+ // No spaces around commas
+ std::vector<std::string> no_space_result;
+ EXPECT_TRUE(detail::parse_accept_header(
+ "text/html;q=0.9,application/json;q=0.8,text/plain;q=0.7",
+ no_space_result));
+ EXPECT_EQ(no_space_result.size(), 3U);
+ EXPECT_EQ(no_space_result[0], "text/html");
+ EXPECT_EQ(no_space_result[1], "application/json");
+ EXPECT_EQ(no_space_result[2], "text/plain");
+}
+
+TEST(ParseAcceptHeaderTest, InvalidCases) {
+ std::vector<std::string> result;
+
+ // Invalid quality value (> 1.0)
+ EXPECT_FALSE(
+ detail::parse_accept_header("text/html;q=1.5,application/json", result));
+
+ // Invalid quality value (< 0.0)
+ EXPECT_FALSE(
+ detail::parse_accept_header("text/html;q=-0.1,application/json", result));
+
+ // Invalid quality value (not a number)
+ EXPECT_FALSE(detail::parse_accept_header(
+ "text/html;q=invalid,application/json", result));
+
+ // Empty quality value
+ EXPECT_FALSE(
+ detail::parse_accept_header("text/html;q=,application/json", result));
+
+ // Invalid media type format (no slash and not wildcard)
+ EXPECT_FALSE(
+ detail::parse_accept_header("invalidtype,application/json", result));
+
+ // Empty media type
+ result.clear();
+ EXPECT_FALSE(detail::parse_accept_header(",application/json", result));
+
+ // Only commas
+ result.clear();
+ EXPECT_FALSE(detail::parse_accept_header(",,,", result));
+
+ // Valid cases should still work
+ EXPECT_TRUE(detail::parse_accept_header("*/*", result));
+ EXPECT_EQ(result.size(), 1U);
+ EXPECT_EQ(result[0], "*/*");
+
+ EXPECT_TRUE(detail::parse_accept_header("*", result));
+ EXPECT_EQ(result.size(), 1U);
+ EXPECT_EQ(result[0], "*");
+
+ EXPECT_TRUE(detail::parse_accept_header("text/*", result));
+ EXPECT_EQ(result.size(), 1U);
+ EXPECT_EQ(result[0], "text/*");
+}
+
+TEST(ParseAcceptHeaderTest, ContentTypesPopulatedAndInvalidHeaderHandling) {
+ Server svr;
+
+ svr.Get("/accept_ok", [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.accept_content_types.size(), 3U);
+ EXPECT_EQ(req.accept_content_types[0], "application/json");
+ EXPECT_EQ(req.accept_content_types[1], "text/html");
+ EXPECT_EQ(req.accept_content_types[2], "*/*");
+ res.set_content("ok", "text/plain");
+ });
+
+ svr.Get("/accept_bad_request", [&](const Request & /*req*/, Response &res) {
+ EXPECT_TRUE(false);
+ res.set_content("bad request", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ {
+ auto res =
+ cli.Get("/accept_ok",
+ {{"Accept", "application/json, text/html;q=0.8, */*;q=0.1"}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ auto res = cli.Get("/accept_bad_request",
+ {{"Accept", "text/html;q=abc,application/json"}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::BadRequest_400, res->status);
+ }
+}
+
+TEST(DivideTest, DivideStringTests) {
+ auto divide = [](const std::string &str, char d) {
+ std::string lhs;
+ std::string rhs;
+
+ detail::divide(str, d,
+ [&](const char *lhs_data, std::size_t lhs_size,
+ const char *rhs_data, std::size_t rhs_size) {
+ lhs.assign(lhs_data, lhs_size);
+ rhs.assign(rhs_data, rhs_size);
+ });
+
+ return std::make_pair(std::move(lhs), std::move(rhs));
+ };
+
+ {
+ const auto res = divide("", '=');
+ EXPECT_EQ(res.first, "");
+ EXPECT_EQ(res.second, "");
+ }
+
+ {
+ const auto res = divide("=", '=');
+ EXPECT_EQ(res.first, "");
+ EXPECT_EQ(res.second, "");
+ }
+
+ {
+ const auto res = divide(" ", '=');
+ EXPECT_EQ(res.first, " ");
+ EXPECT_EQ(res.second, "");
+ }
+
+ {
+ const auto res = divide("a", '=');
+ EXPECT_EQ(res.first, "a");
+ EXPECT_EQ(res.second, "");
+ }
+
+ {
+ const auto res = divide("a=", '=');
+ EXPECT_EQ(res.first, "a");
+ EXPECT_EQ(res.second, "");
+ }
+
+ {
+ const auto res = divide("=b", '=');
+ EXPECT_EQ(res.first, "");
+ EXPECT_EQ(res.second, "b");
+ }
+
+ {
+ const auto res = divide("a=b", '=');
+ EXPECT_EQ(res.first, "a");
+ EXPECT_EQ(res.second, "b");
+ }
+
+ {
+ const auto res = divide("a=b=", '=');
+ EXPECT_EQ(res.first, "a");
+ EXPECT_EQ(res.second, "b=");
+ }
+
+ {
+ const auto res = divide("a=b=c", '=');
+ EXPECT_EQ(res.first, "a");
+ EXPECT_EQ(res.second, "b=c");
+ }
+}
+
+TEST(SplitTest, ParseQueryString) {
+ string s = "key1=val1&key2=val2&key3=val3";
+ Params dic;
+
+ detail::split(s.c_str(), s.c_str() + s.size(), '&',
+ [&](const char *b, const char *e) {
+ string key, val;
+ detail::split(b, e, '=', [&](const char *b2, const char *e2) {
+ if (key.empty()) {
+ key.assign(b2, e2);
+ } else {
+ val.assign(b2, e2);
+ }
+ });
+ dic.emplace(key, val);
+ });
+
+ EXPECT_EQ("val1", dic.find("key1")->second);
+ EXPECT_EQ("val2", dic.find("key2")->second);
+ EXPECT_EQ("val3", dic.find("key3")->second);
+}
+
+TEST(SplitTest, ParseInvalidQueryTests) {
+
+ {
+ string s = " ";
+ Params dict;
+ detail::parse_query_text(s, dict);
+ EXPECT_TRUE(dict.empty());
+ }
+
+ {
+ string s = " = =";
+ Params dict;
+ detail::parse_query_text(s, dict);
+ EXPECT_TRUE(dict.empty());
+ }
+}
+
+TEST(ParseQueryTest, ParseQueryString) {
+ {
+ std::string s = "key1=val1&key2=val2&key3=val3";
+ Params dic;
+
+ detail::parse_query_text(s, dic);
+
+ EXPECT_EQ("val1", dic.find("key1")->second);
+ EXPECT_EQ("val2", dic.find("key2")->second);
+ EXPECT_EQ("val3", dic.find("key3")->second);
+ }
+
+ {
+ std::string s = "key1&key2=val1&key3=val1=val2&key4=val1=val2=val3";
+ Params dic;
+
+ detail::parse_query_text(s, dic);
+
+ EXPECT_EQ("", dic.find("key1")->second);
+ EXPECT_EQ("val1", dic.find("key2")->second);
+ EXPECT_EQ("val1=val2", dic.find("key3")->second);
+ EXPECT_EQ("val1=val2=val3", dic.find("key4")->second);
+ }
+}
+
+TEST(ParamsToQueryTest, ConvertParamsToQuery) {
+ Params dic;
+
+ EXPECT_EQ(detail::params_to_query_str(dic), "");
+
+ dic.emplace("key1", "val1");
+
+ EXPECT_EQ(detail::params_to_query_str(dic), "key1=val1");
+
+ dic.emplace("key2", "val2");
+ dic.emplace("key3", "val3");
+
+ EXPECT_EQ(detail::params_to_query_str(dic), "key1=val1&key2=val2&key3=val3");
+}
+
+TEST(ParseMultipartBoundaryTest, DefaultValue) {
+ string content_type = "multipart/form-data; boundary=something";
+ string boundary;
+ auto ret = detail::parse_multipart_boundary(content_type, boundary);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(boundary, "something");
+}
+
+TEST(ParseMultipartBoundaryTest, ValueWithQuote) {
+ string content_type = "multipart/form-data; boundary=\"gc0pJq0M:08jU534c0p\"";
+ string boundary;
+ auto ret = detail::parse_multipart_boundary(content_type, boundary);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(boundary, "gc0pJq0M:08jU534c0p");
+}
+
+TEST(ParseMultipartBoundaryTest, ValueWithCharset) {
+ string content_type =
+ "multipart/mixed; boundary=THIS_STRING_SEPARATES;charset=UTF-8";
+ string boundary;
+ auto ret = detail::parse_multipart_boundary(content_type, boundary);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(boundary, "THIS_STRING_SEPARATES");
+}
+
+TEST(ParseMultipartBoundaryTest, ValueWithQuotesAndCharset) {
+ string content_type =
+ "multipart/mixed; boundary=\"cpp-httplib-multipart-data\"; charset=UTF-8";
+ string boundary;
+ auto ret = detail::parse_multipart_boundary(content_type, boundary);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(boundary, "cpp-httplib-multipart-data");
+}
+
+TEST(GetHeaderValueTest, DefaultValue) {
+ Headers headers = {{"Dummy", "Dummy"}};
+ auto val = detail::get_header_value(headers, "Content-Type", "text/plain", 0);
+ EXPECT_STREQ("text/plain", val);
+}
+
+TEST(GetHeaderValueTest, DefaultValueInt) {
+ Headers headers = {{"Dummy", "Dummy"}};
+ auto val = detail::get_header_value_u64(headers, "Content-Length", 100, 0);
+ EXPECT_EQ(100ull, val);
+}
+
+TEST(GetHeaderValueTest, RegularValue) {
+ Headers headers = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
+ auto val = detail::get_header_value(headers, "Content-Type", "text/plain", 0);
+ EXPECT_STREQ("text/html", val);
+}
+
+TEST(GetHeaderValueTest, RegularValueWithDifferentCase) {
+ Headers headers = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
+ auto val = detail::get_header_value(headers, "content-type", "text/plain", 0);
+ EXPECT_STREQ("text/html", val);
+}
+
+TEST(GetHeaderValueTest, SetContent) {
+ Response res;
+
+ res.set_content("html", "text/html");
+ EXPECT_EQ("text/html", res.get_header_value("Content-Type"));
+
+ res.set_content("text", "text/plain");
+ EXPECT_EQ(1U, res.get_header_value_count("Content-Type"));
+ EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
+}
+
+TEST(GetHeaderValueTest, RegularValueInt) {
+ Headers headers = {{"Content-Length", "100"}, {"Dummy", "Dummy"}};
+ auto val = detail::get_header_value_u64(headers, "Content-Length", 0, 0);
+ EXPECT_EQ(100ull, val);
+}
+
+TEST(GetHeaderValueTest, RegularInvalidValueInt) {
+ Headers headers = {{"Content-Length", "x"}};
+ auto is_invalid_value = false;
+ auto val = detail::get_header_value_u64(headers, "Content-Length", 0, 0,
+ is_invalid_value);
+ EXPECT_EQ(0ull, val);
+ EXPECT_TRUE(is_invalid_value);
+}
+
+TEST(GetHeaderValueTest, Range) {
+ {
+ Headers headers = {make_range_header({{1, -1}})};
+ auto val = detail::get_header_value(headers, "Range", 0, 0);
+ EXPECT_STREQ("bytes=1-", val);
+ }
+
+ {
+ Headers headers = {make_range_header({{-1, 1}})};
+ auto val = detail::get_header_value(headers, "Range", 0, 0);
+ EXPECT_STREQ("bytes=-1", val);
+ }
+
+ {
+ Headers headers = {make_range_header({{1, 10}})};
+ auto val = detail::get_header_value(headers, "Range", 0, 0);
+ EXPECT_STREQ("bytes=1-10", val);
+ }
+
+ {
+ Headers headers = {make_range_header({{1, 10}, {100, -1}})};
+ auto val = detail::get_header_value(headers, "Range", 0, 0);
+ EXPECT_STREQ("bytes=1-10, 100-", val);
+ }
+
+ {
+ Headers headers = {make_range_header({{1, 10}, {100, 200}})};
+ auto val = detail::get_header_value(headers, "Range", 0, 0);
+ EXPECT_STREQ("bytes=1-10, 100-200", val);
+ }
+
+ {
+ Headers headers = {make_range_header({{0, 0}, {-1, 1}})};
+ auto val = detail::get_header_value(headers, "Range", 0, 0);
+ EXPECT_STREQ("bytes=0-0, -1", val);
+ }
+}
+
+TEST(ParseHeaderValueTest, Range) {
+ {
+ Ranges ranges;
+ auto ret = detail::parse_range_header("bytes=1-", ranges);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(1u, ranges.size());
+ EXPECT_EQ(1u, ranges[0].first);
+ EXPECT_EQ(-1, ranges[0].second);
+ }
+
+ {
+ Ranges ranges;
+ auto ret = detail::parse_range_header("bytes=-1", ranges);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(1u, ranges.size());
+ EXPECT_EQ(-1, ranges[0].first);
+ EXPECT_EQ(1u, ranges[0].second);
+ }
+
+ {
+ Ranges ranges;
+ auto ret = detail::parse_range_header("bytes=1-10", ranges);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(1u, ranges.size());
+ EXPECT_EQ(1u, ranges[0].first);
+ EXPECT_EQ(10u, ranges[0].second);
+ }
+
+ {
+ Ranges ranges;
+ auto ret = detail::parse_range_header("bytes=10-1", ranges);
+ EXPECT_FALSE(ret);
+ }
+
+ {
+ Ranges ranges;
+ auto ret = detail::parse_range_header("bytes=1-10, 100-", ranges);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(2u, ranges.size());
+ EXPECT_EQ(1u, ranges[0].first);
+ EXPECT_EQ(10u, ranges[0].second);
+ EXPECT_EQ(100u, ranges[1].first);
+ EXPECT_EQ(-1, ranges[1].second);
+ }
+
+ {
+ Ranges ranges;
+ auto ret =
+ detail::parse_range_header("bytes=1-10, 100-200, 300-400", ranges);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(3u, ranges.size());
+ EXPECT_EQ(1u, ranges[0].first);
+ EXPECT_EQ(10u, ranges[0].second);
+ EXPECT_EQ(100u, ranges[1].first);
+ EXPECT_EQ(200u, ranges[1].second);
+ EXPECT_EQ(300u, ranges[2].first);
+ EXPECT_EQ(400u, ranges[2].second);
+ }
+
+ {
+ Ranges ranges;
+
+ EXPECT_FALSE(detail::parse_range_header("bytes", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=0", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=-", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes= ", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=,", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=,,", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=,,,", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=a-b", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=1-0", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=0--1", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=0- 1", ranges));
+ EXPECT_FALSE(detail::parse_range_header("bytes=0 -1", ranges));
+ EXPECT_TRUE(ranges.empty());
+ }
+}
+
+TEST(ParseAcceptEncoding1, AcceptEncoding) {
+ Request req;
+ req.set_header("Accept-Encoding", "gzip");
+
+ Response res;
+ res.set_header("Content-Type", "text/plain");
+
+ auto ret = detail::encoding_type(req, res);
+
+#ifdef CPPHTTPLIB_ZLIB_SUPPORT
+ EXPECT_TRUE(ret == detail::EncodingType::Gzip);
+#else
+ EXPECT_TRUE(ret == detail::EncodingType::None);
+#endif
+}
+
+TEST(ParseAcceptEncoding2, AcceptEncoding) {
+ Request req;
+ req.set_header("Accept-Encoding", "gzip, deflate, br, zstd");
+
+ Response res;
+ res.set_header("Content-Type", "text/plain");
+
+ auto ret = detail::encoding_type(req, res);
+
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+ EXPECT_TRUE(ret == detail::EncodingType::Brotli);
+#elif CPPHTTPLIB_ZLIB_SUPPORT
+ EXPECT_TRUE(ret == detail::EncodingType::Gzip);
+#elif CPPHTTPLIB_ZSTD_SUPPORT
+ EXPECT_TRUE(ret == detail::EncodingType::Zstd);
+#else
+ EXPECT_TRUE(ret == detail::EncodingType::None);
+#endif
+}
+
+TEST(ParseAcceptEncoding3, AcceptEncoding) {
+ Request req;
+ req.set_header("Accept-Encoding",
+ "br;q=1.0, gzip;q=0.8, zstd;q=0.8, *;q=0.1");
+
+ Response res;
+ res.set_header("Content-Type", "text/plain");
+
+ auto ret = detail::encoding_type(req, res);
+
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+ EXPECT_TRUE(ret == detail::EncodingType::Brotli);
+#elif CPPHTTPLIB_ZLIB_SUPPORT
+ EXPECT_TRUE(ret == detail::EncodingType::Gzip);
+#elif CPPHTTPLIB_ZSTD_SUPPORT
+ EXPECT_TRUE(ret == detail::EncodingType::Zstd);
+#else
+ EXPECT_TRUE(ret == detail::EncodingType::None);
+#endif
+}
+
+TEST(BufferStreamTest, read) {
+ detail::BufferStream strm1;
+ Stream &strm = strm1;
+
+ EXPECT_EQ(5, strm.write("hello"));
+
+ char buf[512];
+ EXPECT_EQ(2, strm.read(buf, 2));
+ EXPECT_EQ('h', buf[0]);
+ EXPECT_EQ('e', buf[1]);
+
+ EXPECT_EQ(2, strm.read(buf, 2));
+ EXPECT_EQ('l', buf[0]);
+ EXPECT_EQ('l', buf[1]);
+
+ EXPECT_EQ(1, strm.read(buf, 1));
+ EXPECT_EQ('o', buf[0]);
+
+ EXPECT_EQ(0, strm.read(buf, 1));
+}
+
+TEST(HostnameToIPConversionTest, HTTPWatch_Online) {
+ auto host = "www.httpwatch.com";
+
+ auto ip = hosted_at(host);
+ EXPECT_EQ("23.96.13.243", ip);
+
+ std::vector<std::string> addrs;
+ hosted_at(host, addrs);
+ EXPECT_EQ(1u, addrs.size());
+}
+
+#if 0 // It depends on each test environment...
+TEST(HostnameToIPConversionTest, YouTube_Online) {
+ auto host = "www.youtube.com";
+
+ std::vector<std::string> addrs;
+ hosted_at(host, addrs);
+
+ EXPECT_EQ(20u, addrs.size());
+
+ auto it = std::find(addrs.begin(), addrs.end(), "2607:f8b0:4006:809::200e");
+ EXPECT_TRUE(it != addrs.end());
+}
+#endif
+
+class ChunkedEncodingTest : public ::testing::Test {
+protected:
+ ChunkedEncodingTest()
+ : cli_(HOST, PORT)
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ ,
+ svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
+#endif
+ {
+ cli_.set_connection_timeout(2);
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli_.enable_server_certificate_verification(false);
+#endif
+ }
+
+ virtual void SetUp() {
+ read_file("./image.jpg", image_data_);
+
+ svr_.Get("/hi", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ svr_.Get(
+ "/chunked", [this](const httplib::Request &, httplib::Response &res) {
+ res.set_chunked_content_provider(
+ "image/jpeg", [this](size_t offset, httplib::DataSink &sink) {
+ size_t remaining = image_data_.size() - offset;
+ if (remaining == 0) {
+ sink.done();
+ } else {
+ constexpr size_t CHUNK_SIZE = 1024;
+ size_t send_size = std::min(CHUNK_SIZE, remaining);
+ sink.write(&image_data_[offset], send_size);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ return true;
+ });
+ });
+
+ t_ = thread([&]() { ASSERT_TRUE(svr_.listen(HOST, PORT)); });
+
+ svr_.wait_until_ready();
+ }
+
+ virtual void TearDown() {
+ svr_.stop();
+ if (!request_threads_.empty()) {
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ for (auto &t : request_threads_) {
+ t.join();
+ }
+ }
+ t_.join();
+ }
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli_;
+ SSLServer svr_;
+#else
+ Client cli_;
+ Server svr_;
+#endif
+ thread t_;
+ std::vector<thread> request_threads_;
+ std::string image_data_;
+};
+
+TEST_F(ChunkedEncodingTest, NormalGet) {
+ auto res = cli_.Get("/chunked");
+ ASSERT_TRUE(res);
+
+ std::string out;
+ read_file("./image.jpg", out);
+
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(out, res->body);
+}
+
+TEST_F(ChunkedEncodingTest, WithContentReceiver) {
+ std::string body;
+ auto res = cli_.Get("/chunked", [&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+ ASSERT_TRUE(res);
+
+ std::string out;
+ read_file("./image.jpg", out);
+
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(out, body);
+}
+
+TEST_F(ChunkedEncodingTest, WithResponseHandlerAndContentReceiver) {
+ std::string body;
+ auto res = cli_.Get(
+ "/chunked",
+ [&](const Response &response) {
+ EXPECT_EQ(StatusCode::OK_200, response.status);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+ ASSERT_TRUE(res);
+
+ std::string out;
+ read_file("./image.jpg", out);
+
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(out, body);
+}
+
+TEST(RangeTest, FromHTTPBin_Online) {
+#ifdef CPPHTTPLIB_DEFAULT_HTTPBIN
+ auto host = "httpbin.org";
+ auto path = std::string{"/range/32"};
+#else
+ auto host = "nghttp2.org";
+ auto path = std::string{"/httpbin/range/32"};
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ auto port = 443;
+ SSLClient cli(host, port);
+#else
+ auto port = 80;
+ Client cli(host, port);
+#endif
+ cli.set_connection_timeout(5);
+
+ {
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res);
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyzabcdef", res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ Headers headers = {make_range_header({{1, -1}})};
+ auto res = cli.Get(path, headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ("bcdefghijklmnopqrstuvwxyzabcdef", res->body);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ }
+
+ {
+ Headers headers = {make_range_header({{1, 10}})};
+ auto res = cli.Get(path, headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ("bcdefghijk", res->body);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ }
+
+ {
+ Headers headers = {make_range_header({{0, 31}})};
+ auto res = cli.Get(path, headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyzabcdef", res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ Headers headers = {make_range_header({{0, -1}})};
+ auto res = cli.Get(path, headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyzabcdef", res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ Headers headers = {make_range_header({{0, 32}})};
+ auto res = cli.Get(path, headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status);
+ }
+}
+
+TEST(GetAddrInfoDanglingRefTest, LongTimeout) {
+ auto host = "unresolvableaddress.local";
+ auto path = std::string{"/"};
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ auto port = 443;
+ SSLClient cli(host, port);
+#else
+ auto port = 80;
+ Client cli(host, port);
+#endif
+ cli.set_connection_timeout(1);
+
+ {
+ auto res = cli.Get(path);
+ ASSERT_FALSE(res);
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(8));
+}
+
+TEST(ConnectionErrorTest, InvalidHost) {
+ auto host = "-abcde.com";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ auto port = 443;
+ SSLClient cli(host, port);
+#else
+ auto port = 80;
+ Client cli(host, port);
+#endif
+ cli.set_connection_timeout(std::chrono::seconds(2));
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Connection, res.error());
+}
+
+TEST(ConnectionErrorTest, InvalidHost2) {
+ auto host = "httpbin.org/";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+ cli.set_connection_timeout(std::chrono::seconds(2));
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Connection, res.error());
+}
+
+TEST(ConnectionErrorTest, InvalidHostCheckResultErrorToString) {
+ auto host = "httpbin.org/";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+ cli.set_connection_timeout(std::chrono::seconds(2));
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(!res);
+ stringstream s;
+ s << "error code: " << res.error();
+ EXPECT_EQ("error code: Could not establish connection (2)", s.str());
+}
+
+TEST(ConnectionErrorTest, InvalidPort) {
+ auto host = "localhost";
+ auto port = 44380;
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host, port);
+#else
+ Client cli(host, port);
+#endif
+ cli.set_connection_timeout(std::chrono::seconds(2));
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(!res);
+ EXPECT_TRUE(Error::Connection == res.error() ||
+ Error::ConnectionTimeout == res.error());
+}
+
+TEST(ConnectionErrorTest, Timeout_Online) {
+ auto host = "google.com";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ auto port = 44380;
+ SSLClient cli(host, port);
+#else
+ auto port = 8080;
+ Client cli(host, port);
+#endif
+ cli.set_connection_timeout(std::chrono::seconds(2));
+
+ // only probe one address type so that the error reason
+ // correlates to the timed-out IPv4, not the unsupported
+ // IPv6 connection attempt
+ cli.set_address_family(AF_INET);
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::ConnectionTimeout, res.error());
+}
+
+TEST(CancelTest, NoCancel_Online) {
+#ifdef CPPHTTPLIB_DEFAULT_HTTPBIN
+ auto host = "httpbin.org";
+ auto path = std::string{"/range/32"};
+#else
+ auto host = "nghttp2.org";
+ auto path = std::string{"/httpbin/range/32"};
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ auto port = 443;
+ SSLClient cli(host, port);
+#else
+ auto port = 80;
+ Client cli(host, port);
+#endif
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res = cli.Get(path, [](uint64_t, uint64_t) { return true; });
+ ASSERT_TRUE(res);
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyzabcdef", res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(CancelTest, WithCancelSmallPayload_Online) {
+#ifdef CPPHTTPLIB_DEFAULT_HTTPBIN
+ auto host = "httpbin.org";
+ auto path = std::string{"/range/32"};
+#else
+ auto host = "nghttp2.org";
+ auto path = std::string{"/httpbin/range/32"};
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ auto port = 443;
+ SSLClient cli(host, port);
+#else
+ auto port = 80;
+ Client cli(host, port);
+#endif
+
+ auto res = cli.Get(path, [](uint64_t, uint64_t) { return false; });
+ cli.set_connection_timeout(std::chrono::seconds(5));
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, WithCancelLargePayload_Online) {
+#ifdef CPPHTTPLIB_DEFAULT_HTTPBIN
+ auto host = "httpbin.org";
+ auto path = std::string{"/range/65536"};
+#else
+ auto host = "nghttp2.org";
+ auto path = std::string{"/httpbin/range/65536"};
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ auto port = 443;
+ SSLClient cli(host, port);
+#else
+ auto port = 80;
+ Client cli(host, port);
+#endif
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ uint32_t count = 0;
+ auto res =
+ cli.Get(path, [&count](uint64_t, uint64_t) { return (count++ == 0); });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, NoCancelPost) {
+ Server svr;
+
+ svr.Post("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Post("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return true; });
+ ASSERT_TRUE(res);
+ EXPECT_EQ("Hello World!", res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(CancelTest, WithCancelSmallPayloadPost) {
+ Server svr;
+
+ svr.Post("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Post("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return false; });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, WithCancelLargePayloadPost) {
+ Server svr;
+
+ svr.Post("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content(LARGE_DATA, "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Post("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return false; });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, NoCancelPut) {
+ Server svr;
+
+ svr.Put("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Put("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return true; });
+ ASSERT_TRUE(res);
+ EXPECT_EQ("Hello World!", res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(CancelTest, WithCancelSmallPayloadPut) {
+ Server svr;
+
+ svr.Put("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Put("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return false; });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, WithCancelLargePayloadPut) {
+ Server svr;
+
+ svr.Put("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content(LARGE_DATA, "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Put("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return false; });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, NoCancelPatch) {
+ Server svr;
+
+ svr.Patch("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Patch("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return true; });
+ ASSERT_TRUE(res);
+ EXPECT_EQ("Hello World!", res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(CancelTest, WithCancelSmallPayloadPatch) {
+ Server svr;
+
+ svr.Patch("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Patch("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return false; });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, WithCancelLargePayloadPatch) {
+ Server svr;
+
+ svr.Patch("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content(LARGE_DATA, "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Patch("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return false; });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, NoCancelDelete) {
+ Server svr;
+
+ svr.Delete("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Delete("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return true; });
+ ASSERT_TRUE(res);
+ EXPECT_EQ("Hello World!", res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(CancelTest, WithCancelSmallPayloadDelete) {
+ Server svr;
+
+ svr.Delete("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Delete("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return false; });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST(CancelTest, WithCancelLargePayloadDelete) {
+ Server svr;
+
+ svr.Delete("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content(LARGE_DATA, "text/plain");
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_connection_timeout(std::chrono::seconds(5));
+
+ auto res =
+ cli.Delete("/", Headers(), JSON_DATA.data(), JSON_DATA.size(),
+ "application/json", [](uint64_t, uint64_t) { return false; });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+static std::string remove_whitespace(const std::string &input) {
+ std::string output;
+ output.reserve(input.size());
+ std::copy_if(input.begin(), input.end(), std::back_inserter(output),
+ [](unsigned char c) { return !std::isspace(c); });
+ return output;
+}
+
+TEST(BaseAuthTest, FromHTTPWatch_Online) {
+#ifdef CPPHTTPLIB_DEFAULT_HTTPBIN
+ auto host = "httpbin.org";
+ auto path = std::string{"/basic-auth/hello/world"};
+#else
+ auto host = "nghttp2.org";
+ auto path = std::string{"/httpbin/basic-auth/hello/world"};
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ auto port = 443;
+ SSLClient cli(host, port);
+#else
+ auto port = 80;
+ Client cli(host, port);
+#endif
+
+ {
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+
+ {
+ auto res =
+ cli.Get(path, {make_basic_authentication_header("hello", "world")});
+ ASSERT_TRUE(res);
+ EXPECT_EQ("{\"authenticated\":true,\"user\":\"hello\"}",
+ remove_whitespace(res->body));
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ cli.set_basic_auth("hello", "world");
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res);
+ EXPECT_EQ("{\"authenticated\":true,\"user\":\"hello\"}",
+ remove_whitespace(res->body));
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ cli.set_basic_auth("hello", "bad");
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+
+ {
+ cli.set_basic_auth("bad", "world");
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(DigestAuthTest, FromHTTPWatch_Online) {
+#ifdef CPPHTTPLIB_DEFAULT_HTTPBIN
+ auto host = "httpbin.org";
+ auto unauth_path = std::string{"/digest-auth/auth/hello/world"};
+ auto paths = std::vector<std::string>{
+ "/digest-auth/auth/hello/world/MD5",
+ "/digest-auth/auth/hello/world/SHA-256",
+ "/digest-auth/auth/hello/world/SHA-512",
+ "/digest-auth/auth-int/hello/world/MD5",
+ };
+#else
+ auto host = "nghttp2.org";
+ auto unauth_path = std::string{"/httpbin/digest-auth/auth/hello/world"};
+ auto paths = std::vector<std::string>{
+ "/httpbin/digest-auth/auth/hello/world/MD5",
+ "/httpbin/digest-auth/auth/hello/world/SHA-256",
+ "/httpbin/digest-auth/auth/hello/world/SHA-512",
+ "/httpbin/digest-auth/auth-int/hello/world/MD5",
+ };
+#endif
+
+ auto port = 443;
+ SSLClient cli(host, port);
+
+ {
+ auto res = cli.Get(unauth_path);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+
+ {
+
+ cli.set_digest_auth("hello", "world");
+ for (const auto &path : paths) {
+ auto res = cli.Get(path.c_str());
+ ASSERT_TRUE(res);
+ EXPECT_EQ("{\"authenticated\":true,\"user\":\"hello\"}",
+ remove_whitespace(res->body));
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ cli.set_digest_auth("hello", "bad");
+ for (const auto &path : paths) {
+ auto res = cli.Get(path.c_str());
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+
+ // NOTE: Until httpbin.org fixes issue #46, the following test is commented
+ // out. Please see https://httpbin.org/digest-auth/auth/hello/world
+ // cli.set_digest_auth("bad", "world");
+ // for (const auto& path : paths) {
+ // auto res = cli.Get(path.c_str());
+ // ASSERT_TRUE(res);
+ // EXPECT_EQ(StatusCode::BadRequest_400, res->status);
+ // }
+ }
+}
+#endif
+
+TEST(SpecifyServerIPAddressTest, AnotherHostname_Online) {
+ auto host = "google.com";
+ auto another_host = "example.com";
+ auto wrong_ip = "0.0.0.0";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+
+ cli.set_hostname_addr_map({{another_host, wrong_ip}});
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::MovedPermanently_301, res->status);
+}
+
+TEST(SpecifyServerIPAddressTest, RealHostname_Online) {
+ auto host = "google.com";
+ auto wrong_ip = "0.0.0.0";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+
+ cli.set_hostname_addr_map({{host, wrong_ip}});
+ auto res = cli.Get("/");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Connection, res.error());
+}
+
+TEST(AbsoluteRedirectTest, Redirect_Online) {
+ auto host = "nghttp2.org";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+
+ cli.set_follow_location(true);
+ auto res = cli.Get("/httpbin/absolute-redirect/3");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(RedirectTest, Redirect_Online) {
+ auto host = "nghttp2.org";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+
+ cli.set_follow_location(true);
+ auto res = cli.Get("/httpbin/redirect/3");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(RelativeRedirectTest, Redirect_Online) {
+ auto host = "nghttp2.org";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+
+ cli.set_follow_location(true);
+ auto res = cli.Get("/httpbin/relative-redirect/3");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(TooManyRedirectTest, Redirect_Online) {
+ auto host = "nghttp2.org";
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+
+ cli.set_follow_location(true);
+ auto res = cli.Get("/httpbin/redirect/21");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::ExceedRedirectCount, res.error());
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(YahooRedirectTest, Redirect_Online) {
+ Client cli("yahoo.com");
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
+
+ cli.set_follow_location(true);
+ res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("https://www.yahoo.com/", res->location);
+}
+
+// Previously "nghttp2.org" "/httpbin/redirect-to"
+#define REDIR_HOST "httpbingo.org"
+#define REDIR_PATH "/redirect-to"
+
+TEST(HttpsToHttpRedirectTest, Redirect_Online) {
+ SSLClient cli(REDIR_HOST);
+ cli.set_follow_location(true);
+ auto res =
+ cli.Get(REDIR_PATH "?url=http%3A%2F%2Fexample.com&status_code=302");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(HttpsToHttpRedirectTest2, Redirect_Online) {
+ SSLClient cli(REDIR_HOST);
+ cli.set_follow_location(true);
+
+ Params params;
+ params.emplace("url", "http://example.com");
+ params.emplace("status_code", "302");
+
+ auto res = cli.Get(REDIR_PATH, params, Headers{});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(HttpsToHttpRedirectTest3, Redirect_Online) {
+ SSLClient cli(REDIR_HOST);
+ cli.set_follow_location(true);
+
+ Params params;
+ params.emplace("url", "http://example.com");
+
+ auto res = cli.Get(REDIR_PATH "?status_code=302", params, Headers{});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(UrlWithSpace, Redirect_Online) {
+ SSLClient cli("edge.forgecdn.net");
+ cli.set_follow_location(true);
+
+ auto res = cli.Get("/files/2595/310/Neat 1.4-17.jar");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(18527U, res->get_header_value_u64("Content-Length"));
+}
+
+#endif
+
+#if !defined(_WIN32) && !defined(_WIN64)
+TEST(ReceiveSignals, Signal) {
+ auto setupSignalHandlers = []() {
+ struct sigaction act;
+
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction = [](int sig, siginfo_t *, void *) {
+ switch (sig) {
+ case SIGINT:
+ default: break;
+ }
+ };
+ ::sigaction(SIGINT, &act, nullptr);
+ };
+
+ Server svr;
+ int port = 0;
+ auto thread = std::thread([&]() {
+ setupSignalHandlers();
+ port = svr.bind_to_any_port("localhost");
+ svr.listen_after_bind();
+ });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ ASSERT_TRUE(svr.is_running());
+ pthread_kill(thread.native_handle(), SIGINT);
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ ASSERT_TRUE(svr.is_running());
+}
+#endif
+
+TEST(RedirectToDifferentPort, Redirect) {
+ Server svr1;
+ svr1.Get("/1", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ int svr1_port = 0;
+ auto thread1 = std::thread([&]() {
+ svr1_port = svr1.bind_to_any_port("localhost");
+ svr1.listen_after_bind();
+ });
+
+ Server svr2;
+ svr2.Get("/2", [&](const Request & /*req*/, Response &res) {
+ res.set_redirect("http://localhost:" + std::to_string(svr1_port) + "/1");
+ });
+
+ int svr2_port = 0;
+ auto thread2 = std::thread([&]() {
+ svr2_port = svr2.bind_to_any_port("localhost");
+ svr2.listen_after_bind();
+ });
+ auto se = detail::scope_exit([&] {
+ svr2.stop();
+ thread2.join();
+ svr1.stop();
+ thread1.join();
+ ASSERT_FALSE(svr2.is_running());
+ ASSERT_FALSE(svr1.is_running());
+ });
+
+ svr1.wait_until_ready();
+ svr2.wait_until_ready();
+
+ Client cli("localhost", svr2_port);
+ cli.set_follow_location(true);
+
+ auto res = cli.Get("/2");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("Hello World!", res->body);
+}
+
+TEST(RedirectFromPageWithContent, Redirect) {
+ Server svr;
+
+ svr.Get("/1", [&](const Request & /*req*/, Response &res) {
+ res.set_content("___", "text/plain");
+ res.set_redirect("/2");
+ });
+
+ svr.Get("/2", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ auto th = std::thread([&]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ th.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli("localhost", PORT);
+ cli.set_follow_location(true);
+
+ std::string body;
+ auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("Hello World!", body);
+ }
+
+ {
+ Client cli("localhost", PORT);
+
+ std::string body;
+ auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Found_302, res->status);
+ EXPECT_EQ("___", body);
+ }
+}
+
+TEST(RedirectFromPageWithContentIP6, Redirect) {
+ Server svr;
+
+ svr.Get("/1", [&](const Request & /*req*/, Response &res) {
+ res.set_content("___", "text/plain");
+ // res.set_redirect("/2");
+ res.set_redirect("http://[::1]:1234/2");
+ });
+
+ svr.Get("/2", [&](const Request &req, Response &res) {
+ auto host_header = req.headers.find("Host");
+ ASSERT_TRUE(host_header != req.headers.end());
+ EXPECT_EQ("[::1]:1234", host_header->second);
+
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ auto th = std::thread([&]() { svr.listen("::1", 1234); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ th.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ // When IPV6 support isn't available svr.listen("::1", 1234) never
+ // actually starts anything, so the condition !svr.is_running() will
+ // always remain true, and the loop never stops.
+ // This basically counts how many milliseconds have passed since the
+ // call to svr.listen(), and if after 5 seconds nothing started yet
+ // aborts the test.
+ for (unsigned int milliseconds = 0; !svr.is_running(); milliseconds++) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ ASSERT_LT(milliseconds, 5000U);
+ }
+
+ {
+ Client cli("http://[::1]:1234");
+ cli.set_follow_location(true);
+
+ std::string body;
+ auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("Hello World!", body);
+ }
+
+ {
+ Client cli("http://[::1]:1234");
+
+ std::string body;
+ auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Found_302, res->status);
+ EXPECT_EQ("___", body);
+ }
+}
+
+TEST(PathUrlEncodeTest, PathUrlEncode) {
+ Server svr;
+
+ svr.Get("/foo", [](const Request &req, Response &res) {
+ auto a = req.params.find("a");
+ if (a != req.params.end()) {
+ res.set_content((*a).second, "text/plain");
+ res.status = StatusCode::OK_200;
+ } else {
+ res.status = StatusCode::BadRequest_400;
+ }
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+ cli.set_path_encode(false);
+
+ auto res = cli.Get("/foo?a=explicitly+encoded");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ // This expects it back with a space, as the `+` won't have been
+ // url-encoded, and server-side the params get decoded turning `+`
+ // into spaces.
+ EXPECT_EQ("explicitly encoded", res->body);
+ }
+}
+
+TEST(PathUrlEncodeTest, IncludePercentEncodingLF) {
+ Server svr;
+
+ svr.Get("/", [](const Request &req, Response &) {
+ EXPECT_EQ("\x0A", req.get_param_value("something"));
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+ cli.set_path_encode(false);
+
+ auto res = cli.Get("/?something=%0A");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+}
+
+TEST(BindServerTest, DISABLED_BindDualStack) {
+ Server svr;
+
+ svr.Get("/1", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ auto thread = std::thread([&]() { svr.listen("::", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli("127.0.0.1", PORT);
+
+ auto res = cli.Get("/1");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("Hello World!", res->body);
+ }
+ {
+ Client cli("::1", PORT);
+
+ auto res = cli.Get("/1");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("Hello World!", res->body);
+ }
+}
+
+TEST(BindServerTest, BindAndListenSeparately) {
+ Server svr;
+ int port = svr.bind_to_any_port("0.0.0.0");
+ ASSERT_TRUE(svr.is_valid());
+ ASSERT_TRUE(port > 0);
+ svr.stop();
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(BindServerTest, BindAndListenSeparatelySSL) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE,
+ CLIENT_CA_CERT_DIR);
+ int port = svr.bind_to_any_port("0.0.0.0");
+ ASSERT_TRUE(svr.is_valid());
+ ASSERT_TRUE(port > 0);
+ svr.stop();
+}
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(BindServerTest, BindAndListenSeparatelySSLEncryptedKey) {
+ SSLServer svr(SERVER_ENCRYPTED_CERT_FILE, SERVER_ENCRYPTED_PRIVATE_KEY_FILE,
+ nullptr, nullptr, SERVER_ENCRYPTED_PRIVATE_KEY_PASS);
+ int port = svr.bind_to_any_port("0.0.0.0");
+ ASSERT_TRUE(svr.is_valid());
+ ASSERT_TRUE(port > 0);
+ svr.stop();
+}
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+X509 *readCertificate(const std::string &strFileName) {
+ std::ifstream inStream(strFileName);
+ std::string strCertPEM((std::istreambuf_iterator<char>(inStream)),
+ std::istreambuf_iterator<char>());
+
+ if (strCertPEM.empty()) return (nullptr);
+
+ BIO *pbCert = BIO_new(BIO_s_mem());
+ BIO_write(pbCert, strCertPEM.c_str(), (int)strCertPEM.size());
+ X509 *pCert = PEM_read_bio_X509(pbCert, NULL, 0, NULL);
+ BIO_free(pbCert);
+
+ return (pCert);
+}
+
+EVP_PKEY *readPrivateKey(const std::string &strFileName) {
+ std::ifstream inStream(strFileName);
+ std::string strPrivateKeyPEM((std::istreambuf_iterator<char>(inStream)),
+ std::istreambuf_iterator<char>());
+
+ if (strPrivateKeyPEM.empty()) return (nullptr);
+
+ BIO *pbPrivKey = BIO_new(BIO_s_mem());
+ BIO_write(pbPrivKey, strPrivateKeyPEM.c_str(), (int)strPrivateKeyPEM.size());
+ EVP_PKEY *pPrivateKey = PEM_read_bio_PrivateKey(pbPrivKey, NULL, NULL, NULL);
+ BIO_free(pbPrivKey);
+
+ return (pPrivateKey);
+}
+
+TEST(BindServerTest, UpdateCerts) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE);
+ int port = svr.bind_to_any_port("0.0.0.0");
+ ASSERT_TRUE(svr.is_valid());
+ ASSERT_TRUE(port > 0);
+
+ X509 *cert = readCertificate(SERVER_CERT_FILE);
+ X509 *ca_cert = readCertificate(CLIENT_CA_CERT_FILE);
+ EVP_PKEY *key = readPrivateKey(SERVER_PRIVATE_KEY_FILE);
+
+ ASSERT_TRUE(cert != nullptr);
+ ASSERT_TRUE(ca_cert != nullptr);
+ ASSERT_TRUE(key != nullptr);
+
+ X509_STORE *cert_store = X509_STORE_new();
+
+ X509_STORE_add_cert(cert_store, ca_cert);
+
+ svr.update_certs(cert, key, cert_store);
+
+ ASSERT_TRUE(svr.is_valid());
+ svr.stop();
+
+ X509_free(cert);
+ X509_free(ca_cert);
+ EVP_PKEY_free(key);
+}
+#endif
+
+TEST(ErrorHandlerTest, ContentLength) {
+ Server svr;
+
+ svr.set_error_handler([](const Request & /*req*/, Response &res) {
+ res.status = StatusCode::OK_200;
+ res.set_content("abcdefghijklmnopqrstuvwxyz",
+ "text/html"); // <= Content-Length still 13
+ });
+
+ svr.Get("/hi", [](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!\n", "text/plain");
+ res.status = 524;
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+
+ auto res = cli.Get("/hi", {{"Accept-Encoding", ""}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("26", res->get_header_value("Content-Length"));
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyz", res->body);
+ }
+}
+
+#ifndef CPPHTTPLIB_NO_EXCEPTIONS
+TEST(ExceptionTest, WithoutExceptionHandler) {
+ Server svr;
+
+ svr.Get("/exception", [&](const Request & /*req*/, Response & /*res*/) {
+ throw std::runtime_error("exception...");
+ });
+
+ svr.Get("/unknown", [&](const Request & /*req*/, Response & /*res*/) {
+ throw std::runtime_error("exception\r\n...");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ {
+ auto res = cli.Get("/exception");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::InternalServerError_500, res->status);
+ ASSERT_TRUE(res->has_header("EXCEPTION_WHAT"));
+ EXPECT_EQ("exception...", res->get_header_value("EXCEPTION_WHAT"));
+ }
+
+ {
+ auto res = cli.Get("/unknown");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::InternalServerError_500, res->status);
+ ASSERT_TRUE(res->has_header("EXCEPTION_WHAT"));
+ EXPECT_EQ("exception\\r\\n...", res->get_header_value("EXCEPTION_WHAT"));
+ }
+}
+
+TEST(ExceptionTest, WithExceptionHandler) {
+ Server svr;
+
+ svr.set_exception_handler([](const Request & /*req*/, Response &res,
+ std::exception_ptr ep) {
+ EXPECT_FALSE(ep == nullptr);
+ try {
+ std::rethrow_exception(ep);
+ } catch (std::exception &e) {
+ EXPECT_EQ("abc", std::string(e.what()));
+ } catch (...) {}
+ res.status = StatusCode::InternalServerError_500;
+ res.set_content("abcdefghijklmnopqrstuvwxyz",
+ "text/html"); // <= Content-Length still 13 at this point
+ });
+
+ svr.Get("/hi", [](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!\n", "text/plain");
+ throw std::runtime_error("abc");
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ for (size_t i = 0; i < 10; i++) {
+ Client cli(HOST, PORT);
+
+ for (size_t j = 0; j < 100; j++) {
+ auto res = cli.Get("/hi", {{"Accept-Encoding", ""}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::InternalServerError_500, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("26", res->get_header_value("Content-Length"));
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyz", res->body);
+ }
+
+ cli.set_keep_alive(true);
+
+ for (size_t j = 0; j < 100; j++) {
+ auto res = cli.Get("/hi", {{"Accept-Encoding", ""}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::InternalServerError_500, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("26", res->get_header_value("Content-Length"));
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyz", res->body);
+ }
+ }
+}
+
+TEST(ExceptionTest, AndErrorHandler) {
+ Server svr;
+
+ svr.set_error_handler([](const Request & /*req*/, Response &res) {
+ if (res.body.empty()) { res.set_content("NOT_FOUND", "text/html"); }
+ });
+
+ svr.set_exception_handler(
+ [](const Request & /*req*/, Response &res, std::exception_ptr ep) {
+ EXPECT_FALSE(ep == nullptr);
+ try {
+ std::rethrow_exception(ep);
+ } catch (std::exception &e) {
+ res.set_content(e.what(), "text/html");
+ } catch (...) {}
+ res.status = StatusCode::InternalServerError_500;
+ });
+
+ svr.Get("/exception", [](const Request & /*req*/, Response & /*res*/) {
+ throw std::runtime_error("EXCEPTION");
+ });
+
+ svr.Get("/error", [](const Request & /*req*/, Response &res) {
+ res.set_content("ERROR", "text/html");
+ res.status = StatusCode::InternalServerError_500;
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+
+ {
+ auto res = cli.Get("/exception");
+ ASSERT_TRUE(res);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("EXCEPTION", res->body);
+ }
+
+ {
+ auto res = cli.Get("/error");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::InternalServerError_500, res->status);
+ EXPECT_EQ("ERROR", res->body);
+ }
+
+ {
+ auto res = cli.Get("/invalid");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+ EXPECT_EQ("NOT_FOUND", res->body);
+ }
+}
+#endif
+
+TEST(NoContentTest, ContentLength) {
+ Server svr;
+
+ svr.Get("/hi", [](const Request & /*req*/, Response &res) {
+ res.status = StatusCode::NoContent_204;
+ });
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+
+ auto res = cli.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NoContent_204, res->status);
+ EXPECT_EQ("0", res->get_header_value("Content-Length"));
+ }
+}
+
+TEST(RoutingHandlerTest, PreAndPostRoutingHandlers) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(svr.is_valid());
+#else
+ Server svr;
+#endif
+
+ svr.set_pre_routing_handler([](const Request &req, Response &res) {
+ if (req.path == "/routing_handler") {
+ res.set_header("PRE_ROUTING", "on");
+ res.set_content("Routing Handler", "text/plain");
+ return httplib::Server::HandlerResponse::Handled;
+ }
+ return httplib::Server::HandlerResponse::Unhandled;
+ });
+
+ svr.set_error_handler([](const Request & /*req*/, Response &res) {
+ res.set_content("Error", "text/html");
+ });
+
+ svr.set_post_routing_handler([](const Request &req, Response &res) {
+ if (req.path == "/routing_handler") {
+ res.set_header("POST_ROUTING", "on");
+ }
+ });
+
+ svr.Get("/hi", [](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!\n", "text/plain");
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(HOST, PORT);
+ cli.enable_server_certificate_verification(false);
+#else
+ Client cli(HOST, PORT);
+#endif
+
+ auto res = cli.Get("/routing_handler");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("Routing Handler", res->body);
+ EXPECT_EQ(1U, res->get_header_value_count("PRE_ROUTING"));
+ EXPECT_EQ("on", res->get_header_value("PRE_ROUTING"));
+ EXPECT_EQ(1U, res->get_header_value_count("POST_ROUTING"));
+ EXPECT_EQ("on", res->get_header_value("POST_ROUTING"));
+ }
+
+ {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(HOST, PORT);
+ cli.enable_server_certificate_verification(false);
+#else
+ Client cli(HOST, PORT);
+#endif
+
+ auto res = cli.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("Hello World!\n", res->body);
+ EXPECT_EQ(0U, res->get_header_value_count("PRE_ROUTING"));
+ EXPECT_EQ(0U, res->get_header_value_count("POST_ROUTING"));
+ }
+
+ {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(HOST, PORT);
+ cli.enable_server_certificate_verification(false);
+#else
+ Client cli(HOST, PORT);
+#endif
+
+ auto res = cli.Get("/aaa");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+ EXPECT_EQ("Error", res->body);
+ EXPECT_EQ(0U, res->get_header_value_count("PRE_ROUTING"));
+ EXPECT_EQ(0U, res->get_header_value_count("POST_ROUTING"));
+ }
+}
+
+TEST(RequestHandlerTest, PreRequestHandler) {
+ auto route_path = "/user/:user";
+
+ Server svr;
+
+ svr.Get("/hi", [](const Request &, Response &res) {
+ res.set_content("hi", "text/plain");
+ });
+
+ svr.Get(route_path, [](const Request &req, Response &res) {
+ res.set_content(req.path_params.at("user"), "text/plain");
+ });
+
+ svr.set_pre_request_handler([&](const Request &req, Response &res) {
+ if (req.matched_route == route_path) {
+ auto user = req.path_params.at("user");
+ if (user != "john") {
+ res.status = StatusCode::Forbidden_403;
+ res.set_content("error", "text/html");
+ return Server::HandlerResponse::Handled;
+ }
+ }
+ return Server::HandlerResponse::Unhandled;
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ {
+ auto res = cli.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("hi", res->body);
+ }
+
+ {
+ auto res = cli.Get("/user/john");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("john", res->body);
+ }
+
+ {
+ auto res = cli.Get("/user/invalid-user");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Forbidden_403, res->status);
+ EXPECT_EQ("error", res->body);
+ }
+}
+
+TEST(InvalidFormatTest, StatusCode) {
+ Server svr;
+
+ svr.Get("/hi", [](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!\n", "text/plain");
+ res.status = 9999; // Status should be a three-digit code...
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+
+ auto res = cli.Get("/hi");
+ ASSERT_FALSE(res);
+ }
+}
+
+TEST(URLFragmentTest, WithFragment) {
+ Server svr;
+
+ svr.Get("/hi", [](const Request &req, Response & /*res*/) {
+ EXPECT_TRUE(req.target == "/hi");
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+
+ auto res = cli.Get("/hi#key1=val1=key2=val2");
+ EXPECT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli.Get("/hi%23key1=val1=key2=val2");
+ EXPECT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+ }
+}
+
+TEST(HeaderWriter, SetHeaderWriter) {
+ Server svr;
+
+ svr.set_header_writer([](Stream &strm, Headers &hdrs) {
+ hdrs.emplace("CustomServerHeader", "CustomServerValue");
+ return detail::write_headers(strm, hdrs);
+ });
+ svr.Get("/hi", [](const Request &req, Response &res) {
+ auto it = req.headers.find("CustomClientHeader");
+ EXPECT_TRUE(it != req.headers.end());
+ EXPECT_EQ(it->second, "CustomClientValue");
+ res.set_content("Hello World!\n", "text/plain");
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+ cli.set_header_writer([](Stream &strm, Headers &hdrs) {
+ hdrs.emplace("CustomClientHeader", "CustomClientValue");
+ return detail::write_headers(strm, hdrs);
+ });
+
+ auto res = cli.Get("/hi");
+ EXPECT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+
+ auto it = res->headers.find("CustomServerHeader");
+ EXPECT_TRUE(it != res->headers.end());
+ EXPECT_EQ(it->second, "CustomServerValue");
+ }
+}
+
+class ServerTest : public ::testing::Test {
+protected:
+ ServerTest()
+ : cli_(HOST, PORT)
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ ,
+ svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
+#endif
+ {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli_.enable_server_certificate_verification(false);
+#endif
+ }
+
+ virtual void SetUp() {
+ svr_.set_mount_point("/", "./www");
+ svr_.set_mount_point("/mount", "./www2");
+ svr_.set_file_extension_and_mimetype_mapping("abcde", "text/abcde");
+
+ svr_.Get("/hi",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ })
+ .Get("/file_content",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_file_content("./www/dir/test.html");
+ })
+ .Get("/file_content_with_content_type",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_file_content("./www/file", "text/plain");
+ })
+ .Get("/invalid_file_content",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_file_content("./www/dir/invalid_file_path");
+ })
+ .Get("/http_response_splitting",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_header("a", "1\r\nSet-Cookie: a=1");
+ EXPECT_EQ(0U, res.headers.size());
+ EXPECT_FALSE(res.has_header("a"));
+
+ res.set_header("a", "1\nSet-Cookie: a=1");
+ EXPECT_EQ(0U, res.headers.size());
+ EXPECT_FALSE(res.has_header("a"));
+
+ res.set_header("a", "1\rSet-Cookie: a=1");
+ EXPECT_EQ(0U, res.headers.size());
+ EXPECT_FALSE(res.has_header("a"));
+
+ res.set_header("a\r\nb", "0");
+ EXPECT_EQ(0U, res.headers.size());
+ EXPECT_FALSE(res.has_header("a"));
+
+ res.set_header("a\rb", "0");
+ EXPECT_EQ(0U, res.headers.size());
+ EXPECT_FALSE(res.has_header("a"));
+
+ res.set_header("a\nb", "0");
+ EXPECT_EQ(0U, res.headers.size());
+ EXPECT_FALSE(res.has_header("a"));
+
+ res.set_redirect("1\r\nSet-Cookie: a=1");
+ EXPECT_EQ(0U, res.headers.size());
+ EXPECT_FALSE(res.has_header("Location"));
+ })
+ .Get("/slow",
+ [&](const Request & /*req*/, Response &res) {
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ res.set_content("slow", "text/plain");
+ })
+#if 0
+ .Post("/slowpost",
+ [&](const Request & /*req*/, Response &res) {
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ res.set_content("slow", "text/plain");
+ })
+#endif
+ .Get("/remote_addr",
+ [&](const Request &req, Response &res) {
+ auto remote_addr = req.headers.find("REMOTE_ADDR")->second;
+ EXPECT_TRUE(req.has_header("REMOTE_PORT"));
+ EXPECT_EQ(req.remote_addr, req.get_header_value("REMOTE_ADDR"));
+ EXPECT_EQ(req.remote_port,
+ std::stoi(req.get_header_value("REMOTE_PORT")));
+ res.set_content(remote_addr.c_str(), "text/plain");
+ })
+ .Get("/local_addr",
+ [&](const Request &req, Response &res) {
+ EXPECT_TRUE(req.has_header("LOCAL_PORT"));
+ EXPECT_TRUE(req.has_header("LOCAL_ADDR"));
+ auto local_addr = req.get_header_value("LOCAL_ADDR");
+ auto local_port = req.get_header_value("LOCAL_PORT");
+ EXPECT_EQ(req.local_addr, local_addr);
+ EXPECT_EQ(req.local_port, std::stoi(local_port));
+ res.set_content(local_addr.append(":").append(local_port),
+ "text/plain");
+ })
+ .Get("/endwith%",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ })
+ .Get("/a\\+\\+b",
+ [&](const Request &req, Response &res) {
+ ASSERT_TRUE(req.has_param("a +b"));
+ auto val = req.get_param_value("a +b");
+ res.set_content(val, "text/plain");
+ })
+ .Get("/", [&](const Request & /*req*/,
+ Response &res) { res.set_redirect("/hi"); })
+ .Post("/1",
+ [](const Request & /*req*/, Response &res) {
+ res.set_redirect("/2", StatusCode::SeeOther_303);
+ })
+ .Get("/2",
+ [](const Request & /*req*/, Response &res) {
+ res.set_content("redirected.", "text/plain");
+ res.status = StatusCode::OK_200;
+ })
+ .Post("/person",
+ [&](const Request &req, Response &res) {
+ if (req.has_param("name") && req.has_param("note")) {
+ persons_[req.get_param_value("name")] =
+ req.get_param_value("note");
+ } else {
+ res.status = StatusCode::BadRequest_400;
+ }
+ })
+ .Put("/person",
+ [&](const Request &req, Response &res) {
+ if (req.has_param("name") && req.has_param("note")) {
+ persons_[req.get_param_value("name")] =
+ req.get_param_value("note");
+ } else {
+ res.status = StatusCode::BadRequest_400;
+ }
+ })
+ .Get("/person/(.*)",
+ [&](const Request &req, Response &res) {
+ string name = req.matches[1];
+ if (persons_.find(name) != persons_.end()) {
+ auto note = persons_[name];
+ res.set_content(note, "text/plain");
+ } else {
+ res.status = StatusCode::NotFound_404;
+ }
+ })
+ .Delete("/person",
+ [&](const Request &req, Response &res) {
+ if (req.has_param("name")) {
+ string name = req.get_param_value("name");
+ if (persons_.find(name) != persons_.end()) {
+ persons_.erase(name);
+ res.set_content("DELETED", "text/plain");
+ } else {
+ res.status = StatusCode::NotFound_404;
+ }
+ } else {
+ res.status = StatusCode::BadRequest_400;
+ }
+ })
+ .Post("/x-www-form-urlencoded-json",
+ [&](const Request &req, Response &res) {
+ auto json = req.get_param_value("json");
+ ASSERT_EQ(JSON_DATA, json);
+ res.set_content(json, "appliation/json");
+ res.status = StatusCode::OK_200;
+ })
+ .Get("/streamed-chunked",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_chunked_content_provider(
+ "text/plain", [](size_t /*offset*/, DataSink &sink) {
+ sink.os << "123";
+ sink.os << "456";
+ sink.os << "789";
+ sink.done();
+ return true;
+ });
+ })
+ .Get("/streamed-chunked2",
+ [&](const Request & /*req*/, Response &res) {
+ auto i = new int(0);
+ res.set_chunked_content_provider(
+ "text/plain",
+ [i](size_t /*offset*/, DataSink &sink) {
+ switch (*i) {
+ case 0: sink.os << "123"; break;
+ case 1: sink.os << "456"; break;
+ case 2: sink.os << "789"; break;
+ case 3: sink.done(); break;
+ }
+ (*i)++;
+ return true;
+ },
+ [i](bool success) {
+ EXPECT_TRUE(success);
+ delete i;
+ });
+ })
+ .Get("/streamed-chunked-with-trailer",
+ [&](const Request & /*req*/, Response &res) {
+ auto i = new int(0);
+ res.set_header("Trailer", "Dummy1, Dummy2");
+ res.set_chunked_content_provider(
+ "text/plain",
+ [i](size_t /*offset*/, DataSink &sink) {
+ switch (*i) {
+ case 0: sink.os << "123"; break;
+ case 1: sink.os << "456"; break;
+ case 2: sink.os << "789"; break;
+ case 3: {
+ sink.done_with_trailer(
+ {{"Dummy1", "DummyVal1"}, {"Dummy2", "DummyVal2"}});
+ } break;
+ }
+ (*i)++;
+ return true;
+ },
+ [i](bool success) {
+ EXPECT_TRUE(success);
+ delete i;
+ });
+ })
+ .Get("/streamed",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content_provider(
+ 6, "text/plain",
+ [](size_t offset, size_t /*length*/, DataSink &sink) {
+ sink.os << (offset < 3 ? "a" : "b");
+ return true;
+ });
+ })
+ .Get("/streamed-with-range",
+ [&](const Request &req, Response &res) {
+ auto data = new std::string("abcdefg");
+ res.set_content_provider(
+ data->size(), "text/plain",
+ [data](size_t offset, size_t length, DataSink &sink) {
+ size_t DATA_CHUNK_SIZE = 4;
+ const auto &d = *data;
+ auto out_len =
+ std::min(static_cast<size_t>(length), DATA_CHUNK_SIZE);
+ auto ret =
+ sink.write(&d[static_cast<size_t>(offset)], out_len);
+ EXPECT_TRUE(ret);
+ return true;
+ },
+ [data, &req](bool success) {
+ EXPECT_EQ(success, !req.has_param("error"));
+ delete data;
+ });
+ })
+ .Get("/streamed-cancel",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content_provider(
+ size_t(-1), "text/plain",
+ [](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ sink.os << "data_chunk";
+ return true;
+ });
+ })
+ .Get("/regex-with-delimiter",
+ [&](const Request &req, Response & /*res*/) {
+ ASSERT_TRUE(req.has_param("key"));
+ EXPECT_EQ("^(?.*(value))", req.get_param_value("key"));
+ })
+ .Get("/with-range",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content("abcdefg", "text/plain");
+ })
+ .Get("/test-start-time",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_NE(req.start_time_,
+ std::chrono::steady_clock::time_point::min());
+ })
+ .Get("/with-range-customized-response",
+ [&](const Request & /*req*/, Response &res) {
+ res.status = StatusCode::BadRequest_400;
+ res.set_content(JSON_DATA, "application/json");
+ })
+ .Post("/chunked",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ(req.body, "dechunked post body");
+ })
+ .Post("/large-chunked",
+ [&](const Request &req, Response & /*res*/) {
+ std::string expected(6 * 30 * 1024u, 'a');
+ EXPECT_EQ(req.body, expected);
+ })
+ .Post("/multipart",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ(4u, req.form.get_field_count("text1") +
+ req.form.get_field_count("text2") +
+ req.form.get_field_count("file3") +
+ req.form.get_field_count("file4"));
+ EXPECT_EQ(2u, req.form.get_file_count("file1") +
+ req.form.get_file_count("file2"));
+ ASSERT_TRUE(!req.form.has_file("???"));
+ ASSERT_TRUE(!req.form.has_field("???"));
+ ASSERT_TRUE(req.body.empty());
+
+ {
+ const auto &text = req.form.get_field("text1");
+ EXPECT_EQ("text default", text);
+ }
+
+ {
+ const auto &text = req.form.get_field("text2");
+ EXPECT_EQ("aωb", text);
+ }
+
+ {
+ const auto &file = req.form.get_file("file1");
+ EXPECT_EQ("hello.txt", file.filename);
+ EXPECT_EQ("text/plain", file.content_type);
+ EXPECT_EQ("h\ne\n\nl\nl\no\n", file.content);
+ }
+
+ {
+ const auto &file = req.form.get_file("file2");
+ EXPECT_EQ("world.json", file.filename);
+ EXPECT_EQ("application/json", file.content_type);
+ EXPECT_EQ("{\n \"world\", true\n}\n", file.content);
+ }
+
+ {
+ const auto &text = req.form.get_field("file3");
+ EXPECT_EQ(0u, text.size());
+ }
+
+ {
+ const auto &text = req.form.get_field("file4");
+ EXPECT_EQ(0u, text.size());
+ }
+ })
+ .Post("/multipart/multi_file_values",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ(3u, req.form.get_field_count("text") +
+ req.form.get_field_count("multi_text1"));
+ EXPECT_EQ(2u, req.form.get_file_count("multi_file1"));
+ ASSERT_TRUE(!req.form.has_file("???"));
+ ASSERT_TRUE(!req.form.has_field("???"));
+ ASSERT_TRUE(req.body.empty());
+
+ {
+ const auto &text = req.form.get_field("text");
+ EXPECT_EQ("default text", text);
+ }
+ {
+ const auto &text1_values = req.form.get_fields("multi_text1");
+ EXPECT_EQ(2u, text1_values.size());
+ EXPECT_EQ("aaaaa", text1_values[0]);
+ EXPECT_EQ("bbbbb", text1_values[1]);
+ }
+
+ {
+ const auto &file1_values = req.form.get_files("multi_file1");
+ EXPECT_EQ(2u, file1_values.size());
+ auto file1 = file1_values[0];
+ EXPECT_EQ(file1.filename, "hello.txt");
+ EXPECT_EQ(file1.content_type, "text/plain");
+ EXPECT_EQ("h\ne\n\nl\nl\no\n", file1.content);
+
+ auto file2 = file1_values[1];
+ EXPECT_EQ(file2.filename, "world.json");
+ EXPECT_EQ(file2.content_type, "application/json");
+ EXPECT_EQ("{\n \"world\", true\n}\n", file2.content);
+ }
+ })
+ .Post("/empty",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, "");
+ EXPECT_EQ("text/plain", req.get_header_value("Content-Type"));
+ EXPECT_EQ("0", req.get_header_value("Content-Length"));
+ res.set_content("empty", "text/plain");
+ })
+ .Post("/empty-no-content-type",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, "");
+ EXPECT_FALSE(req.has_header("Content-Type"));
+ EXPECT_EQ("0", req.get_header_value("Content-Length"));
+ res.set_content("empty-no-content-type", "text/plain");
+ })
+ .Post("/path-only",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, "");
+ EXPECT_EQ("", req.get_header_value("Content-Type"));
+ EXPECT_EQ("0", req.get_header_value("Content-Length"));
+ res.set_content("path-only", "text/plain");
+ })
+ .Post("/path-headers-only",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, "");
+ EXPECT_EQ("", req.get_header_value("Content-Type"));
+ EXPECT_EQ("0", req.get_header_value("Content-Length"));
+ EXPECT_EQ("world", req.get_header_value("hello"));
+ EXPECT_EQ("world2", req.get_header_value("hello2"));
+ res.set_content("path-headers-only", "text/plain");
+ })
+ .Post("/post-large",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, LARGE_DATA);
+ res.set_content(req.body, "text/plain");
+ })
+ .Put("/empty-no-content-type",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, "");
+ EXPECT_FALSE(req.has_header("Content-Type"));
+ EXPECT_EQ("0", req.get_header_value("Content-Length"));
+ res.set_content("empty-no-content-type", "text/plain");
+ })
+ .Put("/put",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, "PUT");
+ res.set_content(req.body, "text/plain");
+ })
+ .Put("/put-large",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, LARGE_DATA);
+ res.set_content(req.body, "text/plain");
+ })
+ .Patch("/patch",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, "PATCH");
+ res.set_content(req.body, "text/plain");
+ })
+ .Delete("/delete",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content("DELETE", "text/plain");
+ })
+ .Delete("/delete-body",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(req.body, "content");
+ res.set_content(req.body, "text/plain");
+ })
+ .Options(R"(\*)",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_header("Allow", "GET, POST, HEAD, OPTIONS");
+ })
+ .Get("/request-target",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ("/request-target?aaa=bbb&ccc=ddd", req.target);
+ EXPECT_EQ("bbb", req.get_param_value("aaa"));
+ EXPECT_EQ("ddd", req.get_param_value("ccc"));
+ })
+ .Get("/long-query-value",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ(LONG_QUERY_URL, req.target);
+ EXPECT_EQ(LONG_QUERY_VALUE, req.get_param_value("key"));
+ })
+ .Get("/too-long-query-value",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ(TOO_LONG_QUERY_URL, req.target);
+ EXPECT_EQ(TOO_LONG_QUERY_VALUE, req.get_param_value("key"));
+ })
+ .Get("/array-param",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ(3u, req.get_param_value_count("array"));
+ EXPECT_EQ("value1", req.get_param_value("array", 0));
+ EXPECT_EQ("value2", req.get_param_value("array", 1));
+ EXPECT_EQ("value3", req.get_param_value("array", 2));
+ })
+ .Post("/validate-no-multiple-headers",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ(1u, req.get_header_value_count("Content-Length"));
+ EXPECT_EQ("5", req.get_header_value("Content-Length"));
+ })
+ .Post("/content_receiver",
+ [&](const Request &req, Response &res,
+ const ContentReader &content_reader) {
+ if (req.is_multipart_form_data()) {
+ std::vector<FormData> items;
+ content_reader(
+ [&](const FormData &file) {
+ items.push_back(file);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ items.back().content.append(data, data_length);
+ return true;
+ });
+
+ EXPECT_EQ(5u, items.size());
+
+ {
+ const auto &file = get_file_value(items, "text1");
+ EXPECT_TRUE(file.filename.empty());
+ EXPECT_EQ("text default", file.content);
+ }
+
+ {
+ const auto &file = get_file_value(items, "text2");
+ EXPECT_TRUE(file.filename.empty());
+ EXPECT_EQ("aωb", file.content);
+ }
+
+ {
+ const auto &file = get_file_value(items, "file1");
+ EXPECT_EQ("hello.txt", file.filename);
+ EXPECT_EQ("text/plain", file.content_type);
+ EXPECT_EQ("h\ne\n\nl\nl\no\n", file.content);
+ }
+
+ {
+ const auto &file = get_file_value(items, "file2");
+ EXPECT_EQ("world.json", file.filename);
+ EXPECT_EQ("application/json", file.content_type);
+ EXPECT_EQ(R"({\n "world": true\n}\n)", file.content);
+ }
+
+ {
+ const auto &file = get_file_value(items, "file3");
+ EXPECT_TRUE(file.filename.empty());
+ EXPECT_EQ("application/octet-stream", file.content_type);
+ EXPECT_EQ(0u, file.content.size());
+ }
+ } else {
+ std::string body;
+ content_reader([&](const char *data, size_t data_length) {
+ EXPECT_EQ(7U, data_length);
+ body.append(data, data_length);
+ return true;
+ });
+ EXPECT_EQ(body, "content");
+ res.set_content(body, "text/plain");
+ }
+ })
+ .Put("/content_receiver",
+ [&](const Request & /*req*/, Response &res,
+ const ContentReader &content_reader) {
+ std::string body;
+ content_reader([&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+ EXPECT_EQ(body, "content");
+ res.set_content(body, "text/plain");
+ })
+ .Patch("/content_receiver",
+ [&](const Request & /*req*/, Response &res,
+ const ContentReader &content_reader) {
+ std::string body;
+ content_reader([&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+ EXPECT_EQ(body, "content");
+ res.set_content(body, "text/plain");
+ })
+ .Post("/query-string-and-body",
+ [&](const Request &req, Response & /*res*/) {
+ ASSERT_TRUE(req.has_param("key"));
+ EXPECT_EQ(req.get_param_value("key"), "value");
+ EXPECT_EQ(req.body, "content");
+ })
+ .Get("/last-request",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ("close", req.get_header_value("Connection"));
+ })
+ .Get(R"(/redirect/(\d+))",
+ [&](const Request &req, Response &res) {
+ auto num = std::stoi(req.matches[1]) + 1;
+ std::string url = "/redirect/" + std::to_string(num);
+ res.set_redirect(url);
+ })
+ .Post("/binary",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(4U, req.body.size());
+ EXPECT_EQ("application/octet-stream",
+ req.get_header_value("Content-Type"));
+ EXPECT_EQ("4", req.get_header_value("Content-Length"));
+ res.set_content(req.body, "application/octet-stream");
+ })
+ .Put("/binary",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(4U, req.body.size());
+ EXPECT_EQ("application/octet-stream",
+ req.get_header_value("Content-Type"));
+ EXPECT_EQ("4", req.get_header_value("Content-Length"));
+ res.set_content(req.body, "application/octet-stream");
+ })
+ .Patch("/binary",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(4U, req.body.size());
+ EXPECT_EQ("application/octet-stream",
+ req.get_header_value("Content-Type"));
+ EXPECT_EQ("4", req.get_header_value("Content-Length"));
+ res.set_content(req.body, "application/octet-stream");
+ })
+ .Delete("/binary",
+ [&](const Request &req, Response &res) {
+ EXPECT_EQ(4U, req.body.size());
+ EXPECT_EQ("application/octet-stream",
+ req.get_header_value("Content-Type"));
+ EXPECT_EQ("4", req.get_header_value("Content-Length"));
+ res.set_content(req.body, "application/octet-stream");
+ })
+ .Get("/issue1772",
+ [&](const Request & /*req*/, Response &res) {
+ res.status = 401;
+ res.set_header("WWW-Authenticate", "Basic realm=123456");
+ })
+ .Delete("/issue609",
+ [](const httplib::Request &, httplib::Response &res,
+ const httplib::ContentReader &) {
+ res.set_content("ok", "text/plain");
+ })
+#if defined(CPPHTTPLIB_ZLIB_SUPPORT) || defined(CPPHTTPLIB_BROTLI_SUPPORT) || \
+ defined(CPPHTTPLIB_ZSTD_SUPPORT)
+ .Get("/compress",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content(
+ "12345678901234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890",
+ "text/plain");
+ })
+ .Get("/nocompress",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content(
+ "12345678901234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890",
+ "application/octet-stream");
+ })
+ .Post("/compress-multipart",
+ [&](const Request &req, Response & /*res*/) {
+ EXPECT_EQ(2u, req.form.fields.size());
+ ASSERT_TRUE(!req.form.has_field("???"));
+
+ {
+ const auto &text = req.form.get_field("key1");
+ EXPECT_EQ("test", text);
+ }
+
+ {
+ const auto &text = req.form.get_field("key2");
+ EXPECT_EQ("--abcdefg123", text);
+ }
+ })
+#endif
+ ;
+
+ persons_["john"] = "programmer";
+
+ t_ = thread([&]() { ASSERT_TRUE(svr_.listen(HOST, PORT)); });
+
+ svr_.wait_until_ready();
+ }
+
+ virtual void TearDown() {
+ svr_.stop();
+ if (!request_threads_.empty()) {
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ for (auto &t : request_threads_) {
+ t.join();
+ }
+ }
+ t_.join();
+ }
+
+ map<string, string> persons_;
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli_;
+ SSLServer svr_;
+#else
+ Client cli_;
+ Server svr_;
+#endif
+ thread t_;
+ std::vector<thread> request_threads_;
+};
+
+TEST_F(ServerTest, GetMethod200) {
+ auto res = cli_.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ("HTTP/1.1", res->version);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("OK", res->reason);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ(1U, res->get_header_value_count("Content-Type"));
+ EXPECT_EQ("Hello World!", res->body);
+}
+
+void performance_test(const char *host) {
+ auto port = 1234;
+
+ Server svr;
+
+ svr.Get("/benchmark", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Benchmark Response", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&]() { svr.listen(host, port); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(host, port);
+
+ auto start = std::chrono::high_resolution_clock::now();
+
+ auto res = cli.Get("/benchmark");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+
+ auto end = std::chrono::high_resolution_clock::now();
+
+ auto elapsed =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
+ .count();
+
+ EXPECT_LE(elapsed, 5) << "Performance is too slow: " << elapsed
+ << "ms (Issue #1777)";
+}
+
+TEST(BenchmarkTest, localhost) { performance_test("localhost"); }
+
+TEST(BenchmarkTest, v6) { performance_test("::1"); }
+
+TEST_F(ServerTest, GetEmptyFile) {
+ auto res = cli_.Get("/empty_file");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("application/octet-stream", res->get_header_value("Content-Type"));
+ EXPECT_EQ(0, std::stoi(res->get_header_value("Content-Length")));
+ EXPECT_EQ("", res->body);
+}
+
+TEST_F(ServerTest, GetFileContent) {
+ auto res = cli_.Get("/file_content");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ(9, std::stoi(res->get_header_value("Content-Length")));
+ EXPECT_EQ("test.html", res->body);
+}
+
+TEST_F(ServerTest, GetFileContentWithRange) {
+ auto res = cli_.Get("/file_content", {{make_range_header({{1, 3}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("bytes 1-3/9", res->get_header_value("Content-Range"));
+ EXPECT_EQ(3, std::stoi(res->get_header_value("Content-Length")));
+ EXPECT_EQ("est", res->body);
+}
+
+TEST_F(ServerTest, GetFileContentWithContentType) {
+ auto res = cli_.Get("/file_content_with_content_type");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ(5, std::stoi(res->get_header_value("Content-Length")));
+ EXPECT_EQ("file\n", res->body);
+}
+
+TEST_F(ServerTest, GetInvalidFileContent) {
+ auto res = cli_.Get("/invalid_file_content");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, GetMethod200withPercentEncoding) {
+ auto res = cli_.Get("/%68%69"); // auto res = cli_.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ("HTTP/1.1", res->version);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ(1U, res->get_header_value_count("Content-Type"));
+ EXPECT_EQ("Hello World!", res->body);
+}
+
+TEST_F(ServerTest, GetMethod302) {
+ auto res = cli_.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Found_302, res->status);
+ EXPECT_EQ("/hi", res->get_header_value("Location"));
+}
+
+TEST_F(ServerTest, GetMethod302Redirect) {
+ cli_.set_follow_location(true);
+ auto res = cli_.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("Hello World!", res->body);
+ EXPECT_EQ("/hi", res->location);
+}
+
+TEST_F(ServerTest, GetMethod404) {
+ auto res = cli_.Get("/invalid");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, HeadMethod200) {
+ auto res = cli_.Head("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_TRUE(res->body.empty());
+}
+
+TEST_F(ServerTest, HeadMethod200Static) {
+ auto res = cli_.Head("/mount/dir/index.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ(104, std::stoi(res->get_header_value("Content-Length")));
+ EXPECT_TRUE(res->body.empty());
+}
+
+TEST_F(ServerTest, HeadMethod404) {
+ auto res = cli_.Head("/invalid");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+ EXPECT_TRUE(res->body.empty());
+}
+
+TEST_F(ServerTest, GetMethodPersonJohn) {
+ auto res = cli_.Get("/person/john");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("programmer", res->body);
+}
+
+TEST_F(ServerTest, PostMethod1) {
+ auto res = cli_.Get("/person/john1");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+
+ res = cli_.Post("/person", "name=john1&note=coder",
+ "application/x-www-form-urlencoded");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli_.Get("/person/john1");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
+ ASSERT_EQ("coder", res->body);
+}
+
+TEST_F(ServerTest, PostMethod2) {
+ auto res = cli_.Get("/person/john2");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+
+ Params params;
+ params.emplace("name", "john2");
+ params.emplace("note", "coder");
+
+ res = cli_.Post("/person", params);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli_.Get("/person/john2");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
+ ASSERT_EQ("coder", res->body);
+}
+
+TEST_F(ServerTest, PutMethod3) {
+ auto res = cli_.Get("/person/john3");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+
+ Params params;
+ params.emplace("name", "john3");
+ params.emplace("note", "coder");
+
+ res = cli_.Put("/person", params);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli_.Get("/person/john3");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
+ ASSERT_EQ("coder", res->body);
+}
+
+TEST_F(ServerTest, DeleteMethod1) {
+ auto res = cli_.Get("/person/john4");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+
+ Params params;
+ params.emplace("name", "john4");
+ params.emplace("note", "coder");
+
+ res = cli_.Post("/person", params);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli_.Get("/person/john4");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
+ ASSERT_EQ("coder", res->body);
+
+ Params delete_params;
+ delete_params.emplace("name", "john4");
+
+ res = cli_.Delete("/person", delete_params);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("DELETED", res->body);
+
+ res = cli_.Get("/person/john4");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, DeleteMethod2) {
+ auto res = cli_.Get("/person/john5");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+
+ Params params;
+ params.emplace("name", "john5");
+ params.emplace("note", "developer");
+
+ res = cli_.Post("/person", params);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli_.Get("/person/john5");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
+ ASSERT_EQ("developer", res->body);
+
+ Params delete_params;
+ delete_params.emplace("name", "john5");
+
+ Headers headers;
+ headers.emplace("Custom-Header", "test-value");
+
+ res = cli_.Delete("/person", headers, delete_params);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("DELETED", res->body);
+
+ res = cli_.Get("/person/john5");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, DeleteMethod3) {
+ auto res = cli_.Get("/person/john6");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+
+ Params params;
+ params.emplace("name", "john6");
+ params.emplace("note", "tester");
+
+ res = cli_.Post("/person", params);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli_.Get("/person/john6");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
+ ASSERT_EQ("tester", res->body);
+
+ Params delete_params;
+ delete_params.emplace("name", "john6");
+
+ Headers headers;
+ headers.emplace("Custom-Header", "test-value");
+
+ res = cli_.Delete("/person", headers, delete_params, nullptr);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("DELETED", res->body);
+
+ res = cli_.Get("/person/john6");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, PostWwwFormUrlEncodedJson) {
+ Params params;
+ params.emplace("json", JSON_DATA);
+
+ auto res = cli_.Post("/x-www-form-urlencoded-json", params);
+
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(JSON_DATA, res->body);
+}
+
+TEST_F(ServerTest, PostEmptyContent) {
+ auto res = cli_.Post("/empty", "", "text/plain");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("empty", res->body);
+}
+
+TEST_F(ServerTest, PostEmptyContentWithNoContentType) {
+ auto res = cli_.Post("/empty-no-content-type");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("empty-no-content-type", res->body);
+}
+
+TEST_F(ServerTest, PostPathOnly) {
+ auto res = cli_.Post("/path-only");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("path-only", res->body);
+}
+
+TEST_F(ServerTest, PostPathAndHeadersOnly) {
+ auto res = cli_.Post("/path-headers-only",
+ Headers({{"hello", "world"}, {"hello2", "world2"}}));
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("path-headers-only", res->body);
+}
+
+TEST_F(ServerTest, PostLarge) {
+ auto res = cli_.Post("/post-large", LARGE_DATA, "text/plain");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(LARGE_DATA, res->body);
+}
+
+TEST_F(ServerTest, PutEmptyContentWithNoContentType) {
+ auto res = cli_.Put("/empty-no-content-type");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("empty-no-content-type", res->body);
+}
+
+TEST_F(ServerTest, GetMethodDir) {
+ auto res = cli_.Get("/dir/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+
+ auto body = R"(<html>
+<head>
+</head>
+<body>
+ <a href="/dir/test.html">Test</a>
+ <a href="/hi">hi</a>
+</body>
+</html>
+)";
+ EXPECT_EQ(body, res->body);
+}
+
+TEST_F(ServerTest, GetMethodDirTest) {
+ auto res = cli_.Get("/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("test.html", res->body);
+}
+
+TEST_F(ServerTest, GetMethodDirTestWithDoubleDots) {
+ auto res = cli_.Get("/dir/../dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("test.html", res->body);
+}
+
+TEST_F(ServerTest, GetMethodInvalidPath) {
+ auto res = cli_.Get("/dir/../test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, GetMethodOutOfBaseDir) {
+ auto res = cli_.Get("/../www/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, GetMethodOutOfBaseDir2) {
+ auto res = cli_.Get("/dir/../../www/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, GetMethodDirMountTest) {
+ auto res = cli_.Get("/mount/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("test.html", res->body);
+}
+
+TEST_F(ServerTest, GetMethodDirMountTestWithDoubleDots) {
+ auto res = cli_.Get("/mount/dir/../dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
+ EXPECT_EQ("test.html", res->body);
+}
+
+TEST_F(ServerTest, GetMethodInvalidMountPath) {
+ auto res = cli_.Get("/mount/dir/../test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, GetMethodEmbeddedNUL) {
+ auto res = cli_.Get("/mount/dir/test.html%00.js");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, GetMethodOutOfBaseDirMount) {
+ auto res = cli_.Get("/mount/../www2/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, GetMethodOutOfBaseDirMount2) {
+ auto res = cli_.Get("/mount/dir/../../www2/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, GetMethodOutOfBaseDirMountWithBackslash) {
+ auto res = cli_.Get("/mount/%2e%2e%5c/www2/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, PostMethod303) {
+ auto res = cli_.Post("/1", "body", "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::SeeOther_303, res->status);
+ EXPECT_EQ("/2", res->get_header_value("Location"));
+}
+
+TEST_F(ServerTest, PostMethod303Redirect) {
+ cli_.set_follow_location(true);
+ auto res = cli_.Post("/1", "body", "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("redirected.", res->body);
+ EXPECT_EQ("/2", res->location);
+}
+
+TEST_F(ServerTest, UserDefinedMIMETypeMapping) {
+ auto res = cli_.Get("/dir/test.abcde");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
+ EXPECT_EQ("abcde", res->body);
+}
+
+TEST_F(ServerTest, StaticFileRange) {
+ auto res = cli_.Get("/dir/test.abcde", {{make_range_header({{2, 3}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
+ EXPECT_EQ("2", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 2-3/5", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("cd"), res->body);
+}
+
+TEST_F(ServerTest, StaticFileRanges) {
+ auto res =
+ cli_.Get("/dir/test.abcde", {{make_range_header({{1, 2}, {4, -1}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_TRUE(
+ res->get_header_value("Content-Type")
+ .find(
+ "multipart/byteranges; boundary=--cpp-httplib-multipart-data-") ==
+ 0);
+ EXPECT_EQ("266", res->get_header_value("Content-Length"));
+}
+
+TEST_F(ServerTest, StaticFileRangeHead) {
+ auto res = cli_.Head("/dir/test.abcde", {{make_range_header({{2, 3}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
+ EXPECT_EQ("2", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 2-3/5", res->get_header_value("Content-Range"));
+}
+
+TEST_F(ServerTest, StaticFileRangeBigFile) {
+ auto res = cli_.Get("/dir/1MB.txt", {{make_range_header({{-1, 5}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("5", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 1048571-1048575/1048576",
+ res->get_header_value("Content-Range"));
+ EXPECT_EQ("LAST\n", res->body);
+}
+
+TEST_F(ServerTest, StaticFileRangeBigFile2) {
+ auto res = cli_.Get("/dir/1MB.txt", {{make_range_header({{1, 4097}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("4097", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 1-4097/1048576", res->get_header_value("Content-Range"));
+}
+
+TEST_F(ServerTest, StaticFileBigFile) {
+ auto res = cli_.Get("/dir/1MB.txt");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("1048576", res->get_header_value("Content-Length"));
+}
+
+TEST_F(ServerTest, InvalidBaseDirMount) {
+ EXPECT_EQ(false, svr_.set_mount_point("invalid_mount_point", "./www3"));
+}
+
+TEST_F(ServerTest, Binary) {
+ std::vector<char> binary{0x00, 0x01, 0x02, 0x03};
+
+ auto res = cli_.Post("/binary", binary.data(), binary.size(),
+ "application/octet-stream");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(4U, res->body.size());
+
+ res = cli_.Put("/binary", binary.data(), binary.size(),
+ "application/octet-stream");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(4U, res->body.size());
+
+ res = cli_.Patch("/binary", binary.data(), binary.size(),
+ "application/octet-stream");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(4U, res->body.size());
+
+ res = cli_.Delete("/binary", binary.data(), binary.size(),
+ "application/octet-stream");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(4U, res->body.size());
+}
+
+TEST_F(ServerTest, BinaryString) {
+ auto binary = std::string("\x00\x01\x02\x03", 4);
+
+ auto res = cli_.Post("/binary", binary, "application/octet-stream");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(4U, res->body.size());
+
+ res = cli_.Put("/binary", binary, "application/octet-stream");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(4U, res->body.size());
+
+ res = cli_.Patch("/binary", binary, "application/octet-stream");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(4U, res->body.size());
+
+ res = cli_.Delete("/binary", binary, "application/octet-stream");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(4U, res->body.size());
+}
+
+TEST_F(ServerTest, EmptyRequest) {
+ auto res = cli_.Get("");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Connection, res.error());
+}
+
+TEST_F(ServerTest, LongRequest) {
+ std::string request;
+ for (size_t i = 0; i < 545; i++) {
+ request += "/TooLongRequest";
+ }
+ request += "OK";
+
+ auto res = cli_.Get(request.c_str());
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, TooLongRequest) {
+ std::string request;
+ for (size_t i = 0; i < 546; i++) {
+ request += "/TooLongRequest";
+ }
+ request += "_NG";
+
+ auto res = cli_.Get(request.c_str());
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::UriTooLong_414, res->status);
+}
+
+TEST_F(ServerTest, AlmostTooLongRequest) {
+ // test for #2046 - URI length check shouldn't include other content on req
+ // line URI is max URI length, minus 14 other chars in req line (GET, space,
+ // leading /, space, HTTP/1.1)
+ std::string request =
+ "/" + string(CPPHTTPLIB_REQUEST_URI_MAX_LENGTH - 14, 'A');
+
+ auto res = cli_.Get(request.c_str());
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, LongHeader) {
+ Request req;
+ req.method = "GET";
+ req.path = "/hi";
+
+ std::string host_and_port;
+ host_and_port += HOST;
+ host_and_port += ":";
+ host_and_port += std::to_string(PORT);
+
+ req.headers.emplace("Host", host_and_port.c_str());
+ req.headers.emplace("Accept", "*/*");
+ req.headers.emplace("User-Agent", "cpp-httplib/0.1");
+
+ req.headers.emplace(
+ "Header-Name",
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@");
+
+ auto res = std::make_shared<Response>();
+ auto error = Error::Success;
+ auto ret = cli_.send(req, *res, error);
+
+ ASSERT_TRUE(ret);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, LongQueryValue) {
+ auto res = cli_.Get(LONG_QUERY_URL.c_str());
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::UriTooLong_414, res->status);
+}
+
+TEST_F(ServerTest, TooLongQueryValue) {
+ auto res = cli_.Get(TOO_LONG_QUERY_URL.c_str());
+
+ ASSERT_FALSE(res);
+ EXPECT_EQ(Error::Read, res.error());
+}
+
+TEST_F(ServerTest, TooLongHeader) {
+ Request req;
+ req.method = "GET";
+ req.path = "/hi";
+
+ std::string host_and_port;
+ host_and_port += HOST;
+ host_and_port += ":";
+ host_and_port += std::to_string(PORT);
+
+ req.headers.emplace("Host", host_and_port.c_str());
+ req.headers.emplace("Accept", "*/*");
+ req.headers.emplace("User-Agent", "cpp-httplib/0.1");
+
+ req.headers.emplace(
+ "Header-Name",
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@@@@@@@@@@@@");
+
+ auto res = std::make_shared<Response>();
+ auto error = Error::Success;
+ auto ret = cli_.send(req, *res, error);
+
+ ASSERT_TRUE(ret);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, HeaderCountAtLimit) {
+ // Test with headers just under the 100 limit
+ httplib::Headers headers;
+
+ // Add 95 custom headers (the client will add Host, User-Agent, Accept, etc.)
+ // This should keep us just under the 100 header limit
+ for (int i = 0; i < 95; i++) {
+ std::string name = "X-Test-Header-" + std::to_string(i);
+ std::string value = "value" + std::to_string(i);
+ headers.emplace(name, value);
+ }
+
+ // This should work fine as we're under the limit
+ auto res = cli_.Get("/hi", headers);
+ EXPECT_TRUE(res);
+ if (res) { EXPECT_EQ(StatusCode::OK_200, res->status); }
+}
+
+TEST_F(ServerTest, HeaderCountExceedsLimit) {
+ // Test with many headers to exceed the 100 limit
+ httplib::Headers headers;
+
+ // Add 150 headers to definitely exceed the 100 limit
+ for (int i = 0; i < 150; i++) {
+ std::string name = "X-Test-Header-" + std::to_string(i);
+ std::string value = "value" + std::to_string(i);
+ headers.emplace(name, value);
+ }
+
+ // This should fail due to exceeding header count limit
+ auto res = cli_.Get("/hi", headers);
+
+ // The request should either fail or return 400 Bad Request
+ if (res) {
+ // If we get a response, it should be 400 Bad Request
+ EXPECT_EQ(StatusCode::BadRequest_400, res->status);
+ } else {
+ // Or the request should fail entirely
+ EXPECT_FALSE(res);
+ }
+}
+
+TEST_F(ServerTest, PercentEncoding) {
+ auto res = cli_.Get("/e%6edwith%");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, PercentEncodingUnicode) {
+ auto res = cli_.Get("/e%u006edwith%");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, InvalidPercentEncoding) {
+ auto res = cli_.Get("/%endwith%");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, InvalidPercentEncodingUnicode) {
+ auto res = cli_.Get("/%uendwith%");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, EndWithPercentCharacterInQuery) {
+ auto res = cli_.Get("/hello?aaa=bbb%");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST_F(ServerTest, PlusSignEncoding) {
+ auto res = cli_.Get("/a+%2Bb?a %2bb=a %2Bb");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("a +b", res->body);
+}
+
+TEST_F(ServerTest, HeaderCountSecurityTest) {
+ // This test simulates a potential DoS attack using many headers
+ // to verify our security fix prevents memory exhaustion
+
+ httplib::Headers attack_headers;
+
+ // Attempt to add many headers like an attacker would (200 headers to far
+ // exceed limit)
+ for (int i = 0; i < 200; i++) {
+ std::string name = "X-Attack-Header-" + std::to_string(i);
+ std::string value = "attack_payload_" + std::to_string(i);
+ attack_headers.emplace(name, value);
+ }
+
+ // Try to POST with excessive headers
+ auto res = cli_.Post("/", attack_headers, "test_data", "text/plain");
+
+ // Should either fail or return 400 Bad Request due to security limit
+ if (res) {
+ // If we get a response, it should be 400 Bad Request
+ EXPECT_EQ(StatusCode::BadRequest_400, res->status);
+ } else {
+ // Request failed, which is the expected behavior for DoS protection
+ EXPECT_FALSE(res);
+ }
+}
+
+TEST_F(ServerTest, MultipartFormData) {
+ UploadFormDataItems items = {
+ {"text1", "text default", "", ""},
+ {"text2", "aωb", "", ""},
+ {"file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain"},
+ {"file2", "{\n \"world\", true\n}\n", "world.json", "application/json"},
+ {"file3", "", "", "application/octet-stream"},
+ {"file4", "", "", " application/json tmp-string "}};
+
+ auto res = cli_.Post("/multipart", items);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, MultipartFormDataMultiFileValues) {
+ UploadFormDataItems items = {
+ {"text", "default text", "", ""},
+
+ {"multi_text1", "aaaaa", "", ""},
+ {"multi_text1", "bbbbb", "", ""},
+
+ {"multi_file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain"},
+ {"multi_file1", "{\n \"world\", true\n}\n", "world.json",
+ "application/json"},
+ };
+
+ auto res = cli_.Post("/multipart/multi_file_values", items);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, CaseInsensitiveHeaderName) {
+ auto res = cli_.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("content-type"));
+ EXPECT_EQ("Hello World!", res->body);
+}
+
+TEST_F(ServerTest, CaseInsensitiveTransferEncoding) {
+ Request req;
+ req.method = "POST";
+ req.path = "/chunked";
+
+ std::string host_and_port;
+ host_and_port += HOST;
+ host_and_port += ":";
+ host_and_port += std::to_string(PORT);
+
+ req.headers.emplace("Host", host_and_port.c_str());
+ req.headers.emplace("Accept", "*/*");
+ req.headers.emplace("User-Agent", "cpp-httplib/0.1");
+ req.headers.emplace("Content-Type", "text/plain");
+ req.headers.emplace("Content-Length", "0");
+ req.headers.emplace(
+ "Transfer-Encoding",
+ "Chunked"); // Note, "Chunked" rather than typical "chunked".
+
+ // Client does not chunk, so make a chunked body manually.
+ req.body = "4\r\ndech\r\nf\r\nunked post body\r\n0\r\n\r\n";
+
+ auto res = std::make_shared<Response>();
+ auto error = Error::Success;
+ auto ret = cli_.send(req, *res, error);
+
+ ASSERT_TRUE(ret);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, GetStreamed2) {
+ auto res = cli_.Get("/streamed", {{make_range_header({{2, 3}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("2", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 2-3/6", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("ab"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamed) {
+ auto res = cli_.Get("/streamed");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("6", res->get_header_value("Content-Length"));
+ EXPECT_EQ(std::string("aaabbb"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedWithRange1) {
+ auto res = cli_.Get("/streamed-with-range", {{make_range_header({{3, 5}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("3", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 3-5/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("def"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedWithRange2) {
+ auto res = cli_.Get("/streamed-with-range", {{make_range_header({{1, -1}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("6", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 1-6/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("bcdefg"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedWithRangeSuffix1) {
+ auto res = cli_.Get("/streamed-with-range", {{"Range", "bytes=-3"}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("3", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 4-6/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("efg"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedWithRangeSuffix2) {
+ auto res = cli_.Get("/streamed-with-range?error", {{"Range", "bytes=-9999"}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status);
+ EXPECT_EQ("0", res->get_header_value("Content-Length"));
+ EXPECT_EQ(false, res->has_header("Content-Range"));
+ EXPECT_EQ(0U, res->body.size());
+}
+
+TEST_F(ServerTest, GetStreamedWithRangeError) {
+ auto res = cli_.Get("/streamed-with-range",
+ {{"Range", "bytes=92233720368547758079223372036854775806-"
+ "92233720368547758079223372036854775807"}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status);
+ EXPECT_EQ("0", res->get_header_value("Content-Length"));
+ EXPECT_EQ(false, res->has_header("Content-Range"));
+ EXPECT_EQ(0U, res->body.size());
+}
+
+TEST_F(ServerTest, GetRangeWithMaxLongLength) {
+ auto res = cli_.Get(
+ "/with-range",
+ {{"Range", "bytes=0-" + std::to_string(std::numeric_limits<long>::max())},
+ {"Accept-Encoding", ""}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("7", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 0-6/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("abcdefg"), res->body);
+}
+
+TEST_F(ServerTest, GetRangeWithZeroToInfinite) {
+ auto res = cli_.Get("/with-range", {
+ {"Range", "bytes=0-"},
+ {"Accept-Encoding", ""},
+ });
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("7", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 0-6/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("abcdefg"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedWithRangeMultipart) {
+ auto res =
+ cli_.Get("/streamed-with-range", {{make_range_header({{1, 2}, {4, 5}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("267", res->get_header_value("Content-Length"));
+ EXPECT_EQ(false, res->has_header("Content-Range"));
+ EXPECT_EQ(267U, res->body.size());
+
+ // Check that both range contents are present
+ EXPECT_TRUE(res->body.find("bc\r\n") != std::string::npos);
+ EXPECT_TRUE(res->body.find("ef\r\n") != std::string::npos);
+
+ // Check that Content-Range headers are present for both ranges
+ EXPECT_TRUE(res->body.find("Content-Range: bytes 1-2/7") !=
+ std::string::npos);
+ EXPECT_TRUE(res->body.find("Content-Range: bytes 4-5/7") !=
+ std::string::npos);
+}
+
+TEST_F(ServerTest, GetStreamedWithTooManyRanges) {
+ Ranges ranges;
+ for (size_t i = 0; i < CPPHTTPLIB_RANGE_MAX_COUNT + 1; i++) {
+ ranges.emplace_back(0, -1);
+ }
+
+ auto res =
+ cli_.Get("/streamed-with-range?error", {{make_range_header(ranges)}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status);
+ EXPECT_EQ("0", res->get_header_value("Content-Length"));
+ EXPECT_EQ(false, res->has_header("Content-Range"));
+ EXPECT_EQ(0U, res->body.size());
+}
+
+TEST_F(ServerTest, GetStreamedWithOverwrapping) {
+ auto res =
+ cli_.Get("/streamed-with-range", {{make_range_header({{1, 4}, {2, 5}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ(5U, res->body.size());
+
+ // Check that overlapping ranges are coalesced into a single range
+ EXPECT_EQ("bcdef", res->body);
+ EXPECT_EQ("bytes 1-5/7", res->get_header_value("Content-Range"));
+
+ // Should be single range, not multipart
+ EXPECT_TRUE(res->has_header("Content-Range"));
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+}
+
+TEST_F(ServerTest, GetStreamedWithNonAscendingRanges) {
+ auto res =
+ cli_.Get("/streamed-with-range", {{make_range_header({{4, 5}, {0, 2}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ(268U, res->body.size());
+
+ // Check that both range contents are present
+ EXPECT_TRUE(res->body.find("ef\r\n") != std::string::npos);
+ EXPECT_TRUE(res->body.find("abc\r\n") != std::string::npos);
+
+ // Check that Content-Range headers are present for both ranges
+ EXPECT_TRUE(res->body.find("Content-Range: bytes 4-5/7") !=
+ std::string::npos);
+ EXPECT_TRUE(res->body.find("Content-Range: bytes 0-2/7") !=
+ std::string::npos);
+}
+
+TEST_F(ServerTest, GetStreamedWithDuplicateRanges) {
+ auto res =
+ cli_.Get("/streamed-with-range", {{make_range_header({{0, 2}, {0, 2}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ(269U, res->body.size());
+
+ // Check that both duplicate range contents are present
+ size_t first_abc = res->body.find("abc\r\n");
+ EXPECT_TRUE(first_abc != std::string::npos);
+ size_t second_abc = res->body.find("abc\r\n", first_abc + 1);
+ EXPECT_TRUE(second_abc != std::string::npos);
+
+ // Check that Content-Range headers are present for both ranges
+ size_t first_range = res->body.find("Content-Range: bytes 0-2/7");
+ EXPECT_TRUE(first_range != std::string::npos);
+ size_t second_range =
+ res->body.find("Content-Range: bytes 0-2/7", first_range + 1);
+ EXPECT_TRUE(second_range != std::string::npos);
+}
+
+TEST_F(ServerTest, GetStreamedWithRangesMoreThanTwoOverwrapping) {
+ auto res = cli_.Get("/streamed-with-range?error",
+ {{make_range_header({{0, 1}, {1, 2}, {2, 3}, {3, 4}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status);
+ EXPECT_EQ("0", res->get_header_value("Content-Length"));
+ EXPECT_EQ(false, res->has_header("Content-Range"));
+ EXPECT_EQ(0U, res->body.size());
+}
+
+TEST_F(ServerTest, GetStreamedEndless) {
+ uint64_t offset = 0;
+ auto res = cli_.Get("/streamed-cancel",
+ [&](const char * /*data*/, uint64_t data_length) {
+ if (offset < 100) {
+ offset += data_length;
+ return true;
+ }
+ return false;
+ });
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST_F(ServerTest, ClientStop) {
+ std::atomic_size_t count{4};
+ std::vector<std::thread> threads;
+
+ for (auto i = count.load(); i != 0; --i) {
+ threads.emplace_back([&]() {
+ auto res = cli_.Get("/streamed-cancel",
+ [&](const char *, uint64_t) { return true; });
+
+ --count;
+
+ ASSERT_TRUE(!res);
+ EXPECT_TRUE(res.error() == Error::Canceled ||
+ res.error() == Error::Read || res.error() == Error::Write);
+ });
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ while (count != 0) {
+ cli_.stop();
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ for (auto &t : threads) {
+ t.join();
+ }
+}
+
+TEST_F(ServerTest, GetWithRange1) {
+ auto res = cli_.Get("/with-range", {
+ make_range_header({{3, 5}}),
+ {"Accept-Encoding", ""},
+ });
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("3", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 3-5/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("def"), res->body);
+}
+
+TEST_F(ServerTest, GetWithRange2) {
+ auto res = cli_.Get("/with-range", {
+ make_range_header({{1, -1}}),
+ {"Accept-Encoding", ""},
+ });
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("6", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 1-6/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("bcdefg"), res->body);
+}
+
+TEST_F(ServerTest, GetWithRange3) {
+ auto res = cli_.Get("/with-range", {
+ make_range_header({{0, 0}}),
+ {"Accept-Encoding", ""},
+ });
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("1", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 0-0/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("a"), res->body);
+}
+
+TEST_F(ServerTest, GetWithRange4) {
+ auto res = cli_.Get("/with-range", {
+ make_range_header({{-1, 2}}),
+ {"Accept-Encoding", ""},
+ });
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("2", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 5-6/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("fg"), res->body);
+}
+
+TEST_F(ServerTest, GetWithRange5) {
+ auto res = cli_.Get("/with-range", {
+ make_range_header({{0, 5}}),
+ {"Accept-Encoding", ""},
+ });
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("6", res->get_header_value("Content-Length"));
+ EXPECT_EQ(true, res->has_header("Content-Range"));
+ EXPECT_EQ("bytes 0-5/7", res->get_header_value("Content-Range"));
+ EXPECT_EQ(std::string("abcdef"), res->body);
+}
+
+TEST_F(ServerTest, GetWithRangeOffsetGreaterThanContent) {
+ auto res = cli_.Get("/with-range", {{make_range_header({{10000, 20000}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status);
+}
+
+TEST_F(ServerTest, GetWithRangeMultipart) {
+ auto res = cli_.Get("/with-range", {{make_range_header({{1, 2}, {4, 5}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ EXPECT_EQ("267", res->get_header_value("Content-Length"));
+ EXPECT_EQ(false, res->has_header("Content-Range"));
+ EXPECT_EQ(267U, res->body.size());
+}
+
+TEST_F(ServerTest, GetWithRangeMultipartOffsetGreaterThanContent) {
+ auto res =
+ cli_.Get("/with-range", {{make_range_header({{-1, 2}, {10000, 30000}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status);
+}
+
+TEST_F(ServerTest, GetWithRangeCustomizedResponse) {
+ auto res = cli_.Get("/with-range-customized-response",
+ {{make_range_header({{1, 2}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::BadRequest_400, res->status);
+ EXPECT_EQ(true, res->has_header("Content-Length"));
+ EXPECT_EQ(false, res->has_header("Content-Range"));
+ EXPECT_EQ(JSON_DATA, res->body);
+}
+
+TEST_F(ServerTest, GetWithRangeMultipartCustomizedResponseMultipleRange) {
+ auto res = cli_.Get("/with-range-customized-response",
+ {{make_range_header({{1, 2}, {4, 5}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::BadRequest_400, res->status);
+ EXPECT_EQ(true, res->has_header("Content-Length"));
+ EXPECT_EQ(false, res->has_header("Content-Range"));
+ EXPECT_EQ(JSON_DATA, res->body);
+}
+
+TEST_F(ServerTest, Issue1772) {
+ auto res = cli_.Get("/issue1772", {{make_range_header({{1000, -1}})}});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+}
+
+TEST_F(ServerTest, Issue609) {
+ auto res = cli_.Delete("/issue609");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(std::string("ok"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedChunked) {
+ auto res = cli_.Get("/streamed-chunked");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(std::string("123456789"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedChunked2) {
+ auto res = cli_.Get("/streamed-chunked2");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(std::string("123456789"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedChunkedWithTrailer) {
+ auto res = cli_.Get("/streamed-chunked-with-trailer");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(std::string("123456789"), res->body);
+
+ EXPECT_TRUE(res->has_header("Trailer"));
+ EXPECT_EQ(1U, res->get_header_value_count("Trailer"));
+ EXPECT_EQ(std::string("Dummy1, Dummy2"), res->get_header_value("Trailer"));
+
+ // Trailers are now stored separately from headers (security fix)
+ EXPECT_EQ(2U, res->trailers.size());
+ EXPECT_TRUE(res->has_trailer("Dummy1"));
+ EXPECT_TRUE(res->has_trailer("Dummy2"));
+ EXPECT_FALSE(res->has_trailer("Dummy3"));
+ EXPECT_EQ(std::string("DummyVal1"), res->get_trailer_value("Dummy1"));
+ EXPECT_EQ(std::string("DummyVal2"), res->get_trailer_value("Dummy2"));
+
+ // Verify trailers are NOT in headers (security verification)
+ EXPECT_EQ(std::string(""), res->get_header_value("Dummy1"));
+ EXPECT_EQ(std::string(""), res->get_header_value("Dummy2"));
+}
+
+TEST_F(ServerTest, LargeChunkedPost) {
+ Request req;
+ req.method = "POST";
+ req.path = "/large-chunked";
+
+ std::string host_and_port;
+ host_and_port += HOST;
+ host_and_port += ":";
+ host_and_port += std::to_string(PORT);
+
+ req.headers.emplace("Host", host_and_port.c_str());
+ req.headers.emplace("Accept", "*/*");
+ req.headers.emplace("User-Agent", "cpp-httplib/0.1");
+ req.headers.emplace("Content-Type", "text/plain");
+ req.headers.emplace("Content-Length", "0");
+ req.headers.emplace("Transfer-Encoding", "chunked");
+
+ std::string long_string(30 * 1024u, 'a');
+ std::string chunk = "7800\r\n" + long_string + "\r\n";
+
+ // Attempt to make a large enough post to exceed OS buffers, to test that
+ // the server handles short reads if the full chunk data isn't available.
+ req.body = chunk + chunk + chunk + chunk + chunk + chunk + "0\r\n\r\n";
+
+ auto res = std::make_shared<Response>();
+ auto error = Error::Success;
+ auto ret = cli_.send(req, *res, error);
+
+ ASSERT_TRUE(ret);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, GetMethodRemoteAddr) {
+ auto res = cli_.Get("/remote_addr");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_TRUE(res->body == "::1" || res->body == "127.0.0.1");
+}
+
+TEST_F(ServerTest, GetMethodLocalAddr) {
+ auto res = cli_.Get("/local_addr");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_TRUE(res->body == std::string("::1:").append(to_string(PORT)) ||
+ res->body == std::string("127.0.0.1:").append(to_string(PORT)));
+}
+
+TEST_F(ServerTest, HTTPResponseSplitting) {
+ auto res = cli_.Get("/http_response_splitting");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, SlowRequest) {
+ request_threads_.emplace_back([this]() { auto res = cli_.Get("/slow"); });
+ request_threads_.emplace_back([this]() { auto res = cli_.Get("/slow"); });
+ request_threads_.emplace_back([this]() { auto res = cli_.Get("/slow"); });
+}
+
+#if 0
+TEST_F(ServerTest, SlowPost) {
+ char buffer[64 * 1024];
+ memset(buffer, 0x42, sizeof(buffer));
+
+ auto res = cli_.Post(
+ "/slowpost", 64 * 1024 * 1024,
+ [&](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ auto ret = sink.write(buffer, sizeof(buffer));
+ EXPECT_TRUE(ret);
+ return true;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, SlowPostFail) {
+ char buffer[64 * 1024];
+ memset(buffer, 0x42, sizeof(buffer));
+
+ cli_.set_write_timeout(std::chrono::seconds(0));
+ auto res = cli_.Post(
+ "/slowpost", 64 * 1024 * 1024,
+ [&](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ sink.write(buffer, sizeof(buffer));
+ return true;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Write, res.error());
+}
+#endif
+
+TEST_F(ServerTest, Put) {
+ auto res = cli_.Put("/put", "PUT", "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("PUT", res->body);
+}
+
+TEST_F(ServerTest, PutWithContentProvider) {
+ auto res = cli_.Put(
+ "/put", 3,
+ [](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ sink.os << "PUT";
+ return true;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("PUT", res->body);
+}
+
+TEST_F(ServerTest, PostWithContentProviderAbort) {
+ auto res = cli_.Post(
+ "/post", 42,
+ [](size_t /*offset*/, size_t /*length*/, DataSink & /*sink*/) {
+ return false;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST_F(ServerTest, PutWithContentProviderWithoutLength) {
+ auto res = cli_.Put(
+ "/put",
+ [](size_t /*offset*/, DataSink &sink) {
+ sink.os << "PUT";
+ sink.done();
+ return true;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("PUT", res->body);
+}
+
+TEST_F(ServerTest, PostWithContentProviderWithoutLengthAbort) {
+ auto res = cli_.Post(
+ "/post", [](size_t /*offset*/, DataSink & /*sink*/) { return false; },
+ "text/plain");
+
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+#ifdef CPPHTTPLIB_ZLIB_SUPPORT
+TEST_F(ServerTest, PutWithContentProviderWithGzip) {
+ cli_.set_compress(true);
+ auto res = cli_.Put(
+ "/put", 3,
+ [](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ sink.os << "PUT";
+ return true;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("PUT", res->body);
+}
+
+TEST_F(ServerTest, PostWithContentProviderWithGzipAbort) {
+ cli_.set_compress(true);
+ auto res = cli_.Post(
+ "/post", 42,
+ [](size_t /*offset*/, size_t /*length*/, DataSink & /*sink*/) {
+ return false;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST_F(ServerTest, PutWithContentProviderWithoutLengthWithGzip) {
+ cli_.set_compress(true);
+ auto res = cli_.Put(
+ "/put",
+ [](size_t /*offset*/, DataSink &sink) {
+ sink.os << "PUT";
+ sink.done();
+ return true;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("PUT", res->body);
+}
+
+TEST_F(ServerTest, PostWithContentProviderWithoutLengthWithGzipAbort) {
+ cli_.set_compress(true);
+ auto res = cli_.Post(
+ "/post", [](size_t /*offset*/, DataSink & /*sink*/) { return false; },
+ "text/plain");
+
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::Canceled, res.error());
+}
+
+TEST_F(ServerTest, PutLargeFileWithGzip) {
+ cli_.set_compress(true);
+ auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(LARGE_DATA, res->body);
+}
+
+TEST_F(ServerTest, PutLargeFileWithGzip2) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ std::string s = std::string("https://") + HOST + ":" + std::to_string(PORT);
+ Client cli(s.c_str());
+ cli.enable_server_certificate_verification(false);
+#else
+ std::string s = std::string("http://") + HOST + ":" + std::to_string(PORT);
+ Client cli(s.c_str());
+#endif
+ cli.set_compress(true);
+
+ auto res = cli.Put("/put-large", LARGE_DATA, "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(LARGE_DATA, res->body);
+ // The compressed size should be less than a 10th of the original. May vary
+ // depending on the zlib library.
+ EXPECT_LT(res.get_request_header_value_u64("Content-Length"),
+ static_cast<uint64_t>(10 * 1024 * 1024));
+ EXPECT_EQ("gzip", res.get_request_header_value("Content-Encoding"));
+}
+
+TEST_F(ServerTest, PutContentWithDeflate) {
+ cli_.set_compress(false);
+ Headers headers;
+ headers.emplace("Content-Encoding", "deflate");
+ // PUT in deflate format:
+ auto res = cli_.Put("/put", headers,
+ "\170\234\013\010\015\001\0\001\361\0\372", "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("PUT", res->body);
+}
+
+TEST_F(ServerTest, GetStreamedChunkedWithGzip) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip, deflate");
+
+ auto res = cli_.Get("/streamed-chunked", headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(std::string("123456789"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedChunkedWithGzip2) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip, deflate");
+
+ auto res = cli_.Get("/streamed-chunked2", headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(std::string("123456789"), res->body);
+}
+
+TEST_F(ServerTest, SplitDelimiterInPathRegex) {
+ auto res = cli_.Get("/regex-with-delimiter?key=^(?.*(value))");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(GzipDecompressor, ChunkedDecompression) {
+ std::string data;
+ for (size_t i = 0; i < 32 * 1024; ++i) {
+ data.push_back(static_cast<char>('a' + i % 26));
+ }
+
+ std::string compressed_data;
+ {
+ httplib::detail::gzip_compressor compressor;
+ bool result = compressor.compress(
+ data.data(), data.size(),
+ /*last=*/true,
+ [&](const char *compressed_data_chunk, size_t compressed_data_size) {
+ compressed_data.insert(compressed_data.size(), compressed_data_chunk,
+ compressed_data_size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+ }
+
+ std::string decompressed_data;
+ {
+ httplib::detail::gzip_decompressor decompressor;
+
+ // Chunk size is chosen specifically to have a decompressed chunk size equal
+ // to 16384 bytes 16384 bytes is the size of decompressor output buffer
+ size_t chunk_size = 130;
+ for (size_t chunk_begin = 0; chunk_begin < compressed_data.size();
+ chunk_begin += chunk_size) {
+ size_t current_chunk_size =
+ std::min(compressed_data.size() - chunk_begin, chunk_size);
+ bool result = decompressor.decompress(
+ compressed_data.data() + chunk_begin, current_chunk_size,
+ [&](const char *decompressed_data_chunk,
+ size_t decompressed_data_chunk_size) {
+ decompressed_data.insert(decompressed_data.size(),
+ decompressed_data_chunk,
+ decompressed_data_chunk_size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+ }
+ }
+ ASSERT_EQ(data, decompressed_data);
+}
+
+TEST(GzipDecompressor, DeflateDecompression) {
+ std::string original_text = "Raw deflate without gzip";
+ unsigned char data[32] = {0x78, 0x9C, 0x0B, 0x4A, 0x2C, 0x57, 0x48, 0x49,
+ 0x4D, 0xCB, 0x49, 0x2C, 0x49, 0x55, 0x28, 0xCF,
+ 0x2C, 0xC9, 0xC8, 0x2F, 0x2D, 0x51, 0x48, 0xAF,
+ 0xCA, 0x2C, 0x00, 0x00, 0x6F, 0x98, 0x09, 0x2E};
+ std::string compressed_data(data, data + sizeof(data) / sizeof(data[0]));
+
+ std::string decompressed_data;
+ {
+ httplib::detail::gzip_decompressor decompressor;
+
+ bool result = decompressor.decompress(
+ compressed_data.data(), compressed_data.size(),
+ [&](const char *decompressed_data_chunk,
+ size_t decompressed_data_chunk_size) {
+ decompressed_data.insert(decompressed_data.size(),
+ decompressed_data_chunk,
+ decompressed_data_chunk_size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+ }
+ ASSERT_EQ(original_text, decompressed_data);
+}
+
+TEST(GzipDecompressor, DeflateDecompressionTrailingBytes) {
+ std::string original_text = "Raw deflate without gzip";
+ unsigned char data[40] = {0x78, 0x9C, 0x0B, 0x4A, 0x2C, 0x57, 0x48, 0x49,
+ 0x4D, 0xCB, 0x49, 0x2C, 0x49, 0x55, 0x28, 0xCF,
+ 0x2C, 0xC9, 0xC8, 0x2F, 0x2D, 0x51, 0x48, 0xAF,
+ 0xCA, 0x2C, 0x00, 0x00, 0x6F, 0x98, 0x09, 0x2E,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ std::string compressed_data(data, data + sizeof(data) / sizeof(data[0]));
+
+ std::string decompressed_data;
+ {
+ httplib::detail::gzip_decompressor decompressor;
+
+ bool result = decompressor.decompress(
+ compressed_data.data(), compressed_data.size(),
+ [&](const char *decompressed_data_chunk,
+ size_t decompressed_data_chunk_size) {
+ decompressed_data.insert(decompressed_data.size(),
+ decompressed_data_chunk,
+ decompressed_data_chunk_size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+ }
+ ASSERT_EQ(original_text, decompressed_data);
+}
+
+#ifdef _WIN32
+TEST(GzipDecompressor, LargeRandomData) {
+
+ // prepare large random data that is difficult to be compressed and is
+ // expected to have large size even when compressed
+ std::random_device seed_gen;
+ std::mt19937 random(seed_gen());
+ constexpr auto large_size_byte = 4294967296UL; // 4GiB
+ constexpr auto data_size = large_size_byte + 134217728UL; // + 128MiB
+ std::vector<std::uint32_t> data(data_size / sizeof(std::uint32_t));
+ std::generate(data.begin(), data.end(), [&]() { return random(); });
+
+ // compress data over 4GiB
+ std::string compressed_data;
+ compressed_data.reserve(large_size_byte + 536870912UL); // + 512MiB reserved
+ httplib::detail::gzip_compressor compressor;
+ auto result = compressor.compress(reinterpret_cast<const char *>(data.data()),
+ data.size() * sizeof(std::uint32_t), true,
+ [&](const char *data, size_t size) {
+ compressed_data.insert(
+ compressed_data.size(), data, size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+
+ // FIXME: compressed data size is expected to be greater than 4GiB,
+ // but there is no guarantee
+ // ASSERT_TRUE(compressed_data.size() >= large_size_byte);
+
+ // decompress data over 4GiB
+ std::string decompressed_data;
+ decompressed_data.reserve(data_size);
+ httplib::detail::gzip_decompressor decompressor;
+ result = decompressor.decompress(
+ compressed_data.data(), compressed_data.size(),
+ [&](const char *data, size_t size) {
+ decompressed_data.insert(decompressed_data.size(), data, size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+
+ // compare
+ ASSERT_EQ(data_size, decompressed_data.size());
+ ASSERT_TRUE(std::memcmp(data.data(), decompressed_data.data(), data_size) ==
+ 0);
+}
+#endif
+#endif
+
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+TEST_F(ServerTest, GetStreamedChunkedWithBrotli) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "br");
+
+ auto res = cli_.Get("/streamed-chunked", headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(std::string("123456789"), res->body);
+}
+
+TEST_F(ServerTest, GetStreamedChunkedWithBrotli2) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "br");
+
+ auto res = cli_.Get("/streamed-chunked2", headers);
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(std::string("123456789"), res->body);
+}
+#endif
+
+TEST_F(ServerTest, Patch) {
+ auto res = cli_.Patch("/patch", "PATCH", "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("PATCH", res->body);
+}
+
+TEST_F(ServerTest, Delete) {
+ auto res = cli_.Delete("/delete");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("DELETE", res->body);
+}
+
+TEST_F(ServerTest, DeleteContentReceiver) {
+ auto res = cli_.Delete("/delete-body", "content", "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("content", res->body);
+}
+
+TEST_F(ServerTest, Options) {
+ auto res = cli_.Options("*");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("GET, POST, HEAD, OPTIONS", res->get_header_value("Allow"));
+ EXPECT_TRUE(res->body.empty());
+}
+
+TEST_F(ServerTest, URL) {
+ auto res = cli_.Get("/request-target?aaa=bbb&ccc=ddd");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, ArrayParam) {
+ auto res = cli_.Get("/array-param?array=value1&array=value2&array=value3");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, NoMultipleHeaders) {
+ Headers headers = {{"Content-Length", "5"}};
+ auto res = cli_.Post("/validate-no-multiple-headers", headers, "hello",
+ "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, PostContentReceiver) {
+ auto res = cli_.Post("/content_receiver", "content", "text/plain");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("content", res->body);
+}
+
+TEST_F(ServerTest, PostMultipartFileContentReceiver) {
+ UploadFormDataItems items = {
+ {"text1", "text default", "", ""},
+ {"text2", "aωb", "", ""},
+ {"file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain"},
+ {"file2", R"({\n "world": true\n}\n)", "world.json", "application/json"},
+ {"file3", "", "", "application/octet-stream"},
+ };
+
+ auto res = cli_.Post("/content_receiver", items);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, PostMultipartPlusBoundary) {
+ UploadFormDataItems items = {
+ {"text1", "text default", "", ""},
+ {"text2", "aωb", "", ""},
+ {"file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain"},
+ {"file2", R"({\n "world": true\n}\n)", "world.json", "application/json"},
+ {"file3", "", "", "application/octet-stream"},
+ };
+
+ auto boundary = std::string("+++++");
+
+ std::string body;
+
+ for (const auto &item : items) {
+ body += "--" + boundary + "\r\n";
+ body += "Content-Disposition: form-data; name=\"" + item.name + "\"";
+ if (!item.filename.empty()) {
+ body += "; filename=\"" + item.filename + "\"";
+ }
+ body += "\r\n";
+ if (!item.content_type.empty()) {
+ body += "Content-Type: " + item.content_type + "\r\n";
+ }
+ body += "\r\n";
+ body += item.content + "\r\n";
+ }
+ body += "--" + boundary + "--\r\n";
+
+ std::string content_type = "multipart/form-data; boundary=" + boundary;
+ auto res = cli_.Post("/content_receiver", body, content_type.c_str());
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, PostContentReceiverGzip) {
+ cli_.set_compress(true);
+ auto res = cli_.Post("/content_receiver", "content", "text/plain");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("content", res->body);
+}
+
+TEST_F(ServerTest, PutContentReceiver) {
+ auto res = cli_.Put("/content_receiver", "content", "text/plain");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("content", res->body);
+}
+
+TEST_F(ServerTest, PatchContentReceiver) {
+ auto res = cli_.Patch("/content_receiver", "content", "text/plain");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ("content", res->body);
+}
+
+template <typename ClientType>
+void TestWithHeadersAndContentReceiver(
+ ClientType &cli,
+ std::function<Result(ClientType &, const std::string &, const Headers &,
+ const std::string &, const std::string &,
+ ContentReceiver, DownloadProgress)>
+ request_func) {
+ Headers headers;
+ headers.emplace("X-Custom-Header", "test-value");
+
+ std::string received_body;
+ auto res = request_func(
+ cli, "/content_receiver", headers, "content", "application/json",
+ [&](const char *data, size_t data_length) {
+ received_body.append(data, data_length);
+ return true;
+ },
+ nullptr);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("content", received_body);
+}
+
+TEST_F(ServerTest, PostWithHeadersAndContentReceiver) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiver<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver, DownloadProgress progress) {
+ return cli.Post(path, headers, body, content_type, receiver, progress);
+ });
+}
+
+TEST_F(ServerTest, PutWithHeadersAndContentReceiver) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiver<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver, DownloadProgress progress) {
+ return cli.Put(path, headers, body, content_type, receiver, progress);
+ });
+}
+
+TEST_F(ServerTest, PatchWithHeadersAndContentReceiver) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiver<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver, DownloadProgress progress) {
+ return cli.Patch(path, headers, body, content_type, receiver, progress);
+ });
+}
+
+template <typename ClientType>
+void TestWithHeadersAndContentReceiverWithProgress(
+ ClientType &cli,
+ std::function<Result(ClientType &, const std::string &, const Headers &,
+ const std::string &, const std::string &,
+ ContentReceiver, DownloadProgress)>
+ request_func) {
+ Headers headers;
+ headers.emplace("X-Test-Header", "progress-test");
+
+ std::string received_body;
+ auto progress_called = false;
+
+ auto res = request_func(
+ cli, "/content_receiver", headers, "content", "text/plain",
+ [&](const char *data, size_t data_length) {
+ received_body.append(data, data_length);
+ return true;
+ },
+ [&](uint64_t /*current*/, uint64_t /*total*/) {
+ progress_called = true;
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("content", received_body);
+ EXPECT_TRUE(progress_called);
+}
+
+TEST_F(ServerTest, PostWithHeadersAndContentReceiverWithProgress) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiverWithProgress<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver, DownloadProgress progress) {
+ return cli.Post(path, headers, body, content_type, receiver, progress);
+ });
+}
+
+TEST_F(ServerTest, PutWithHeadersAndContentReceiverWithProgress) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiverWithProgress<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver, DownloadProgress progress) {
+ return cli.Put(path, headers, body, content_type, receiver, progress);
+ });
+}
+
+TEST_F(ServerTest, PatchWithHeadersAndContentReceiverWithProgress) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiverWithProgress<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver, DownloadProgress progress) {
+ return cli.Patch(path, headers, body, content_type, receiver, progress);
+ });
+}
+
+template <typename ClientType>
+void TestWithHeadersAndContentReceiverError(
+ ClientType &cli, std::function<Result(ClientType &, const std::string &,
+ const Headers &, const std::string &,
+ const std::string &, ContentReceiver)>
+ request_func) {
+ Headers headers;
+ headers.emplace("X-Error-Test", "true");
+
+ std::string received_body;
+ auto receiver_failed = false;
+
+ auto res =
+ request_func(cli, "/content_receiver", headers, "content", "text/plain",
+ [&](const char *data, size_t data_length) {
+ received_body.append(data, data_length);
+ receiver_failed = true;
+ return false;
+ });
+
+ ASSERT_FALSE(res);
+ EXPECT_TRUE(receiver_failed);
+}
+
+TEST_F(ServerTest, PostWithHeadersAndContentReceiverError) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiverError<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver) {
+ return cli.Post(path, headers, body, content_type, receiver);
+ });
+}
+
+TEST_F(ServerTest, PuttWithHeadersAndContentReceiverError) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiverError<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver) {
+ return cli.Put(path, headers, body, content_type, receiver);
+ });
+}
+
+TEST_F(ServerTest, PatchWithHeadersAndContentReceiverError) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ using ClientT = SSLClient;
+#else
+ using ClientT = Client;
+#endif
+ TestWithHeadersAndContentReceiverError<ClientT>(
+ cli_, [](ClientT &cli, const std::string &path, const Headers &headers,
+ const std::string &body, const std::string &content_type,
+ ContentReceiver receiver) {
+ return cli.Patch(path, headers, body, content_type, receiver);
+ });
+}
+
+TEST_F(ServerTest, PostQueryStringAndBody) {
+ auto res =
+ cli_.Post("/query-string-and-body?key=value", "content", "text/plain");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, HTTP2Magic) {
+ Request req;
+ req.method = "PRI";
+ req.path = "*";
+ req.body = "SM";
+
+ auto res = std::make_shared<Response>();
+ auto error = Error::Success;
+ auto ret = cli_.send(req, *res, error);
+
+ ASSERT_TRUE(ret);
+ EXPECT_EQ(StatusCode::BadRequest_400, res->status);
+}
+
+TEST_F(ServerTest, KeepAlive) {
+ auto res = cli_.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("Hello World!", res->body);
+
+ res = cli_.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("Hello World!", res->body);
+
+ res = cli_.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("Hello World!", res->body);
+
+ res = cli_.Get("/not-exist");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+
+ res = cli_.Post("/empty", "", "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("empty", res->body);
+ EXPECT_EQ("close", res->get_header_value("Connection"));
+
+ res = cli_.Post(
+ "/empty", 0, [&](size_t, size_t, DataSink &) { return true; },
+ "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("empty", res->body);
+
+ cli_.set_keep_alive(false);
+ res = cli_.Get("/last-request");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("close", res->get_header_value("Connection"));
+}
+
+TEST_F(ServerTest, TooManyRedirect) {
+ cli_.set_follow_location(true);
+ auto res = cli_.Get("/redirect/0");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::ExceedRedirectCount, res.error());
+}
+
+TEST_F(ServerTest, StartTime) { auto res = cli_.Get("/test-start-time"); }
+
+#ifdef CPPHTTPLIB_ZLIB_SUPPORT
+TEST_F(ServerTest, Gzip) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip, deflate");
+ auto res = cli_.Get("/compress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("33", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, GzipWithoutAcceptEncoding) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "");
+ auto res = cli_.Get("/compress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_TRUE(res->get_header_value("Content-Encoding").empty());
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("100", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, GzipWithContentReceiver) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip, deflate");
+ std::string body;
+ auto res = cli_.Get("/compress", headers,
+ [&](const char *data, uint64_t data_length) {
+ EXPECT_EQ(100U, data_length);
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("33", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, GzipWithoutDecompressing) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip, deflate");
+
+ cli_.set_decompress(false);
+ auto res = cli_.Get("/compress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("33", res->get_header_value("Content-Length"));
+ EXPECT_EQ(33U, res->body.size());
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, GzipWithContentReceiverWithoutAcceptEncoding) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "");
+
+ std::string body;
+ auto res = cli_.Get("/compress", headers,
+ [&](const char *data, uint64_t data_length) {
+ EXPECT_EQ(100U, data_length);
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_TRUE(res->get_header_value("Content-Encoding").empty());
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("100", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, NoGzip) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip, deflate");
+ auto res = cli_.Get("/nocompress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(false, res->has_header("Content-Encoding"));
+ EXPECT_EQ("application/octet-stream", res->get_header_value("Content-Type"));
+ EXPECT_EQ("100", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, NoGzipWithContentReceiver) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip, deflate");
+ std::string body;
+ auto res = cli_.Get("/nocompress", headers,
+ [&](const char *data, uint64_t data_length) {
+ EXPECT_EQ(100U, data_length);
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(false, res->has_header("Content-Encoding"));
+ EXPECT_EQ("application/octet-stream", res->get_header_value("Content-Type"));
+ EXPECT_EQ("100", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, MultipartFormDataGzip) {
+ UploadFormDataItems items = {
+ {"key1", "test", "", ""},
+ {"key2", "--abcdefg123", "", ""},
+ };
+
+ cli_.set_compress(true);
+ auto res = cli_.Post("/compress-multipart", items);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+#endif
+
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+TEST_F(ServerTest, Brotli) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "br");
+ auto res = cli_.Get("/compress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("br", res->get_header_value("Content-Encoding"));
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("19", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+#endif
+
+#ifdef CPPHTTPLIB_ZSTD_SUPPORT
+TEST_F(ServerTest, Zstd) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "zstd");
+ auto res = cli_.Get("/compress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("zstd", res->get_header_value("Content-Encoding"));
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("26", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, ZstdWithoutAcceptEncoding) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "");
+ auto res = cli_.Get("/compress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_TRUE(res->get_header_value("Content-Encoding").empty());
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("100", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, ZstdWithContentReceiver) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "zstd");
+ std::string body;
+ auto res = cli_.Get("/compress", headers,
+ [&](const char *data, uint64_t data_length) {
+ EXPECT_EQ(100U, data_length);
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("zstd", res->get_header_value("Content-Encoding"));
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("26", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, ZstdWithoutDecompressing) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "zstd");
+
+ cli_.set_decompress(false);
+ auto res = cli_.Get("/compress", headers);
+
+ unsigned char compressed[26] = {0x28, 0xb5, 0x2f, 0xfd, 0x20, 0x64, 0x8d,
+ 0x00, 0x00, 0x50, 0x31, 0x32, 0x33, 0x34,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x01,
+ 0x00, 0xd7, 0xa9, 0x20, 0x01};
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("zstd", res->get_header_value("Content-Encoding"));
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("26", res->get_header_value("Content-Length"));
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_EQ(26U, res->body.size());
+ EXPECT_TRUE(std::memcmp(compressed, res->body.data(), sizeof(compressed)) ==
+ 0);
+}
+
+TEST_F(ServerTest, ZstdWithContentReceiverWithoutAcceptEncoding) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "");
+
+ std::string body;
+ auto res = cli_.Get("/compress", headers,
+ [&](const char *data, uint64_t data_length) {
+ EXPECT_EQ(100U, data_length);
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_TRUE(res->get_header_value("Content-Encoding").empty());
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("100", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, NoZstd) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "zstd");
+ auto res = cli_.Get("/nocompress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(false, res->has_header("Content-Encoding"));
+ EXPECT_EQ("application/octet-stream", res->get_header_value("Content-Type"));
+ EXPECT_EQ("100", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ res->body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, NoZstdWithContentReceiver) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "zstd");
+ std::string body;
+ auto res = cli_.Get("/nocompress", headers,
+ [&](const char *data, uint64_t data_length) {
+ EXPECT_EQ(100U, data_length);
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(false, res->has_header("Content-Encoding"));
+ EXPECT_EQ("application/octet-stream", res->get_header_value("Content-Type"));
+ EXPECT_EQ("100", res->get_header_value("Content-Length"));
+ EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
+ "7890123456789012345678901234567890",
+ body);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+// TODO: How to enable zstd ??
+TEST_F(ServerTest, MultipartFormDataZstd) {
+ UploadFormDataItems items = {
+ {"key1", "test", "", ""},
+ {"key2", "--abcdefg123", "", ""},
+ };
+ Headers headers;
+ headers.emplace("Accept-Encoding", "zstd");
+
+ cli_.set_compress(true);
+ auto res = cli_.Post("/compress-multipart", headers, items);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(ServerTest, PutWithContentProviderWithZstd) {
+ Headers headers;
+ headers.emplace("Accept-Encoding", "zstd");
+
+ cli_.set_compress(true);
+ auto res = cli_.Put(
+ "/put", headers, 3,
+ [](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ sink.os << "PUT";
+ return true;
+ },
+ "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("PUT", res->body);
+}
+
+// Pre-compression logging tests
+TEST_F(ServerTest, PreCompressionLogging) {
+ // Test data for compression (matches the actual /compress endpoint content)
+ const std::string test_content =
+ "123456789012345678901234567890123456789012345678901234567890123456789012"
+ "3456789012345678901234567890";
+
+ // Variables to capture logging data
+ std::string pre_compression_body;
+ std::string pre_compression_content_type;
+ std::string pre_compression_content_encoding;
+
+ std::string post_compression_body;
+ std::string post_compression_content_type;
+ std::string post_compression_content_encoding;
+
+ // Set up pre-compression logger
+ svr_.set_pre_compression_logger([&](const Request & /*req*/,
+ const Response &res) {
+ pre_compression_body = res.body;
+ pre_compression_content_type = res.get_header_value("Content-Type");
+ pre_compression_content_encoding = res.get_header_value("Content-Encoding");
+ });
+
+ // Set up post-compression logger
+ svr_.set_logger([&](const Request & /*req*/, const Response &res) {
+ post_compression_body = res.body;
+ post_compression_content_type = res.get_header_value("Content-Type");
+ post_compression_content_encoding =
+ res.get_header_value("Content-Encoding");
+ });
+
+ // Test with gzip compression
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip");
+
+ auto res = cli_.Get("/compress", headers);
+
+ // Verify response was compressed
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
+
+ // Verify pre-compression logger captured uncompressed content
+ EXPECT_EQ(test_content, pre_compression_body);
+ EXPECT_EQ("text/plain", pre_compression_content_type);
+ EXPECT_TRUE(pre_compression_content_encoding
+ .empty()); // No encoding header before compression
+
+ // Verify post-compression logger captured compressed content
+ EXPECT_NE(test_content,
+ post_compression_body); // Should be different after compression
+ EXPECT_EQ("text/plain", post_compression_content_type);
+ EXPECT_EQ("gzip", post_compression_content_encoding);
+
+ // Verify compressed content is smaller
+ EXPECT_LT(post_compression_body.size(), pre_compression_body.size());
+}
+
+TEST_F(ServerTest, PreCompressionLoggingWithBrotli) {
+ const std::string test_content =
+ "123456789012345678901234567890123456789012345678901234567890123456789012"
+ "3456789012345678901234567890";
+
+ std::string pre_compression_body;
+ std::string post_compression_body;
+
+ svr_.set_pre_compression_logger(
+ [&](const Request & /*req*/, const Response &res) {
+ pre_compression_body = res.body;
+ });
+
+ svr_.set_logger([&](const Request & /*req*/, const Response &res) {
+ post_compression_body = res.body;
+ });
+
+ Headers headers;
+ headers.emplace("Accept-Encoding", "br");
+
+ auto res = cli_.Get("/compress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("br", res->get_header_value("Content-Encoding"));
+
+ // Verify pre-compression content is uncompressed
+ EXPECT_EQ(test_content, pre_compression_body);
+
+ // Verify post-compression content is compressed
+ EXPECT_NE(test_content, post_compression_body);
+ EXPECT_LT(post_compression_body.size(), pre_compression_body.size());
+}
+
+TEST_F(ServerTest, PreCompressionLoggingWithoutCompression) {
+ const std::string test_content =
+ "123456789012345678901234567890123456789012345678901234567890123456789012"
+ "3456789012345678901234567890";
+
+ std::string pre_compression_body;
+ std::string post_compression_body;
+
+ svr_.set_pre_compression_logger(
+ [&](const Request & /*req*/, const Response &res) {
+ pre_compression_body = res.body;
+ });
+
+ svr_.set_logger([&](const Request & /*req*/, const Response &res) {
+ post_compression_body = res.body;
+ });
+
+ // Request without compression (use /nocompress endpoint)
+ Headers headers;
+ auto res = cli_.Get("/nocompress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_TRUE(res->get_header_value("Content-Encoding").empty());
+
+ // Pre-compression logger should not be called when no compression is applied
+ EXPECT_TRUE(
+ pre_compression_body.empty()); // Pre-compression logger not called
+ EXPECT_EQ(
+ test_content,
+ post_compression_body); // Post-compression logger captures final content
+}
+
+TEST_F(ServerTest, PreCompressionLoggingOnlyPreLogger) {
+ const std::string test_content =
+ "123456789012345678901234567890123456789012345678901234567890123456789012"
+ "3456789012345678901234567890";
+
+ std::string pre_compression_body;
+ bool pre_logger_called = false;
+
+ // Set only pre-compression logger
+ svr_.set_pre_compression_logger(
+ [&](const Request & /*req*/, const Response &res) {
+ pre_compression_body = res.body;
+ pre_logger_called = true;
+ });
+
+ Headers headers;
+ headers.emplace("Accept-Encoding", "gzip");
+
+ auto res = cli_.Get("/compress", headers);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
+
+ // Verify pre-compression logger was called
+ EXPECT_TRUE(pre_logger_called);
+ EXPECT_EQ(test_content, pre_compression_body);
+}
+
+TEST(ZstdDecompressor, ChunkedDecompression) {
+ std::string data;
+ for (size_t i = 0; i < 32 * 1024; ++i) {
+ data.push_back(static_cast<char>('a' + i % 26));
+ }
+
+ std::string compressed_data;
+ {
+ httplib::detail::zstd_compressor compressor;
+ bool result = compressor.compress(
+ data.data(), data.size(),
+ /*last=*/true,
+ [&](const char *compressed_data_chunk, size_t compressed_data_size) {
+ compressed_data.insert(compressed_data.size(), compressed_data_chunk,
+ compressed_data_size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+ }
+
+ std::string decompressed_data;
+ {
+ httplib::detail::zstd_decompressor decompressor;
+
+ // Chunk size is chosen specifically to have a decompressed chunk size equal
+ // to 16384 bytes 16384 bytes is the size of decompressor output buffer
+ size_t chunk_size = 130;
+ for (size_t chunk_begin = 0; chunk_begin < compressed_data.size();
+ chunk_begin += chunk_size) {
+ size_t current_chunk_size =
+ std::min(compressed_data.size() - chunk_begin, chunk_size);
+ bool result = decompressor.decompress(
+ compressed_data.data() + chunk_begin, current_chunk_size,
+ [&](const char *decompressed_data_chunk,
+ size_t decompressed_data_chunk_size) {
+ decompressed_data.insert(decompressed_data.size(),
+ decompressed_data_chunk,
+ decompressed_data_chunk_size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+ }
+ }
+ ASSERT_EQ(data, decompressed_data);
+}
+
+TEST(ZstdDecompressor, Decompress) {
+ std::string original_text = "Compressed with ZSTD";
+ unsigned char data[29] = {0x28, 0xb5, 0x2f, 0xfd, 0x20, 0x14, 0xa1, 0x00,
+ 0x00, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73,
+ 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68,
+ 0x20, 0x5a, 0x53, 0x54, 0x44};
+ std::string compressed_data(data, data + sizeof(data) / sizeof(data[0]));
+
+ std::string decompressed_data;
+ {
+ httplib::detail::zstd_decompressor decompressor;
+
+ bool result = decompressor.decompress(
+ compressed_data.data(), compressed_data.size(),
+ [&](const char *decompressed_data_chunk,
+ size_t decompressed_data_chunk_size) {
+ decompressed_data.insert(decompressed_data.size(),
+ decompressed_data_chunk,
+ decompressed_data_chunk_size);
+ return true;
+ });
+ ASSERT_TRUE(result);
+ }
+ ASSERT_EQ(original_text, decompressed_data);
+}
+#endif
+
+// Sends a raw request to a server listening at HOST:PORT.
+static bool send_request(time_t read_timeout_sec, const std::string &req,
+ std::string *resp = nullptr) {
+ auto error = Error::Success;
+
+ auto client_sock = detail::create_client_socket(
+ HOST, "", PORT, AF_UNSPEC, false, false, nullptr,
+ /*connection_timeout_sec=*/5, 0,
+ /*read_timeout_sec=*/5, 0,
+ /*write_timeout_sec=*/5, 0, std::string(), error);
+
+ if (client_sock == INVALID_SOCKET) { return false; }
+
+ auto ret = detail::process_client_socket(
+ client_sock, read_timeout_sec, 0, 0, 0, 0,
+ std::chrono::steady_clock::time_point::min(), [&](Stream &strm) {
+ if (req.size() !=
+ static_cast<size_t>(strm.write(req.data(), req.size()))) {
+ return false;
+ }
+
+ char buf[512];
+
+ detail::stream_line_reader line_reader(strm, buf, sizeof(buf));
+ while (line_reader.getline()) {
+ if (resp) { *resp += line_reader.ptr(); }
+ }
+ return true;
+ });
+
+ detail::close_socket(client_sock);
+
+ return ret;
+}
+
+TEST(ServerRequestParsingTest, TrimWhitespaceFromHeaderValues) {
+ Server svr;
+ std::string header_value;
+ svr.Get("/validate-ws-in-headers", [&](const Request &req, Response &res) {
+ header_value = req.get_header_value("foo");
+ res.set_content("ok", "text/plain");
+ });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ // Only space and horizontal tab are whitespace. Make sure other whitespace-
+ // like characters are not treated the same - use vertical tab and escape.
+ const std::string req = "GET /validate-ws-in-headers HTTP/1.1\r\n"
+ "foo: \t \v bar \x1B\t \r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ std::string res;
+ ASSERT_TRUE(send_request(5, req, &res));
+ EXPECT_EQ(header_value, "");
+ EXPECT_EQ("HTTP/1.1 400 Bad Request", res.substr(0, 24));
+}
+
+// Sends a raw request and verifies that there isn't a crash or exception.
+static void test_raw_request(const std::string &req,
+ std::string *out = nullptr) {
+ Server svr;
+ svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
+ res.set_content("ok", "text/plain");
+ });
+ svr.Put("/put_hi", [&](const Request & /*req*/, Response &res) {
+ res.set_content("ok", "text/plain");
+ });
+ svr.Get("/header_field_value_check",
+ [&](const Request & /*req*/, Response &res) {
+ res.set_content("ok", "text/plain");
+ });
+
+ // Server read timeout must be longer than the client read timeout for the
+ // bug to reproduce, probably to force the server to process a request
+ // without a trailing blank line.
+ const time_t client_read_timeout_sec = 1;
+ svr.set_read_timeout(std::chrono::seconds(client_read_timeout_sec + 1));
+ bool listen_thread_ok = false;
+ thread t = thread([&] { listen_thread_ok = svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ EXPECT_TRUE(listen_thread_ok);
+ });
+
+ svr.wait_until_ready();
+
+ ASSERT_TRUE(send_request(client_read_timeout_sec, req, out));
+}
+
+TEST(ServerRequestParsingTest, ReadHeadersRegexComplexity) {
+ // A certain header line causes an exception if the header property is parsed
+ // naively with a single regex. This occurs with libc++ but not libstdc++.
+ test_raw_request(
+ "GET /hi HTTP/1.1\r\n"
+ " : "
+ " "
+ " ");
+}
+
+TEST(ServerRequestParsingTest, ReadHeadersRegexComplexity2) {
+ // A certain header line causes an exception if the header property *name* is
+ // parsed with a regular expression starting with "(.+?):" - this is a non-
+ // greedy matcher and requires backtracking when there are a lot of ":"
+ // characters.
+ // This occurs with libc++ but not libstdc++.
+ test_raw_request(
+ "GET /hi HTTP/1.1\r\n"
+ ":-:::::::::::::::::::::::::::-::::::::::::::::::::::::@-&&&&&&&&&&&"
+ "--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&"
+ "&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-:::::"
+ "::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-::::::::::::::::::::::::"
+ ":::::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::"
+ "::::::::-:::::::::::::::::@-&&&&&&&--:::::::-::::::::::::::::::::::"
+ ":::::::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-:::::::::::::::::::"
+ "::::::::::-:::::::::::::::::@-&&&&&::::::::::::-:::::::::::::::::@-"
+ "&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-::::::::::::::::"
+ ":@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::"
+ "::::@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-::::::@-&&"
+ "&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@"
+ "::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&&&&"
+ "--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&"
+ "&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&"
+ "&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&"
+ "&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@"
+ "-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::"
+ "::@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-::::::::::::"
+ ":::::@-&&&&&&&&&&&::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-::::::"
+ ":::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-:::"
+ "::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-"
+ ":::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&&&&---&&:&"
+ "&&.0------------:-:::::::::::::::::::::::::::::-:::::::::::::::::@-"
+ "&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-::::::::::::::::"
+ ":@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::"
+ "::::@-&&&&&&&&&&&---&&:&&&.0------------O--------\rH PUTHTTP/1.1\r\n"
+ "&&&%%%");
+}
+
+TEST(ServerRequestParsingTest, ExcessiveWhitespaceInUnparsableHeaderLine) {
+ // Make sure this doesn't crash the server.
+ // In a previous version of the header line regex, the "\r" rendered the line
+ // unparsable and the regex engine repeatedly backtracked, trying to look for
+ // a new position where the leading white space ended and the field value
+ // began.
+ // The crash occurs with libc++ but not libstdc++.
+ test_raw_request("GET /hi HTTP/1.1\r\n"
+ "a:" +
+ std::string(2000, ' ') + '\r' + std::string(20, 'z') +
+ "\r\n"
+ "\r\n");
+}
+
+TEST(ServerRequestParsingTest, InvalidFirstChunkLengthInRequest) {
+ std::string out;
+
+ test_raw_request("PUT /put_hi HTTP/1.1\r\n"
+ "Content-Type: text/plain\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "nothex\r\n",
+ &out);
+ EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
+}
+
+TEST(ServerRequestParsingTest, InvalidSecondChunkLengthInRequest) {
+ std::string out;
+
+ test_raw_request("PUT /put_hi HTTP/1.1\r\n"
+ "Content-Type: text/plain\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "3\r\n"
+ "xyz\r\n"
+ "NaN\r\n",
+ &out);
+ EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
+}
+
+TEST(ServerRequestParsingTest, ChunkLengthTooHighInRequest) {
+ std::string out;
+
+ test_raw_request("PUT /put_hi HTTP/1.1\r\n"
+ "Content-Type: text/plain\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ // Length is too large for 64 bits.
+ "1ffffffffffffffff\r\n"
+ "xyz\r\n",
+ &out);
+ EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
+}
+
+TEST(ServerRequestParsingTest, InvalidHeaderTextWithExtraCR) {
+ test_raw_request("GET /hi HTTP/1.1\r\n"
+ "Content-Type: text/plain\r\n\r");
+}
+
+TEST(ServerRequestParsingTest, InvalidSpaceInURL) {
+ std::string out;
+ test_raw_request("GET /h i HTTP/1.1\r\n\r\n", &out);
+ EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
+}
+
+TEST(ServerRequestParsingTest, InvalidFieldValueContains_CR_LF_NUL) {
+ std::string out;
+ std::string request(
+ "GET /header_field_value_check HTTP/1.1\r\nTest: [\r\x00\n]\r\n\r\n", 55);
+ test_raw_request(request, &out);
+ EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
+}
+
+TEST(ServerRequestParsingTest, InvalidFieldValueContains_LF) {
+ std::string out;
+ std::string request(
+ "GET /header_field_value_check HTTP/1.1\r\nTest: [\n\n\n]\r\n\r\n", 55);
+ test_raw_request(request, &out);
+ EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
+}
+
+TEST(ServerRequestParsingTest, InvalidFieldNameContains_PreceedingSpaces) {
+ std::string out;
+ std::string request(
+ "GET /header_field_value_check HTTP/1.1\r\n Test: val\r\n\r\n", 55);
+ test_raw_request(request, &out);
+ EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
+}
+
+TEST(ServerRequestParsingTest, EmptyFieldValue) {
+ std::string out;
+
+ test_raw_request("GET /header_field_value_check HTTP/1.1\r\n"
+ "Test: \r\n\r\n",
+ &out);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.substr(0, 15));
+}
+
+TEST(ServerStopTest, StopServerWithChunkedTransmission) {
+ Server svr;
+
+ svr.Get("/events", [](const Request & /*req*/, Response &res) {
+ res.set_header("Cache-Control", "no-cache");
+ res.set_chunked_content_provider(
+ "text/event-stream", [](size_t offset, DataSink &sink) {
+ std::string s = "data:";
+ s += std::to_string(offset);
+ s += "\n\n";
+ auto ret = sink.write(s.data(), s.size());
+ EXPECT_TRUE(ret);
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ return true;
+ });
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ svr.wait_until_ready();
+
+ Client client(HOST, PORT);
+ const Headers headers = {{"Accept", "text/event-stream"}};
+
+ auto get_thread = std::thread([&client, &headers]() {
+ auto res = client.Get(
+ "/events", headers,
+ [](const char * /*data*/, size_t /*len*/) -> bool { return true; });
+ });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ get_thread.join();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ // Give GET time to get a few messages.
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+}
+
+TEST(ServerStopTest, ClientAccessAfterServerDown) {
+ httplib::Server svr;
+ svr.Post("/hi",
+ [&](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.status = StatusCode::OK_200;
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+
+ auto res = cli.Post("/hi", "data", "text/plain");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+
+ res = cli.Post("/hi", "data", "text/plain");
+ ASSERT_FALSE(res);
+}
+
+TEST(ServerStopTest, ListenFailure) {
+ Server svr;
+ auto t = thread([&]() {
+ auto ret = svr.listen("????", PORT);
+ EXPECT_FALSE(ret);
+ });
+ svr.wait_until_ready();
+ svr.stop();
+ t.join();
+}
+
+TEST(ServerStopTest, Decommision) {
+ Server svr;
+
+ svr.Get("/hi", [&](const Request &, Response &res) { res.body = "hi..."; });
+
+ for (int i = 0; i < 4; i++) {
+ auto is_even = !(i % 2);
+
+ std::thread t{[&] {
+ try {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ if (is_even) {
+ throw std::runtime_error("Some thing that happens to go wrong.");
+ }
+
+ svr.listen(HOST, PORT);
+ } catch (...) { svr.decommission(); }
+ }};
+
+ svr.wait_until_ready();
+
+ // Server is up
+ {
+ Client cli(HOST, PORT);
+ auto res = cli.Get("/hi");
+ if (is_even) {
+ EXPECT_FALSE(res);
+ } else {
+ EXPECT_TRUE(res);
+ EXPECT_EQ("hi...", res->body);
+ }
+ }
+
+ svr.stop();
+ t.join();
+
+ // Server is down...
+ {
+ Client cli(HOST, PORT);
+ auto res = cli.Get("/hi");
+ EXPECT_FALSE(res);
+ }
+ }
+}
+
+// Helper function for string body upload progress tests
+template <typename SetupHandler, typename ClientCall>
+void TestStringBodyUploadProgress(SetupHandler &&setup_handler,
+ ClientCall &&client_call,
+ const string &body) {
+ Server svr;
+ setup_handler(svr);
+
+ thread t = thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ vector<uint64_t> progress_values;
+ bool progress_called = false;
+
+ auto res =
+ client_call(cli, body, [&](uint64_t current, uint64_t /*total*/) -> bool {
+ progress_values.push_back(current);
+ progress_called = true;
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(200, res->status);
+ EXPECT_TRUE(progress_called);
+}
+
+TEST(UploadProgressTest, PostStringBodyBasic) {
+ TestStringBodyUploadProgress(
+ [](Server &svr) {
+ svr.Post("/test", [](const Request & /*req*/, Response &res) {
+ res.set_content("received", "text/plain");
+ });
+ },
+ [](Client &cli, const string &body, UploadProgress progress_callback) {
+ return cli.Post("/test", body, "text/plain", progress_callback);
+ },
+ "test data for upload progress");
+}
+
+TEST(UploadProgressTest, PutStringBodyBasic) {
+ TestStringBodyUploadProgress(
+ [](Server &svr) {
+ svr.Put("/test", [](const Request & /*req*/, Response &res) {
+ res.set_content("put received", "text/plain");
+ });
+ },
+ [](Client &cli, const string &body, UploadProgress progress_callback) {
+ return cli.Put("/test", body, "text/plain", progress_callback);
+ },
+ "put test data for upload progress");
+}
+
+TEST(UploadProgressTest, PatchStringBodyBasic) {
+ TestStringBodyUploadProgress(
+ [](Server &svr) {
+ svr.Patch("/test", [](const Request & /*req*/, Response &res) {
+ res.set_content("patch received", "text/plain");
+ });
+ },
+ [](Client &cli, const string &body, UploadProgress progress_callback) {
+ return cli.Patch("/test", body, "text/plain", progress_callback);
+ },
+ "patch test data for upload progress");
+}
+
+// Helper function for content provider upload progress tests
+template <typename SetupHandler, typename ClientCall>
+void TestContentProviderUploadProgress(SetupHandler &&setup_handler,
+ ClientCall &&client_call) {
+ Server svr;
+ setup_handler(svr);
+
+ thread t = thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ });
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ vector<uint64_t> progress_values;
+
+ auto res =
+ client_call(cli, [&](uint64_t current, uint64_t /*total*/) -> bool {
+ progress_values.push_back(current);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(200, res->status);
+ EXPECT_FALSE(progress_values.empty());
+}
+
+TEST(UploadProgressTest, PostContentProviderProgress) {
+ TestContentProviderUploadProgress(
+ [](Server &svr) {
+ svr.Post("/test", [](const Request & /*req*/, Response &res) {
+ res.set_content("provider received", "text/plain");
+ });
+ },
+ [](Client &cli, UploadProgress progress_callback) {
+ return cli.Post(
+ "/test", 10,
+ [](size_t /*offset*/, size_t /*length*/, DataSink &sink) -> bool {
+ sink.os << "test data";
+ return true;
+ },
+ "text/plain", progress_callback);
+ });
+}
+
+// Helper function for multipart upload progress tests
+template <typename SetupHandler, typename ClientCall>
+void TestMultipartUploadProgress(SetupHandler &&setup_handler,
+ ClientCall &&client_call,
+ const string &endpoint) {
+ Server svr;
+ setup_handler(svr);
+
+ thread t = thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ });
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ vector<uint64_t> progress_values;
+
+ UploadFormDataItems items = {
+ {"field1", "value1", "", ""},
+ {"field2", "longer value for progress tracking test", "", ""},
+ {"file1", "file content data for upload progress", "test.txt",
+ "text/plain"}};
+
+ auto res = client_call(cli, endpoint, items,
+ [&](uint64_t current, uint64_t /*total*/) -> bool {
+ progress_values.push_back(current);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(200, res->status);
+ EXPECT_FALSE(progress_values.empty());
+}
+
+TEST(UploadProgressTest, PostMultipartProgress) {
+ TestMultipartUploadProgress(
+ [](Server &svr) {
+ svr.Post("/multipart", [](const Request &req, Response &res) {
+ EXPECT_TRUE(!req.form.files.empty() || !req.form.fields.empty());
+ res.set_content("multipart received", "text/plain");
+ });
+ },
+ [](Client &cli, const string &endpoint, const UploadFormDataItems &items,
+ UploadProgress progress_callback) {
+ return cli.Post(endpoint, items, progress_callback);
+ },
+ "/multipart");
+}
+
+// Helper function for basic download progress tests
+template <typename SetupHandler, typename ClientCall>
+void TestBasicDownloadProgress(SetupHandler &&setup_handler,
+ ClientCall &&client_call, const string &endpoint,
+ size_t expected_content_size) {
+ Server svr;
+ setup_handler(svr);
+
+ thread t = thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ });
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ vector<uint64_t> progress_values;
+
+ auto res = client_call(cli, endpoint,
+ [&](uint64_t current, uint64_t /*total*/) -> bool {
+ progress_values.push_back(current);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(200, res->status);
+ EXPECT_FALSE(progress_values.empty());
+ EXPECT_EQ(expected_content_size, res->body.size());
+}
+
+TEST(DownloadProgressTest, GetBasic) {
+ TestBasicDownloadProgress(
+ [](Server &svr) {
+ svr.Get("/download", [](const Request & /*req*/, Response &res) {
+ string content(1000, 'D');
+ res.set_content(content, "text/plain");
+ });
+ },
+ [](Client &cli, const string &endpoint,
+ DownloadProgress progress_callback) {
+ return cli.Get(endpoint, progress_callback);
+ },
+ "/download", 1000u);
+}
+
+// Helper function for content receiver download progress tests
+template <typename SetupHandler, typename ClientCall>
+void TestContentReceiverDownloadProgress(SetupHandler &&setup_handler,
+ ClientCall &&client_call,
+ const string &endpoint,
+ size_t expected_content_size) {
+ Server svr;
+ setup_handler(svr);
+
+ thread t = thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ });
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ vector<uint64_t> progress_values;
+ string received_body;
+
+ auto res = client_call(
+ cli, endpoint,
+ [&](const char *data, size_t data_length) -> bool {
+ received_body.append(data, data_length);
+ return true;
+ },
+ [&](uint64_t current, uint64_t /*total*/) -> bool {
+ progress_values.push_back(current);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(200, res->status);
+ EXPECT_FALSE(progress_values.empty());
+ EXPECT_EQ(expected_content_size, received_body.size());
+ EXPECT_TRUE(res->body.empty());
+}
+
+TEST(DownloadProgressTest, GetWithContentReceiver) {
+ TestContentReceiverDownloadProgress(
+ [](Server &svr) {
+ svr.Get("/download-receiver",
+ [](const Request & /*req*/, Response &res) {
+ string content(2000, 'R');
+ res.set_content(content, "text/plain");
+ });
+ },
+ [](Client &cli, const string &endpoint, ContentReceiver content_receiver,
+ DownloadProgress progress_callback) {
+ return cli.Get(endpoint, content_receiver, progress_callback);
+ },
+ "/download-receiver", 2000u);
+}
+
+TEST(StreamingTest, NoContentLengthStreaming) {
+ Server svr;
+
+ svr.Get("/stream", [](const Request & /*req*/, Response &res) {
+ res.set_content_provider("text/plain", [](size_t offset, DataSink &sink) {
+ if (offset < 6) {
+ sink.os << (offset < 3 ? "a" : "b");
+ } else {
+ sink.done();
+ }
+ return true;
+ });
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto listen_se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client client(HOST, PORT);
+
+ auto get_thread = std::thread([&client]() {
+ std::string s;
+ auto res =
+ client.Get("/stream", [&s](const char *data, size_t len) -> bool {
+ s += std::string(data, len);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("aaabbb", s);
+ });
+ auto get_se = detail::scope_exit([&] { get_thread.join(); });
+
+ // Give GET time to get a few messages.
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+}
+
+TEST(MountTest, Unmount) {
+ Server svr;
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ svr.set_mount_point("/mount2", "./www2");
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+
+ res = cli.Get("/mount2/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+
+ svr.set_mount_point("/", "./www");
+
+ res = cli.Get("/dir/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+
+ svr.remove_mount_point("/");
+ res = cli.Get("/dir/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+
+ svr.remove_mount_point("/mount2");
+ res = cli.Get("/mount2/dir/test.html");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+}
+
+TEST(MountTest, Redicect) {
+ Server svr;
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.set_mount_point("/", "./www");
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ auto res = cli.Get("/dir/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli.Get("/dir");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
+
+ res = cli.Get("/file");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+
+ res = cli.Get("/file/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+
+ cli.set_follow_location(true);
+ res = cli.Get("/dir");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(MountTest, MultibytesPathName) {
+ Server svr;
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.set_mount_point("/", "./www");
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ auto res = cli.Get(u8"/日本語Dir/日本語File.txt");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(u8"日本語コンテンツ", res->body);
+}
+
+TEST(KeepAliveTest, ReadTimeout) {
+ Server svr;
+
+ svr.Get("/a", [&](const Request & /*req*/, Response &res) {
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ res.set_content("a", "text/plain");
+ });
+
+ svr.Get("/b", [&](const Request & /*req*/, Response &res) {
+ res.set_content("b", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+ cli.set_keep_alive(true);
+ cli.set_read_timeout(std::chrono::seconds(1));
+
+ auto resa = cli.Get("/a");
+ ASSERT_FALSE(resa);
+ EXPECT_EQ(Error::Read, resa.error());
+
+ auto resb = cli.Get("/b");
+ ASSERT_TRUE(resb);
+ EXPECT_EQ(StatusCode::OK_200, resb->status);
+ EXPECT_EQ("b", resb->body);
+}
+
+TEST(KeepAliveTest, MaxCount) {
+ size_t keep_alive_max_count = 3;
+
+ Server svr;
+ svr.set_keep_alive_max_count(keep_alive_max_count);
+
+ svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_keep_alive(true);
+
+ for (size_t i = 0; i < 5; i++) {
+ auto result = cli.Get("/hi");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(StatusCode::OK_200, result->status);
+
+ if (i == keep_alive_max_count - 1) {
+ EXPECT_EQ("close", result->get_header_value("Connection"));
+ } else {
+ EXPECT_FALSE(result->has_header("Connection"));
+ }
+ }
+}
+
+TEST(KeepAliveTest, Issue1041) {
+ Server svr;
+ svr.set_keep_alive_timeout(3);
+
+ svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.set_keep_alive(true);
+
+ auto result = cli.Get("/hi");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(StatusCode::OK_200, result->status);
+
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+
+ result = cli.Get("/hi");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(StatusCode::OK_200, result->status);
+}
+
+TEST(KeepAliveTest, Issue1959) {
+ Server svr;
+ svr.set_keep_alive_timeout(5);
+
+ svr.Get("/a", [&](const Request & /*req*/, Response &res) {
+ res.set_content("a", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ if (!svr.is_running()) return;
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+ cli.set_keep_alive(true);
+
+ using namespace std::chrono;
+ auto start = steady_clock::now();
+
+ cli.Get("/a");
+
+ svr.stop();
+ listen_thread.join();
+
+ auto end = steady_clock::now();
+ auto elapsed = duration_cast<milliseconds>(end - start).count();
+
+ EXPECT_LT(elapsed, 5000);
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(KeepAliveTest, SSLClientReconnection) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(svr.is_valid());
+ svr.set_keep_alive_timeout(1);
+
+ svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli(HOST, PORT);
+ cli.enable_server_certificate_verification(false);
+ cli.set_keep_alive(true);
+
+ auto result = cli.Get("/hi");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(StatusCode::OK_200, result->status);
+
+ result = cli.Get("/hi");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(StatusCode::OK_200, result->status);
+
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+
+ // Recoonect
+ result = cli.Get("/hi");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(StatusCode::OK_200, result->status);
+
+ result = cli.Get("/hi");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(StatusCode::OK_200, result->status);
+}
+
+TEST(KeepAliveTest, SSLClientReconnectionPost) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(svr.is_valid());
+ svr.set_keep_alive_timeout(1);
+ std::string content = "reconnect";
+
+ svr.Post("/hi", [](const httplib::Request &, httplib::Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli(HOST, PORT);
+ cli.enable_server_certificate_verification(false);
+ cli.set_keep_alive(true);
+
+ auto result = cli.Post(
+ "/hi", content.size(),
+ [&content](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ sink.write(content.c_str(), content.size());
+ return true;
+ },
+ "text/plain");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(200, result->status);
+
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+
+ // Recoonect
+ result = cli.Post(
+ "/hi", content.size(),
+ [&content](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ sink.write(content.c_str(), content.size());
+ return true;
+ },
+ "text/plain");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(200, result->status);
+
+ result = cli.Post(
+ "/hi", content.size(),
+ [&content](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
+ sink.write(content.c_str(), content.size());
+ return true;
+ },
+ "text/plain");
+ ASSERT_TRUE(result);
+ EXPECT_EQ(200, result->status);
+}
+
+TEST(SNI_AutoDetectionTest, SNI_Logic) {
+ {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/sni", [&](const Request &req, Response &res) {
+ std::string expected;
+ if (req.ssl) {
+ if (const char *sni =
+ SSL_get_servername(req.ssl, TLSEXT_NAMETYPE_host_name)) {
+ expected = sni;
+ }
+ }
+ EXPECT_EQ(expected, req.get_param_value("expected"));
+ res.set_content("ok", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ SSLClient cli("localhost", PORT);
+ cli.enable_server_certificate_verification(false);
+ auto res = cli.Get("/sni?expected=localhost");
+ ASSERT_TRUE(res);
+ }
+
+ {
+ SSLClient cli("::1", PORT);
+ cli.enable_server_certificate_verification(false);
+ auto res = cli.Get("/sni?expected=");
+ ASSERT_TRUE(res);
+ }
+ }
+}
+#endif
+
+TEST(ClientProblemDetectionTest, ContentProvider) {
+ Server svr;
+
+ size_t content_length = 1024 * 1024;
+
+ svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
+ res.set_content_provider(
+ content_length, "text/plain",
+ [&](size_t offset, size_t length, DataSink &sink) {
+ auto out_len = std::min(length, static_cast<size_t>(1024));
+ std::string out(out_len, '@');
+ sink.write(out.data(), out_len);
+ return offset < 4096;
+ },
+ [](bool success) { ASSERT_FALSE(success); });
+ });
+
+ svr.Get("/empty", [&](const Request & /*req*/, Response &res) {
+ res.set_content_provider(
+ 0, "text/plain",
+ [&](size_t /*offset*/, size_t /*length*/, DataSink & /*sink*/) -> bool {
+ EXPECT_TRUE(false);
+ return true;
+ },
+ [](bool success) { ASSERT_FALSE(success); });
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ {
+ auto res = cli.Get("/hi", [&](const char * /*data*/,
+ size_t /*data_length*/) { return false; });
+ ASSERT_FALSE(res);
+ }
+
+ {
+ auto res = cli.Get("/empty", [&](const char * /*data*/,
+ size_t /*data_length*/) { return false; });
+ ASSERT_TRUE(res);
+ }
+}
+
+TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
+ Server svr;
+
+ svr.set_error_handler([](Request const &, Response &res) -> void {
+ res.set_chunked_content_provider(
+ "text/plain", [](std::size_t const, DataSink &sink) -> bool {
+ sink.os << "hello";
+ sink.os << "world";
+ sink.done();
+ return true;
+ });
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::NotFound_404, res->status);
+ EXPECT_EQ("helloworld", res->body);
+}
+
+TEST(LongPollingTest, ClientCloseDetection) {
+ Server svr;
+
+ svr.Get("/events", [&](const Request & /*req*/, Response &res) {
+ res.set_chunked_content_provider(
+ "text/plain", [](std::size_t const, DataSink &sink) -> bool {
+ EXPECT_TRUE(sink.is_writable()); // the socket is alive
+ sink.os << "hello";
+
+ auto count = 10;
+ while (count > 0 && sink.is_writable()) {
+ this_thread::sleep_for(chrono::milliseconds(10));
+ count--;
+ }
+ EXPECT_FALSE(sink.is_writable()); // the socket is closed
+ return true;
+ });
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ auto res = cli.Get("/events", [&](const char *data, size_t data_length) {
+ EXPECT_EQ("hello", string(data, data_length));
+ return false; // close the socket immediately.
+ });
+
+ ASSERT_FALSE(res);
+}
+
+TEST(GetWithParametersTest, GetWithParameters) {
+ Server svr;
+
+ svr.Get("/", [&](const Request &req, Response &) {
+ EXPECT_EQ("world", req.get_param_value("hello"));
+ EXPECT_EQ("world2", req.get_param_value("hello2"));
+ EXPECT_EQ("world3", req.get_param_value("hello3"));
+ });
+
+ svr.Get("/params", [&](const Request &req, Response &) {
+ EXPECT_EQ("world", req.get_param_value("hello"));
+ EXPECT_EQ("world2", req.get_param_value("hello2"));
+ EXPECT_EQ("world3", req.get_param_value("hello3"));
+ });
+
+ svr.Get(R"(/resources/([a-z0-9\\-]+))", [&](const Request &req, Response &) {
+ EXPECT_EQ("resource-id", req.matches[1]);
+ EXPECT_EQ("foo", req.get_param_value("param1"));
+ EXPECT_EQ("bar", req.get_param_value("param2"));
+ });
+
+ svr.Get("/users/:id", [&](const Request &req, Response &) {
+ EXPECT_EQ("user-id", req.path_params.at("id"));
+ EXPECT_EQ("foo", req.get_param_value("param1"));
+ EXPECT_EQ("bar", req.get_param_value("param2"));
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+
+ Params params;
+ params.emplace("hello", "world");
+ params.emplace("hello2", "world2");
+ params.emplace("hello3", "world3");
+ auto res = cli.Get("/", params, Headers{});
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ Client cli(HOST, PORT);
+
+ auto res = cli.Get("/params?hello=world&hello2=world2&hello3=world3");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ Client cli(HOST, PORT);
+
+ auto res = cli.Get("/resources/resource-id?param1=foo&param2=bar");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ Client cli(HOST, PORT);
+
+ auto res = cli.Get("/users/user-id?param1=foo&param2=bar");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+}
+
+TEST(GetWithParametersTest, GetWithParameters2) {
+ Server svr;
+
+ svr.Get("/", [&](const Request &req, Response &res) {
+ auto text = req.get_param_value("hello");
+ res.set_content(text, "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ Params params;
+ params.emplace("hello", "world");
+
+ std::string body;
+ auto res = cli.Get("/", params, Headers{},
+ [&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("world", body);
+}
+
+TEST(ClientDefaultHeadersTest, DefaultHeaders_Online) {
+#ifdef CPPHTTPLIB_DEFAULT_HTTPBIN
+ auto host = "httpbin.org";
+ auto path = std::string{"/range/32"};
+#else
+ auto host = "nghttp2.org";
+ auto path = std::string{"/httpbin/range/32"};
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli(host);
+#else
+ Client cli(host);
+#endif
+
+ cli.set_default_headers({make_range_header({{1, 10}})});
+ cli.set_connection_timeout(5);
+
+ {
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res);
+ EXPECT_EQ("bcdefghijk", res->body);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ }
+
+ {
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res);
+ EXPECT_EQ("bcdefghijk", res->body);
+ EXPECT_EQ(StatusCode::PartialContent_206, res->status);
+ }
+}
+
+TEST(ServerDefaultHeadersTest, DefaultHeaders) {
+ Server svr;
+ svr.set_default_headers({{"Hello", "World"}});
+
+ svr.Get("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content("ok", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli("localhost", PORT);
+
+ auto res = cli.Get("/");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("ok", res->body);
+ EXPECT_EQ("World", res->get_header_value("Hello"));
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(KeepAliveTest, ReadTimeoutSSL) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/a", [&](const Request & /*req*/, Response &res) {
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ res.set_content("a", "text/plain");
+ });
+
+ svr.Get("/b", [&](const Request & /*req*/, Response &res) {
+ res.set_content("b", "text/plain");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli("localhost", PORT);
+ cli.enable_server_certificate_verification(false);
+ cli.set_keep_alive(true);
+ cli.set_read_timeout(std::chrono::seconds(1));
+
+ auto resa = cli.Get("/a");
+ ASSERT_TRUE(!resa);
+ EXPECT_EQ(Error::Read, resa.error());
+
+ auto resb = cli.Get("/b");
+ ASSERT_TRUE(resb);
+ EXPECT_EQ(StatusCode::OK_200, resb->status);
+ EXPECT_EQ("b", resb->body);
+}
+#endif
+
+class ServerTestWithAI_PASSIVE : public ::testing::Test {
+protected:
+ ServerTestWithAI_PASSIVE()
+ : cli_(HOST, PORT)
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ ,
+ svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
+#endif
+ {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli_.enable_server_certificate_verification(false);
+#endif
+ }
+
+ virtual void SetUp() {
+ svr_.Get("/hi", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Hello World!", "text/plain");
+ });
+
+ t_ = thread(
+ [&]() { ASSERT_TRUE(svr_.listen(std::string(), PORT, AI_PASSIVE)); });
+
+ svr_.wait_until_ready();
+ }
+
+ virtual void TearDown() {
+ svr_.stop();
+ t_.join();
+ }
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli_;
+ SSLServer svr_;
+#else
+ Client cli_;
+ Server svr_;
+#endif
+ thread t_;
+};
+
+TEST_F(ServerTestWithAI_PASSIVE, GetMethod200) {
+ auto res = cli_.Get("/hi");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+ EXPECT_EQ("Hello World!", res->body);
+}
+
+class ServerUpDownTest : public ::testing::Test {
+protected:
+ ServerUpDownTest() : cli_(HOST, PORT) {}
+
+ virtual void SetUp() {
+ t_ = thread([&]() {
+ svr_.bind_to_any_port(HOST);
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ ASSERT_TRUE(svr_.listen_after_bind());
+ });
+
+ svr_.wait_until_ready();
+ }
+
+ virtual void TearDown() {
+ svr_.stop();
+ t_.join();
+ }
+
+ Client cli_;
+ Server svr_;
+ thread t_;
+};
+
+TEST_F(ServerUpDownTest, QuickStartStop) {
+ // Should not crash, especially when run with
+ // --gtest_filter=ServerUpDownTest.QuickStartStop --gtest_repeat=1000
+}
+
+class PayloadMaxLengthTest : public ::testing::Test {
+protected:
+ PayloadMaxLengthTest()
+ : cli_(HOST, PORT)
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ ,
+ svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
+#endif
+ {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli_.enable_server_certificate_verification(false);
+#endif
+ }
+
+ virtual void SetUp() {
+ svr_.set_payload_max_length(8);
+
+ svr_.Post("/test", [&](const Request & /*req*/, Response &res) {
+ res.set_content("test", "text/plain");
+ });
+
+ t_ = thread([&]() { ASSERT_TRUE(svr_.listen(HOST, PORT)); });
+
+ svr_.wait_until_ready();
+ }
+
+ virtual void TearDown() {
+ svr_.stop();
+ t_.join();
+ }
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli_;
+ SSLServer svr_;
+#else
+ Client cli_;
+ Server svr_;
+#endif
+ thread t_;
+};
+
+TEST_F(PayloadMaxLengthTest, ExceedLimit) {
+ auto res = cli_.Post("/test", "123456789", "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PayloadTooLarge_413, res->status);
+
+ res = cli_.Post("/test", "12345678", "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(PayloadMaxLengthTest, ChunkedEncodingSecurityTest) {
+ // Test chunked encoding with payload exceeding the 8-byte limit
+ std::string large_chunked_data(16, 'A'); // 16 bytes, exceeds 8-byte limit
+
+ auto res = cli_.Post("/test", large_chunked_data, "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PayloadTooLarge_413, res->status);
+}
+
+TEST_F(PayloadMaxLengthTest, ChunkedEncodingWithinLimit) {
+ // Test chunked encoding with payload within the 8-byte limit
+ std::string small_chunked_data(4, 'B'); // 4 bytes, within 8-byte limit
+
+ auto res = cli_.Post("/test", small_chunked_data, "text/plain");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(PayloadMaxLengthTest, RawSocketChunkedTest) {
+ // Test using send_request to send chunked data exceeding payload limit
+ std::string chunked_request = "POST /test HTTP/1.1\r\n"
+ "Host: " +
+ std::string(HOST) + ":" + std::to_string(PORT) +
+ "\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "Connection: close\r\n"
+ "\r\n"
+ "a\r\n" // 10 bytes chunk (exceeds 8-byte limit)
+ "0123456789\r\n"
+ "0\r\n" // End chunk
+ "\r\n";
+
+ std::string response;
+ bool result = send_request(1, chunked_request, &response);
+
+ if (!result) {
+ // If send_request fails, it might be because the server closed the
+ // connection due to payload limit enforcement, which is acceptable
+ SUCCEED()
+ << "Server rejected oversized chunked request (connection closed)";
+ } else {
+ // If we got a response, check if it's an error response or connection was
+ // closed early Short response length indicates connection was closed due to
+ // payload limit
+ if (response.length() <= 10) {
+ SUCCEED() << "Server closed connection for oversized chunked request";
+ } else {
+ // Check for error status codes
+ EXPECT_TRUE(response.find("413") != std::string::npos ||
+ response.find("Payload Too Large") != std::string::npos ||
+ response.find("400") != std::string::npos);
+ }
+ }
+}
+
+TEST_F(PayloadMaxLengthTest, NoContentLengthPayloadLimit) {
+ // Test request without Content-Length header exceeding payload limit
+ std::string request_without_content_length = "POST /test HTTP/1.1\r\n"
+ "Host: " +
+ std::string(HOST) + ":" +
+ std::to_string(PORT) +
+ "\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ // Add payload exceeding the 8-byte limit
+ std::string large_payload(16, 'X'); // 16 bytes, exceeds 8-byte limit
+ request_without_content_length += large_payload;
+
+ std::string response;
+ bool result = send_request(1, request_without_content_length, &response);
+
+ if (!result) {
+ // If send_request fails, server likely closed connection due to payload
+ // limit
+ SUCCEED() << "Server rejected oversized request without Content-Length "
+ "(connection closed)";
+ } else {
+ // Check if server responded with error or closed connection early
+ if (response.length() <= 10) {
+ SUCCEED() << "Server closed connection for oversized request without "
+ "Content-Length";
+ } else {
+ // Check for error status codes
+ EXPECT_TRUE(response.find("413") != std::string::npos ||
+ response.find("Payload Too Large") != std::string::npos ||
+ response.find("400") != std::string::npos);
+ }
+ }
+}
+
+TEST_F(PayloadMaxLengthTest, NoContentLengthWithinLimit) {
+ // Test request without Content-Length header within payload limit
+ std::string request_without_content_length = "POST /test HTTP/1.1\r\n"
+ "Host: " +
+ std::string(HOST) + ":" +
+ std::to_string(PORT) +
+ "\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ // Add payload within the 8-byte limit
+ std::string small_payload(4, 'Y'); // 4 bytes, within 8-byte limit
+ request_without_content_length += small_payload;
+
+ std::string response;
+ bool result = send_request(1, request_without_content_length, &response);
+
+ // For requests without Content-Length, the server may have different behavior
+ // The key is that it should not reject due to payload limit for small
+ // payloads
+ if (result) {
+ // Check for any HTTP response (success or error, but not connection closed)
+ if (response.length() > 10) {
+ SUCCEED()
+ << "Server processed request without Content-Length within limit";
+ } else {
+ // Short response might indicate connection closed, which is acceptable
+ SUCCEED() << "Server closed connection for request without "
+ "Content-Length (acceptable behavior)";
+ }
+ } else {
+ // Connection failure might be due to protocol requirements
+ SUCCEED() << "Connection issue with request without Content-Length "
+ "(environment-specific)";
+ }
+}
+
+class LargePayloadMaxLengthTest : public ::testing::Test {
+protected:
+ LargePayloadMaxLengthTest()
+ : cli_(HOST, PORT)
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ ,
+ svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
+#endif
+ {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli_.enable_server_certificate_verification(false);
+#endif
+ }
+
+ virtual void SetUp() {
+ // Set 10MB payload limit
+ const size_t LARGE_PAYLOAD_LIMIT = 10 * 1024 * 1024; // 10MB
+ svr_.set_payload_max_length(LARGE_PAYLOAD_LIMIT);
+
+ svr_.Post("/test", [&](const Request & /*req*/, Response &res) {
+ res.set_content("Large payload test", "text/plain");
+ });
+
+ t_ = thread([&]() { ASSERT_TRUE(svr_.listen(HOST, PORT)); });
+ svr_.wait_until_ready();
+ }
+
+ virtual void TearDown() {
+ svr_.stop();
+ t_.join();
+ }
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSLClient cli_;
+ SSLServer svr_;
+#else
+ Client cli_;
+ Server svr_;
+#endif
+ thread t_;
+};
+
+TEST_F(LargePayloadMaxLengthTest, ChunkedEncodingWithin10MB) {
+ // Test chunked encoding with payload within 10MB limit
+ std::string medium_payload(5 * 1024 * 1024,
+ 'A'); // 5MB payload, within 10MB limit
+
+ auto res = cli_.Post("/test", medium_payload, "application/octet-stream");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST_F(LargePayloadMaxLengthTest, ChunkedEncodingExceeds10MB) {
+ // Test chunked encoding with payload exceeding 10MB limit
+ std::string large_payload(12 * 1024 * 1024,
+ 'B'); // 12MB payload, exceeds 10MB limit
+
+ auto res = cli_.Post("/test", large_payload, "application/octet-stream");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::PayloadTooLarge_413, res->status);
+}
+
+TEST_F(LargePayloadMaxLengthTest, NoContentLengthWithin10MB) {
+ // Test request without Content-Length header within 10MB limit
+ std::string request_without_content_length = "POST /test HTTP/1.1\r\n"
+ "Host: " +
+ std::string(HOST) + ":" +
+ std::to_string(PORT) +
+ "\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ // Add 1MB payload (within 10MB limit)
+ std::string medium_payload(1024 * 1024, 'C'); // 1MB payload
+ request_without_content_length += medium_payload;
+
+ std::string response;
+ bool result = send_request(5, request_without_content_length, &response);
+
+ if (result) {
+ // Should get a proper HTTP response for payloads within limit
+ if (response.length() > 10) {
+ SUCCEED() << "Server processed 1MB request without Content-Length within "
+ "10MB limit";
+ } else {
+ SUCCEED() << "Server closed connection (acceptable behavior for no "
+ "Content-Length)";
+ }
+ } else {
+ SUCCEED() << "Connection issue with 1MB payload (environment-specific)";
+ }
+}
+
+TEST_F(LargePayloadMaxLengthTest, NoContentLengthExceeds10MB) {
+ // Test request without Content-Length header exceeding 10MB limit
+ std::string request_without_content_length = "POST /test HTTP/1.1\r\n"
+ "Host: " +
+ std::string(HOST) + ":" +
+ std::to_string(PORT) +
+ "\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ // Add 12MB payload (exceeds 10MB limit)
+ std::string large_payload(12 * 1024 * 1024, 'D'); // 12MB payload
+ request_without_content_length += large_payload;
+
+ std::string response;
+ bool result = send_request(10, request_without_content_length, &response);
+
+ if (!result) {
+ // Server should close connection due to payload limit
+ SUCCEED() << "Server rejected 12MB request without Content-Length "
+ "(connection closed)";
+ } else {
+ // Check for error response
+ if (response.length() <= 10) {
+ SUCCEED()
+ << "Server closed connection for 12MB request exceeding 10MB limit";
+ } else {
+ EXPECT_TRUE(response.find("413") != std::string::npos ||
+ response.find("Payload Too Large") != std::string::npos ||
+ response.find("400") != std::string::npos);
+ }
+ }
+}
+
+TEST(HostAndPortPropertiesTest, NoSSL) {
+ httplib::Client cli("www.google.com", 1234);
+ ASSERT_EQ("www.google.com", cli.host());
+ ASSERT_EQ(1234, cli.port());
+}
+
+TEST(HostAndPortPropertiesTest, NoSSLWithSimpleAPI) {
+ httplib::Client cli("www.google.com:1234");
+ ASSERT_EQ("www.google.com", cli.host());
+ ASSERT_EQ(1234, cli.port());
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(HostAndPortPropertiesTest, SSL) {
+ httplib::SSLClient cli("www.google.com");
+ ASSERT_EQ("www.google.com", cli.host());
+ ASSERT_EQ(443, cli.port());
+}
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(SSLClientTest, UpdateCAStore) {
+ httplib::SSLClient httplib_client("www.google.com");
+ auto ca_store_1 = X509_STORE_new();
+ X509_STORE_load_locations(ca_store_1, "/etc/ssl/certs/ca-certificates.crt",
+ nullptr);
+ httplib_client.set_ca_cert_store(ca_store_1);
+
+ auto ca_store_2 = X509_STORE_new();
+ X509_STORE_load_locations(ca_store_2, "/etc/ssl/certs/ca-certificates.crt",
+ nullptr);
+ httplib_client.set_ca_cert_store(ca_store_2);
+}
+
+TEST(SSLClientTest, ServerNameIndication_Online) {
+#ifdef CPPHTTPLIB_DEFAULT_HTTPBIN
+ auto host = "httpbin.org";
+ auto path = std::string{"/get"};
+#else
+ auto host = "nghttp2.org";
+ auto path = std::string{"/httpbin/get"};
+#endif
+
+ SSLClient cli(host, 443);
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(SSLClientTest, ServerCertificateVerificationError_Online) {
+ // Use a site that will cause SSL verification failure due to self-signed cert
+ SSLClient cli("self-signed.badssl.com", 443);
+ cli.enable_server_certificate_verification(true);
+ auto res = cli.Get("/");
+
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::SSLServerVerification, res.error());
+
+ // For SSL server verification errors, ssl_error should be 0, only
+ // ssl_openssl_error should be set
+ EXPECT_EQ(0, res.ssl_error());
+
+ // Verify OpenSSL error is captured for SSLServerVerification
+ // This occurs when SSL_get_verify_result() returns a verification failure
+ EXPECT_EQ(static_cast<unsigned long>(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT),
+ res.ssl_openssl_error());
+}
+
+TEST(SSLClientTest, ServerHostnameVerificationError_Online) {
+ // Use a site where hostname doesn't match the certificate
+ // badssl.com provides wrong.host.badssl.com which has cert for *.badssl.com
+ SSLClient cli("wrong.host.badssl.com", 443);
+ cli.enable_server_certificate_verification(true);
+ cli.enable_server_hostname_verification(true);
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(!res);
+
+ EXPECT_EQ(Error::SSLServerHostnameVerification, res.error());
+
+ // For SSL hostname verification errors, ssl_error should be 0, only
+ // ssl_openssl_error should be set
+ EXPECT_EQ(0, res.ssl_error());
+
+ // Verify OpenSSL error is captured for SSLServerHostnameVerification
+ // This occurs when verify_host() fails due to hostname mismatch
+ EXPECT_EQ(static_cast<unsigned long>(X509_V_ERR_HOSTNAME_MISMATCH),
+ res.ssl_openssl_error());
+}
+
+TEST(SSLClientTest, ServerCertificateVerification1_Online) {
+ Client cli("https://google.com");
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::MovedPermanently_301, res->status);
+}
+
+TEST(SSLClientTest, ServerCertificateVerification2_Online) {
+ SSLClient cli("google.com");
+ cli.set_ca_cert_path(CA_CERT_FILE);
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::MovedPermanently_301, res->status);
+}
+
+TEST(SSLClientTest, ServerCertificateVerification3_Online) {
+ SSLClient cli("google.com");
+ cli.enable_server_certificate_verification(true);
+ cli.set_ca_cert_path("hello");
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::SSLLoadingCerts, res.error());
+
+ // For SSL_CTX operations, ssl_error should be 0, only ssl_openssl_error
+ // should be set
+ EXPECT_EQ(0, res.ssl_error());
+
+ // Verify OpenSSL error is captured for SSLLoadingCerts
+ // This error occurs when SSL_CTX_load_verify_locations() fails
+ // > openssl errstr 0x80000002
+ // error:80000002:system library::No such file or directory
+ // > openssl errstr 0xA000126
+ // error:0A000126:SSL routines::unexpected eof while reading
+ EXPECT_TRUE(res.ssl_openssl_error() == 0x80000002 ||
+ res.ssl_openssl_error() == 0xA000126);
+}
+
+TEST(SSLClientTest, ServerCertificateVerification4) {
+ SSLServer svr(SERVER_CERT2_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/test", [&](const Request &, Response &res) {
+ res.set_content("test", "text/plain");
+ svr.stop();
+ ASSERT_TRUE(true);
+ });
+
+ thread t = thread([&]() { ASSERT_TRUE(svr.listen("127.0.0.1", PORT)); });
+ auto se = detail::scope_exit([&] {
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli("127.0.0.1", PORT);
+ cli.set_ca_cert_path(SERVER_CERT2_FILE);
+ cli.enable_server_certificate_verification(true);
+ cli.set_connection_timeout(30);
+
+ auto res = cli.Get("/test");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(SSLClientTest, ServerCertificateVerification5_Online) {
+ std::string cert;
+ read_file(CA_CERT_FILE, cert);
+
+ SSLClient cli("google.com");
+ cli.load_ca_cert_store(cert.data(), cert.size());
+ const auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::MovedPermanently_301, res->status);
+}
+
+TEST(SSLClientTest, ServerCertificateVerification6_Online) {
+ // clang-format off
+ static constexpr char cert[] =
+ "GlobalSign Root CA\n"
+ "==================\n"
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\n"
+ "GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\n"
+ "b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\n"
+ "BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\n"
+ "VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\n"
+ "DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\n"
+ "THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\n"
+ "Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\n"
+ "c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\n"
+ "gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
+ "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\n"
+ "AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\n"
+ "Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\n"
+ "j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\n"
+ "hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\n"
+ "X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"
+ "-----END CERTIFICATE-----\n";
+ // clang-format on
+
+ SSLClient cli("google.com");
+ cli.load_ca_cert_store(cert, sizeof(cert));
+ const auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::MovedPermanently_301, res->status);
+}
+
+TEST(SSLClientTest, WildcardHostNameMatch_Online) {
+ SSLClient cli("www.youtube.com");
+
+ cli.set_ca_cert_path(CA_CERT_FILE);
+ cli.enable_server_certificate_verification(true);
+ cli.set_follow_location(true);
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(SSLClientTest, Issue2004_Online) {
+ Client client("https://google.com");
+ client.set_follow_location(true);
+
+ auto res = client.Get("/");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+
+ auto body = res->body;
+ EXPECT_EQ(body.substr(0, 15), "<!doctype html>");
+}
+
+#if 0
+TEST(SSLClientTest, SetInterfaceWithINET6) {
+ auto cli = std::make_shared<httplib::Client>("https://httpbin.org");
+ ASSERT_TRUE(cli != nullptr);
+
+ cli->set_address_family(AF_INET6);
+ cli->set_interface("en0");
+
+ auto res = cli->Get("/get");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+#endif
+
+void ClientCertPresent(
+ const std::string &client_cert_file,
+ const std::string &client_private_key_file,
+ const std::string &client_encrypted_private_key_pass = std::string()) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE,
+ CLIENT_CA_CERT_DIR);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/test", [&](const Request &req, Response &res) {
+ res.set_content("test", "text/plain");
+
+ auto peer_cert = SSL_get_peer_certificate(req.ssl);
+ ASSERT_TRUE(peer_cert != nullptr);
+
+ auto subject_name = X509_get_subject_name(peer_cert);
+ ASSERT_TRUE(subject_name != nullptr);
+
+ std::string common_name;
+ {
+ char name[BUFSIZ];
+ auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
+ name, sizeof(name));
+ common_name.assign(name, static_cast<size_t>(name_len));
+ }
+
+ EXPECT_EQ("Common Name", common_name);
+
+ X509_free(peer_cert);
+ });
+
+ thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli(HOST, PORT, client_cert_file, client_private_key_file,
+ client_encrypted_private_key_pass);
+ cli.enable_server_certificate_verification(false);
+ cli.set_connection_timeout(30);
+
+ auto res = cli.Get("/test");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(SSLClientServerTest, ClientCertPresent) {
+ ClientCertPresent(CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
+}
+
+TEST(SSLClientServerTest, ClientEncryptedCertPresent) {
+ ClientCertPresent(CLIENT_ENCRYPTED_CERT_FILE,
+ CLIENT_ENCRYPTED_PRIVATE_KEY_FILE,
+ CLIENT_ENCRYPTED_PRIVATE_KEY_PASS);
+}
+
+#if !defined(_WIN32) || defined(OPENSSL_USE_APPLINK)
+void MemoryClientCertPresent(
+ const std::string &client_cert_file,
+ const std::string &client_private_key_file,
+ const std::string &client_encrypted_private_key_pass = std::string()) {
+ auto f = fopen(SERVER_CERT_FILE, "r+");
+ auto server_cert = PEM_read_X509(f, nullptr, nullptr, nullptr);
+ fclose(f);
+
+ f = fopen(SERVER_PRIVATE_KEY_FILE, "r+");
+ auto server_private_key = PEM_read_PrivateKey(f, nullptr, nullptr, nullptr);
+ fclose(f);
+
+ f = fopen(CLIENT_CA_CERT_FILE, "r+");
+ auto client_cert = PEM_read_X509(f, nullptr, nullptr, nullptr);
+ auto client_ca_cert_store = X509_STORE_new();
+ X509_STORE_add_cert(client_ca_cert_store, client_cert);
+ X509_free(client_cert);
+ fclose(f);
+
+ f = fopen(client_cert_file.c_str(), "r+");
+ client_cert = PEM_read_X509(f, nullptr, nullptr, nullptr);
+ fclose(f);
+
+ f = fopen(client_private_key_file.c_str(), "r+");
+ auto client_private_key = PEM_read_PrivateKey(
+ f, nullptr, nullptr, (void *)client_encrypted_private_key_pass.c_str());
+ fclose(f);
+
+ SSLServer svr(server_cert, server_private_key, client_ca_cert_store);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/test", [&](const Request &req, Response &res) {
+ res.set_content("test", "text/plain");
+
+ auto peer_cert = SSL_get_peer_certificate(req.ssl);
+ ASSERT_TRUE(peer_cert != nullptr);
+
+ auto subject_name = X509_get_subject_name(peer_cert);
+ ASSERT_TRUE(subject_name != nullptr);
+
+ std::string common_name;
+ {
+ char name[BUFSIZ];
+ auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
+ name, sizeof(name));
+ common_name.assign(name, static_cast<size_t>(name_len));
+ }
+
+ EXPECT_EQ("Common Name", common_name);
+
+ X509_free(peer_cert);
+ });
+
+ thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli(HOST, PORT, client_cert, client_private_key,
+ client_encrypted_private_key_pass);
+ cli.enable_server_certificate_verification(false);
+ cli.set_connection_timeout(30);
+
+ auto res = cli.Get("/test");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+
+ X509_free(server_cert);
+ EVP_PKEY_free(server_private_key);
+ X509_free(client_cert);
+ EVP_PKEY_free(client_private_key);
+}
+
+TEST(SSLClientServerTest, MemoryClientCertPresent) {
+ MemoryClientCertPresent(CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
+}
+
+TEST(SSLClientServerTest, MemoryClientEncryptedCertPresent) {
+ MemoryClientCertPresent(CLIENT_ENCRYPTED_CERT_FILE,
+ CLIENT_ENCRYPTED_PRIVATE_KEY_FILE,
+ CLIENT_ENCRYPTED_PRIVATE_KEY_PASS);
+}
+#endif
+
+TEST(SSLClientServerTest, ClientCertMissing) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE,
+ CLIENT_CA_CERT_DIR);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/test", [&](const Request &, Response &) { ASSERT_TRUE(false); });
+
+ thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli(HOST, PORT);
+ cli.set_connection_timeout(30);
+
+ auto res = cli.Get("/test");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::SSLServerVerification, res.error());
+
+ // For SSL server verification errors, ssl_error should be 0, only
+ // ssl_openssl_error should be set
+ EXPECT_EQ(0, res.ssl_error());
+
+ // Verify OpenSSL error is captured for SSLServerVerification
+ // Note: This test may have different error codes depending on the exact
+ // verification failure
+ EXPECT_NE(0UL, res.ssl_openssl_error());
+}
+
+TEST(SSLClientServerTest, TrustDirOptional) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/test", [&](const Request &, Response &res) {
+ res.set_content("test", "text/plain");
+ });
+
+ thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
+ cli.enable_server_certificate_verification(false);
+ cli.set_connection_timeout(30);
+
+ auto res = cli.Get("/test");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(SSLClientServerTest, SSLConnectTimeout) {
+ class NoListenSSLServer : public SSLServer {
+ public:
+ NoListenSSLServer(const char *cert_path, const char *private_key_path,
+ const char *client_ca_cert_file_path,
+ const char *client_ca_cert_dir_path = nullptr)
+ : SSLServer(cert_path, private_key_path, client_ca_cert_file_path,
+ client_ca_cert_dir_path),
+ stop_(false) {}
+
+ std::atomic_bool stop_;
+
+ private:
+ bool process_and_close_socket(socket_t /*sock*/) override {
+ // Don't create SSL context
+ while (!stop_.load()) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+ return true;
+ }
+ };
+ NoListenSSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE,
+ CLIENT_CA_CERT_FILE);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/test", [&](const Request &, Response &res) {
+ res.set_content("test", "text/plain");
+ });
+
+ thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
+ auto se = detail::scope_exit([&] {
+ svr.stop_ = true;
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
+ cli.enable_server_certificate_verification(false);
+ cli.set_connection_timeout(1);
+
+ auto res = cli.Get("/test");
+ ASSERT_TRUE(!res);
+ EXPECT_EQ(Error::SSLConnection, res.error());
+ EXPECT_EQ(SSL_ERROR_WANT_READ, res.ssl_error());
+}
+
+TEST(SSLClientServerTest, CustomizeServerSSLCtx) {
+ auto setup_ssl_ctx_callback = [](SSL_CTX &ssl_ctx) {
+ SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_COMPRESSION);
+ SSL_CTX_set_options(&ssl_ctx,
+ SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+ SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_TLSv1);
+ SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_TLSv1_1);
+ auto ciphers = "ECDHE-RSA-AES128-SHA256:"
+ "ECDHE-DSS-AES128-SHA256:"
+ "ECDHE-RSA-AES256-SHA256:"
+ "ECDHE-DSS-AES256-SHA256:";
+ SSL_CTX_set_cipher_list(&ssl_ctx, ciphers);
+ if (SSL_CTX_use_certificate_chain_file(&ssl_ctx, SERVER_CERT_FILE) != 1 ||
+ SSL_CTX_use_PrivateKey_file(&ssl_ctx, SERVER_PRIVATE_KEY_FILE,
+ SSL_FILETYPE_PEM) != 1) {
+ return false;
+ }
+ SSL_CTX_load_verify_locations(&ssl_ctx, CLIENT_CA_CERT_FILE,
+ CLIENT_CA_CERT_DIR);
+ SSL_CTX_set_verify(
+ &ssl_ctx,
+ SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT, // SSL_VERIFY_CLIENT_ONCE,
+ nullptr);
+ return true;
+ };
+
+ SSLServer svr(setup_ssl_ctx_callback);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Get("/test", [&](const Request &req, Response &res) {
+ res.set_content("test", "text/plain");
+
+ auto peer_cert = SSL_get_peer_certificate(req.ssl);
+ ASSERT_TRUE(peer_cert != nullptr);
+
+ auto subject_name = X509_get_subject_name(peer_cert);
+ ASSERT_TRUE(subject_name != nullptr);
+
+ std::string common_name;
+ {
+ char name[BUFSIZ];
+ auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
+ name, sizeof(name));
+ common_name.assign(name, static_cast<size_t>(name_len));
+ }
+
+ EXPECT_EQ("Common Name", common_name);
+
+ X509_free(peer_cert);
+ });
+
+ thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
+ cli.enable_server_certificate_verification(false);
+ cli.set_connection_timeout(30);
+
+ auto res = cli.Get("/test");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+// Disabled due to the out-of-memory problem on GitHub Actions Workflows
+TEST(SSLClientServerTest, DISABLED_LargeDataTransfer) {
+
+ // prepare large data
+ std::random_device seed_gen;
+ std::mt19937 random(seed_gen());
+ constexpr auto large_size_byte = 2147483648UL + 1048576UL; // 2GiB + 1MiB
+ std::vector<std::uint32_t> binary(large_size_byte / sizeof(std::uint32_t));
+ std::generate(binary.begin(), binary.end(), [&random]() { return random(); });
+
+ // server
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(svr.is_valid());
+
+ svr.Post("/binary", [&](const Request &req, Response &res) {
+ EXPECT_EQ(large_size_byte, req.body.size());
+ EXPECT_EQ(0, std::memcmp(binary.data(), req.body.data(), large_size_byte));
+ res.set_content(req.body, "application/octet-stream");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ // client POST
+ SSLClient cli("localhost", PORT);
+ cli.enable_server_certificate_verification(false);
+ cli.set_read_timeout(std::chrono::seconds(100));
+ cli.set_write_timeout(std::chrono::seconds(100));
+ auto res = cli.Post("/binary", reinterpret_cast<char *>(binary.data()),
+ large_size_byte, "application/octet-stream");
+
+ // compare
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(large_size_byte, res->body.size());
+ EXPECT_EQ(0, std::memcmp(binary.data(), res->body.data(), large_size_byte));
+}
+#endif
+
+#ifdef _WIN32
+TEST(CleanupTest, WSACleanup) {
+ int ret = WSACleanup();
+ ASSERT_EQ(0, ret);
+}
+#endif
+
+#ifndef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(NoSSLSupport, SimpleInterface) {
+ ASSERT_ANY_THROW(Client cli("https://yahoo.com"));
+}
+#endif
+
+#ifndef CPPHTTPLIB_NO_EXCEPTIONS
+TEST(InvalidScheme, SimpleInterface) {
+ ASSERT_ANY_THROW(Client cli("scheme://yahoo.com"));
+}
+#endif
+
+TEST(NoScheme, SimpleInterface) {
+ Client cli("yahoo.com:80");
+ ASSERT_TRUE(cli.is_valid());
+}
+
+TEST(SendAPI, SimpleInterface_Online) {
+ Client cli("http://yahoo.com");
+
+ Request req;
+ req.method = "GET";
+ req.path = "/";
+ auto res = cli.send(req);
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
+}
+
+TEST(SendAPI, WithParamsInRequest) {
+ Server svr;
+
+ svr.Get("/", [&](const Request &req, Response & /*res*/) {
+ EXPECT_TRUE(req.has_param("test"));
+ EXPECT_EQ("test_value", req.get_param_value("test"));
+ });
+
+ auto t = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+
+ {
+ Request req;
+ req.method = "GET";
+ req.path = "/";
+ req.params.emplace("test", "test_value");
+ auto res = cli.send(req);
+ ASSERT_TRUE(res);
+ }
+ {
+ auto res = cli.Get("/", {{"test", "test_value"}}, Headers{});
+ ASSERT_TRUE(res);
+ }
+}
+
+TEST(ClientImplMethods, GetSocketTest) {
+ httplib::Server svr;
+ svr.Get("/", [&](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.status = StatusCode::OK_200;
+ });
+
+ auto thread = std::thread([&]() { svr.listen("127.0.0.1", 3333); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ httplib::Client cli("http://127.0.0.1:3333");
+ cli.set_keep_alive(true);
+
+ // Use the behavior of cpp-httplib of opening the connection
+ // only when the first request happens. If that changes,
+ // this test would be obsolete.
+
+ EXPECT_EQ(cli.socket(), INVALID_SOCKET);
+
+ // This also implicitly tests the server. But other tests would fail much
+ // earlier than this one to be considered.
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ ASSERT_TRUE(cli.socket() != INVALID_SOCKET);
+ }
+}
+
+// Disabled due to out-of-memory problem on GitHub Actions
+#ifdef _WIN64
+TEST(ServerLargeContentTest, DISABLED_SendLargeContent) {
+ // allocate content size larger than 2GB in memory
+ const size_t content_size = 2LL * 1024LL * 1024LL * 1024LL + 1LL;
+ char *content = (char *)malloc(content_size);
+ ASSERT_TRUE(content);
+
+ Server svr;
+ svr.Get("/foo",
+ [=](const httplib::Request & /*req*/, httplib::Response &res) {
+ res.set_content(content, content_size, "application/octet-stream");
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ if (content) free(content);
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ auto res = cli.Get("/foo");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(content_size, res->body.length());
+}
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(YahooRedirectTest2, SimpleInterface_Online) {
+ Client cli("http://yahoo.com");
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
+
+ cli.set_follow_location(true);
+ res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("https://www.yahoo.com/", res->location);
+}
+
+TEST(YahooRedirectTest3, SimpleInterface_Online) {
+ Client cli("https://yahoo.com");
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
+
+ cli.set_follow_location(true);
+ res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("https://www.yahoo.com/", res->location);
+}
+
+TEST(YahooRedirectTest3, NewResultInterface_Online) {
+ Client cli("https://yahoo.com");
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ ASSERT_FALSE(!res);
+ ASSERT_TRUE(res);
+ ASSERT_FALSE(res == nullptr);
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(Error::Success, res.error());
+ EXPECT_EQ(StatusCode::MovedPermanently_301, res.value().status);
+ EXPECT_EQ(StatusCode::MovedPermanently_301, (*res).status);
+ EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
+
+ cli.set_follow_location(true);
+ res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(Error::Success, res.error());
+ EXPECT_EQ(StatusCode::OK_200, res.value().status);
+ EXPECT_EQ(StatusCode::OK_200, (*res).status);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("https://www.yahoo.com/", res->location);
+}
+
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+TEST(DecodeWithChunkedEncoding, BrotliEncoding_Online) {
+ Client cli("https://cdnjs.cloudflare.com");
+ auto res =
+ cli.Get("/ajax/libs/jquery/3.5.1/jquery.js", {{"Accept-Encoding", "br"}});
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(287630U, res->body.size());
+ EXPECT_EQ("application/javascript; charset=utf-8",
+ res->get_header_value("Content-Type"));
+}
+#endif
+
+// Previously "https://nghttp2.org" "/httpbin/redirect-to"
+#undef REDIR_HOST // Silence compiler warning
+#define REDIR_HOST "https://httpbingo.org"
+
+TEST(HttpsToHttpRedirectTest, SimpleInterface_Online) {
+ Client cli(REDIR_HOST);
+ cli.set_follow_location(true);
+ auto res =
+ cli.Get(REDIR_PATH "?url=http%3A%2F%2Fexample.com&status_code=302");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(HttpsToHttpRedirectTest2, SimpleInterface_Online) {
+ Client cli(REDIR_HOST);
+ cli.set_follow_location(true);
+
+ Params params;
+ params.emplace("url", "http://example.com");
+ params.emplace("status_code", "302");
+
+ auto res = cli.Get(REDIR_PATH, params, Headers{});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(HttpsToHttpRedirectTest3, SimpleInterface_Online) {
+ Client cli(REDIR_HOST);
+ cli.set_follow_location(true);
+
+ Params params;
+ params.emplace("url", "http://example.com");
+
+ auto res = cli.Get(REDIR_PATH "?status_code=302", params, Headers{});
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(HttpToHttpsRedirectTest, CertFile) {
+ Server svr;
+ ASSERT_TRUE(svr.is_valid());
+ svr.Get("/index", [&](const Request &, Response &res) {
+ res.set_redirect("https://127.0.0.1:1235/index");
+ svr.stop();
+ });
+
+ SSLServer ssl_svr(SERVER_CERT2_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(ssl_svr.is_valid());
+ ssl_svr.Get("/index", [&](const Request &, Response &res) {
+ res.set_content("test", "text/plain");
+ ssl_svr.stop();
+ });
+
+ thread t = thread([&]() { ASSERT_TRUE(svr.listen("127.0.0.1", PORT)); });
+ thread t2 = thread([&]() { ASSERT_TRUE(ssl_svr.listen("127.0.0.1", 1235)); });
+ auto se = detail::scope_exit([&] {
+ t2.join();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+ ssl_svr.wait_until_ready();
+
+ Client cli("127.0.0.1", PORT);
+ cli.set_ca_cert_path(SERVER_CERT2_FILE);
+ cli.enable_server_certificate_verification(true);
+ cli.set_follow_location(true);
+ cli.set_connection_timeout(30);
+
+ auto res = cli.Get("/index");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(SSLClientRedirectTest, CertFile) {
+ SSLServer ssl_svr1(SERVER_CERT2_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(ssl_svr1.is_valid());
+ ssl_svr1.Get("/index", [&](const Request &, Response &res) {
+ res.set_redirect("https://127.0.0.1:1235/index");
+ ssl_svr1.stop();
+ });
+
+ SSLServer ssl_svr2(SERVER_CERT2_FILE, SERVER_PRIVATE_KEY_FILE);
+ ASSERT_TRUE(ssl_svr2.is_valid());
+ ssl_svr2.Get("/index", [&](const Request &, Response &res) {
+ res.set_content("test", "text/plain");
+ ssl_svr2.stop();
+ });
+
+ thread t = thread([&]() { ASSERT_TRUE(ssl_svr1.listen("127.0.0.1", PORT)); });
+ thread t2 =
+ thread([&]() { ASSERT_TRUE(ssl_svr2.listen("127.0.0.1", 1235)); });
+ auto se = detail::scope_exit([&] {
+ t2.join();
+ t.join();
+ ASSERT_FALSE(ssl_svr1.is_running());
+ });
+
+ ssl_svr1.wait_until_ready();
+ ssl_svr2.wait_until_ready();
+
+ SSLClient cli("127.0.0.1", PORT);
+ std::string cert;
+ read_file(SERVER_CERT2_FILE, cert);
+ cli.load_ca_cert_store(cert.c_str(), cert.size());
+ cli.enable_server_certificate_verification(true);
+ cli.set_follow_location(true);
+ cli.set_connection_timeout(30);
+
+ auto res = cli.Get("/index");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(MultipartFormDataTest, LargeData) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+
+ svr.Post("/post", [&](const Request &req, Response & /*res*/,
+ const ContentReader &content_reader) {
+ if (req.is_multipart_form_data()) {
+ std::vector<FormData> items;
+ content_reader(
+ [&](const FormData &file) {
+ items.push_back(file);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ items.back().content.append(data, data_length);
+ return true;
+ });
+
+ EXPECT_TRUE(std::string(items[0].name) == "document");
+ EXPECT_EQ(size_t(1024 * 1024 * 2), items[0].content.size());
+ EXPECT_TRUE(items[0].filename == "2MB_data");
+ EXPECT_TRUE(items[0].content_type == "application/octet-stream");
+
+ EXPECT_TRUE(items[1].name == "hello");
+ EXPECT_TRUE(items[1].content == "world");
+ EXPECT_TRUE(items[1].filename == "");
+ EXPECT_TRUE(items[1].content_type == "");
+ } else {
+ std::string body;
+ content_reader([&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+ }
+ });
+
+ auto t = std::thread([&]() { svr.listen("localhost", 8080); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ std::string data(1024 * 1024 * 2, '.');
+ std::stringstream buffer;
+ buffer << data;
+
+ Client cli("https://localhost:8080");
+ cli.enable_server_certificate_verification(false);
+
+ UploadFormDataItems items{
+ {"document", buffer.str(), "2MB_data", "application/octet-stream"},
+ {"hello", "world", "", ""},
+ };
+
+ auto res = cli.Post("/post", items);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ }
+}
+
+TEST(MultipartFormDataTest, DataProviderItems) {
+
+ std::random_device seed_gen;
+ std::mt19937 random(seed_gen());
+
+ std::string rand1;
+ rand1.resize(1000);
+ std::generate(rand1.begin(), rand1.end(), [&]() { return random(); });
+
+ std::string rand2;
+ rand2.resize(3000);
+ std::generate(rand2.begin(), rand2.end(), [&]() { return random(); });
+
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+
+ svr.Post("/post-none", [&](const Request &req, Response & /*res*/,
+ const ContentReader &content_reader) {
+ ASSERT_FALSE(req.is_multipart_form_data());
+
+ std::string body;
+ content_reader([&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+
+ EXPECT_EQ(body, "");
+ });
+
+ svr.Post("/post-items", [&](const Request &req, Response & /*res*/,
+ const ContentReader &content_reader) {
+ ASSERT_TRUE(req.is_multipart_form_data());
+ std::vector<FormData> items;
+ content_reader(
+ [&](const FormData &file) {
+ items.push_back(file);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ items.back().content.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(items.size() == 2);
+
+ EXPECT_EQ(std::string(items[0].name), "name1");
+ EXPECT_EQ(items[0].content, "Testing123");
+ EXPECT_EQ(items[0].filename, "filename1");
+ EXPECT_EQ(items[0].content_type, "application/octet-stream");
+
+ EXPECT_EQ(items[1].name, "name2");
+ EXPECT_EQ(items[1].content, "Testing456");
+ EXPECT_EQ(items[1].filename, "");
+ EXPECT_EQ(items[1].content_type, "");
+ });
+
+ svr.Post("/post-providers", [&](const Request &req, Response & /*res*/,
+ const ContentReader &content_reader) {
+ ASSERT_TRUE(req.is_multipart_form_data());
+ std::vector<FormData> items;
+ content_reader(
+ [&](const FormData &file) {
+ items.push_back(file);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ items.back().content.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(items.size() == 2);
+
+ EXPECT_EQ(items[0].name, "name3");
+ EXPECT_EQ(items[0].content, rand1);
+ EXPECT_EQ(items[0].filename, "filename3");
+ EXPECT_EQ(items[0].content_type, "");
+
+ EXPECT_EQ(items[1].name, "name4");
+ EXPECT_EQ(items[1].content, rand2);
+ EXPECT_EQ(items[1].filename, "filename4");
+ EXPECT_EQ(items[1].content_type, "");
+ });
+
+ svr.Post("/post-both", [&](const Request &req, Response & /*res*/,
+ const ContentReader &content_reader) {
+ ASSERT_TRUE(req.is_multipart_form_data());
+ std::vector<FormData> items;
+ content_reader(
+ [&](const FormData &file) {
+ items.push_back(file);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ items.back().content.append(data, data_length);
+ return true;
+ });
+
+ ASSERT_TRUE(items.size() == 4);
+
+ EXPECT_EQ(std::string(items[0].name), "name1");
+ EXPECT_EQ(items[0].content, "Testing123");
+ EXPECT_EQ(items[0].filename, "filename1");
+ EXPECT_EQ(items[0].content_type, "application/octet-stream");
+
+ EXPECT_EQ(items[1].name, "name2");
+ EXPECT_EQ(items[1].content, "Testing456");
+ EXPECT_EQ(items[1].filename, "");
+ EXPECT_EQ(items[1].content_type, "");
+
+ EXPECT_EQ(items[2].name, "name3");
+ EXPECT_EQ(items[2].content, rand1);
+ EXPECT_EQ(items[2].filename, "filename3");
+ EXPECT_EQ(items[2].content_type, "");
+
+ EXPECT_EQ(items[3].name, "name4");
+ EXPECT_EQ(items[3].content, rand2);
+ EXPECT_EQ(items[3].filename, "filename4");
+ EXPECT_EQ(items[3].content_type, "");
+ });
+
+ auto t = std::thread([&]() { svr.listen("localhost", 8080); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli("https://localhost:8080");
+ cli.enable_server_certificate_verification(false);
+
+ UploadFormDataItems items{
+ {"name1", "Testing123", "filename1", "application/octet-stream"},
+ {"name2", "Testing456", "", ""}, // not a file
+ };
+
+ {
+ auto res = cli.Post("/post-none", {}, {}, {});
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ FormDataProviderItems providers;
+
+ {
+ auto res =
+ cli.Post("/post-items", {}, items, providers); // empty providers
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ providers.push_back({"name3",
+ [&](size_t offset, httplib::DataSink &sink) -> bool {
+ // test the offset is given correctly at each step
+ if (!offset)
+ sink.os.write(rand1.data(), 30);
+ else if (offset == 30)
+ sink.os.write(rand1.data() + 30, 300);
+ else if (offset == 330)
+ sink.os.write(rand1.data() + 330, 670);
+ else if (offset == rand1.size())
+ sink.done();
+ return true;
+ },
+ "filename3",
+ {}});
+
+ providers.push_back({"name4",
+ [&](size_t offset, httplib::DataSink &sink) -> bool {
+ // test the offset is given correctly at each step
+ if (!offset)
+ sink.os.write(rand2.data(), 2000);
+ else if (offset == 2000)
+ sink.os.write(rand2.data() + 2000, 1);
+ else if (offset == 2001)
+ sink.os.write(rand2.data() + 2001, 999);
+ else if (offset == rand2.size())
+ sink.done();
+ return true;
+ },
+ "filename4",
+ {}});
+
+ {
+ auto res = cli.Post("/post-providers", {}, {}, providers);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ auto res = cli.Post("/post-both", {}, items, providers);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ }
+ }
+}
+
+TEST(MultipartFormDataTest, BadHeader) {
+ Server svr;
+ svr.Post("/post", [&](const Request & /*req*/, Response &res) {
+ res.set_content("ok", "text/plain");
+ });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ const std::string body =
+ "This is the preamble. It is to be ignored, though it\r\n"
+ "is a handy place for composition agents to include an\r\n"
+ "explanatory note to non-MIME conformant readers.\r\n"
+ "\r\n"
+ "\r\n"
+ "--simple boundary\r\n"
+ "Content-Disposition: form-data; name=\"field1\"\r\n"
+ ": BAD...\r\n"
+ "\r\n"
+ "value1\r\n"
+ "--simple boundary\r\n"
+ "Content-Disposition: form-data; name=\"field2\"; "
+ "filename=\"example.txt\"\r\n"
+ "\r\n"
+ "value2\r\n"
+ "--simple boundary--\r\n"
+ "This is the epilogue. It is also to be ignored.\r\n";
+
+ std::string content_type =
+ R"(multipart/form-data; boundary="simple boundary")";
+
+ Client cli(HOST, PORT);
+ auto res = cli.Post("/post", body, content_type.c_str());
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::BadRequest_400, res->status);
+}
+
+TEST(MultipartFormDataTest, WithPreamble) {
+ Server svr;
+ svr.Post("/post", [&](const Request & /*req*/, Response &res) {
+ res.set_content("ok", "text/plain");
+ });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ const std::string body =
+ "This is the preamble. It is to be ignored, though it\r\n"
+ "is a handy place for composition agents to include an\r\n"
+ "explanatory note to non-MIME conformant readers.\r\n"
+ "\r\n"
+ "\r\n"
+ "--simple boundary\r\n"
+ "Content-Disposition: form-data; name=\"field1\"\r\n"
+ "\r\n"
+ "value1\r\n"
+ "--simple boundary\r\n"
+ "Content-Disposition: form-data; name=\"field2\"; "
+ "filename=\"example.txt\"\r\n"
+ "\r\n"
+ "value2\r\n"
+ "--simple boundary--\r\n"
+ "This is the epilogue. It is also to be ignored.\r\n";
+
+ std::string content_type =
+ R"(multipart/form-data; boundary="simple boundary")";
+
+ Client cli(HOST, PORT);
+ auto res = cli.Post("/post", body, content_type.c_str());
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(MultipartFormDataTest, PostCustomBoundary) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+
+ svr.Post("/post_customboundary", [&](const Request &req, Response & /*res*/,
+ const ContentReader &content_reader) {
+ if (req.is_multipart_form_data()) {
+ std::vector<FormData> items;
+ content_reader(
+ [&](const FormData &file) {
+ items.push_back(file);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ items.back().content.append(data, data_length);
+ return true;
+ });
+
+ EXPECT_TRUE(std::string(items[0].name) == "document");
+ EXPECT_EQ(size_t(1024 * 1024 * 2), items[0].content.size());
+ EXPECT_TRUE(items[0].filename == "2MB_data");
+ EXPECT_TRUE(items[0].content_type == "application/octet-stream");
+
+ EXPECT_TRUE(items[1].name == "hello");
+ EXPECT_TRUE(items[1].content == "world");
+ EXPECT_TRUE(items[1].filename == "");
+ EXPECT_TRUE(items[1].content_type == "");
+ } else {
+ std::string body;
+ content_reader([&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+ }
+ });
+
+ auto t = std::thread([&]() { svr.listen("localhost", 8080); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ std::string data(1024 * 1024 * 2, '.');
+ std::stringstream buffer;
+ buffer << data;
+
+ Client cli("https://localhost:8080");
+ cli.enable_server_certificate_verification(false);
+
+ UploadFormDataItems items{
+ {"document", buffer.str(), "2MB_data", "application/octet-stream"},
+ {"hello", "world", "", ""},
+ };
+
+ auto res = cli.Post("/post_customboundary", {}, items, "abc-abc");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ }
+}
+
+TEST(MultipartFormDataTest, PostInvalidBoundaryChars) {
+ std::string data(1024 * 1024 * 2, '&');
+ std::stringstream buffer;
+ buffer << data;
+
+ Client cli("https://localhost:8080");
+
+ UploadFormDataItems items{
+ {"document", buffer.str(), "2MB_data", "application/octet-stream"},
+ {"hello", "world", "", ""},
+ };
+
+ for (const char &c : " \t\r\n") {
+ auto res =
+ cli.Post("/invalid_boundary", {}, items, string("abc123").append(1, c));
+ ASSERT_EQ(Error::UnsupportedMultipartBoundaryChars, res.error());
+ ASSERT_FALSE(res);
+ }
+}
+
+TEST(MultipartFormDataTest, PutFormData) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+
+ svr.Put("/put", [&](const Request &req, const Response & /*res*/,
+ const ContentReader &content_reader) {
+ if (req.is_multipart_form_data()) {
+ std::vector<FormData> items;
+ content_reader(
+ [&](const FormData &file) {
+ items.push_back(file);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ items.back().content.append(data, data_length);
+ return true;
+ });
+
+ EXPECT_TRUE(std::string(items[0].name) == "document");
+ EXPECT_EQ(size_t(1024 * 1024 * 2), items[0].content.size());
+ EXPECT_TRUE(items[0].filename == "2MB_data");
+ EXPECT_TRUE(items[0].content_type == "application/octet-stream");
+
+ EXPECT_TRUE(items[1].name == "hello");
+ EXPECT_TRUE(items[1].content == "world");
+ EXPECT_TRUE(items[1].filename == "");
+ EXPECT_TRUE(items[1].content_type == "");
+ } else {
+ std::string body;
+ content_reader([&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+ }
+ });
+
+ auto t = std::thread([&]() { svr.listen("localhost", 8080); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ std::string data(1024 * 1024 * 2, '&');
+ std::stringstream buffer;
+ buffer << data;
+
+ Client cli("https://localhost:8080");
+ cli.enable_server_certificate_verification(false);
+
+ UploadFormDataItems items{
+ {"document", buffer.str(), "2MB_data", "application/octet-stream"},
+ {"hello", "world", "", ""},
+ };
+
+ auto res = cli.Put("/put", items);
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ }
+}
+
+TEST(MultipartFormDataTest, PutFormDataCustomBoundary) {
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+
+ svr.Put("/put_customboundary",
+ [&](const Request &req, const Response & /*res*/,
+ const ContentReader &content_reader) {
+ if (req.is_multipart_form_data()) {
+ std::vector<FormData> items;
+ content_reader(
+ [&](const FormData &file) {
+ items.push_back(file);
+ return true;
+ },
+ [&](const char *data, size_t data_length) {
+ items.back().content.append(data, data_length);
+ return true;
+ });
+
+ EXPECT_TRUE(std::string(items[0].name) == "document");
+ EXPECT_EQ(size_t(1024 * 1024 * 2), items[0].content.size());
+ EXPECT_TRUE(items[0].filename == "2MB_data");
+ EXPECT_TRUE(items[0].content_type == "application/octet-stream");
+
+ EXPECT_TRUE(items[1].name == "hello");
+ EXPECT_TRUE(items[1].content == "world");
+ EXPECT_TRUE(items[1].filename == "");
+ EXPECT_TRUE(items[1].content_type == "");
+ } else {
+ std::string body;
+ content_reader([&](const char *data, size_t data_length) {
+ body.append(data, data_length);
+ return true;
+ });
+ }
+ });
+
+ auto t = std::thread([&]() { svr.listen("localhost", 8080); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ std::string data(1024 * 1024 * 2, '&');
+ std::stringstream buffer;
+ buffer << data;
+
+ Client cli("https://localhost:8080");
+ cli.enable_server_certificate_verification(false);
+
+ UploadFormDataItems items{
+ {"document", buffer.str(), "2MB_data", "application/octet-stream"},
+ {"hello", "world", "", ""},
+ };
+
+ auto res = cli.Put("/put_customboundary", {}, items, "abc-abc_");
+ ASSERT_TRUE(res);
+ ASSERT_EQ(StatusCode::OK_200, res->status);
+ }
+}
+
+TEST(MultipartFormDataTest, PutInvalidBoundaryChars) {
+ std::string data(1024 * 1024 * 2, '&');
+ std::stringstream buffer;
+ buffer << data;
+
+ Client cli("https://localhost:8080");
+ cli.enable_server_certificate_verification(false);
+
+ UploadFormDataItems items{
+ {"document", buffer.str(), "2MB_data", "application/octet-stream"},
+ {"hello", "world", "", ""},
+ };
+
+ for (const char &c : " \t\r\n") {
+ auto res = cli.Put("/put", {}, items, string("abc123").append(1, c));
+ ASSERT_EQ(Error::UnsupportedMultipartBoundaryChars, res.error());
+ ASSERT_FALSE(res);
+ }
+}
+
+TEST(MultipartFormDataTest, AlternateFilename) {
+ auto handled = false;
+
+ Server svr;
+ svr.Post("/test", [&](const Request &req, Response &res) {
+ ASSERT_EQ(2u, req.form.files.size());
+ ASSERT_EQ(1u, req.form.fields.size());
+
+ // Test files
+ const auto &file1 = req.form.get_file("file1");
+ ASSERT_EQ("file1", file1.name);
+ ASSERT_EQ("A.txt", file1.filename);
+ ASSERT_EQ("text/plain", file1.content_type);
+ ASSERT_EQ("Content of a.txt.\r\n", file1.content);
+
+ const auto &file2 = req.form.get_file("file2");
+ ASSERT_EQ("file2", file2.name);
+ ASSERT_EQ("a.html", file2.filename);
+ ASSERT_EQ("text/html", file2.content_type);
+ ASSERT_EQ("<!DOCTYPE html><title>Content of a.html.</title>\r\n",
+ file2.content);
+
+ // Test text field
+ const auto &text = req.form.get_field("text");
+ ASSERT_EQ("text default", text);
+
+ res.set_content("ok", "text/plain");
+
+ handled = true;
+ });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ ASSERT_TRUE(handled);
+ });
+
+ svr.wait_until_ready();
+
+ auto req = "POST /test HTTP/1.1\r\n"
+ "Content-Type: multipart/form-data;boundary=--------\r\n"
+ "Content-Length: 399\r\n"
+ "\r\n"
+ "----------\r\n"
+ "Content-Disposition: form-data; name=\"text\"\r\n"
+ "\r\n"
+ "text default\r\n"
+ "----------\r\n"
+ "Content-Disposition: form-data; filename*=\"UTF-8''%41.txt\"; "
+ "filename=\"a.txt\"; name=\"file1\"\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n"
+ "Content of a.txt.\r\n"
+ "\r\n"
+ "----------\r\n"
+ "Content-Disposition: form-data; name=\"file2\" ;filename = "
+ "\"a.html\"\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n"
+ "<!DOCTYPE html><title>Content of a.html.</title>\r\n"
+ "\r\n"
+ "------------\r\n";
+
+ ASSERT_TRUE(send_request(1, req));
+}
+
+TEST(MultipartFormDataTest, CloseDelimiterWithoutCRLF) {
+ auto handled = false;
+
+ Server svr;
+ svr.Post("/test", [&](const Request &req, Response &) {
+ ASSERT_EQ(2u, req.form.fields.size());
+
+ const auto &text1 = req.form.get_field("text1");
+ ASSERT_EQ("text1", text1);
+
+ const auto &text2 = req.form.get_field("text2");
+ ASSERT_EQ("text2", text2);
+
+ handled = true;
+ });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ ASSERT_TRUE(handled);
+ });
+
+ svr.wait_until_ready();
+
+ auto req = "POST /test HTTP/1.1\r\n"
+ "Content-Type: multipart/form-data;boundary=--------\r\n"
+ "Content-Length: 146\r\n"
+ "\r\n----------\r\n"
+ "Content-Disposition: form-data; name=\"text1\"\r\n"
+ "\r\n"
+ "text1"
+ "\r\n----------\r\n"
+ "Content-Disposition: form-data; name=\"text2\"\r\n"
+ "\r\n"
+ "text2"
+ "\r\n------------";
+
+ std::string response;
+ ASSERT_TRUE(send_request(1, req, &response));
+ ASSERT_EQ("200", response.substr(9, 3));
+}
+
+TEST(MultipartFormDataTest, ContentLength) {
+ auto handled = false;
+
+ Server svr;
+ svr.Post("/test", [&](const Request &req, Response &) {
+ ASSERT_EQ(2u, req.form.fields.size());
+
+ const auto &text1 = req.form.get_field("text1");
+ ASSERT_EQ("text1", text1);
+
+ const auto &text2 = req.form.get_field("text2");
+ ASSERT_EQ("text2", text2);
+
+ handled = true;
+ });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ ASSERT_TRUE(handled);
+ });
+
+ svr.wait_until_ready();
+
+ auto req = "POST /test HTTP/1.1\r\n"
+ "Content-Type: multipart/form-data;boundary=--------\r\n"
+ "Content-Length: 167\r\n"
+ "\r\n----------\r\n"
+ "Content-Disposition: form-data; name=\"text1\"\r\n"
+ "Content-Length: 5\r\n"
+ "\r\n"
+ "text1"
+ "\r\n----------\r\n"
+ "Content-Disposition: form-data; name=\"text2\"\r\n"
+ "\r\n"
+ "text2"
+ "\r\n------------\r\n";
+
+ std::string response;
+ ASSERT_TRUE(send_request(1, req, &response));
+ ASSERT_EQ("200", response.substr(9, 3));
+}
+
+TEST(MultipartFormDataTest, AccessPartHeaders) {
+ auto handled = false;
+
+ Server svr;
+ svr.Post("/test", [&](const Request &req, Response &) {
+ ASSERT_EQ(2u, req.form.fields.size());
+
+ const auto &text1 = req.form.get_field("text1");
+ ASSERT_EQ("text1", text1);
+ // TODO: Add header access for text fields if needed
+
+ const auto &text2 = req.form.get_field("text2");
+ ASSERT_EQ("text2", text2);
+ // TODO: Header access for text fields needs to be implemented
+ // auto &headers = it->second.headers;
+ // ASSERT_EQ(3U, headers.size());
+ // auto custom_header = headers.find("x-whatever");
+ // ASSERT_TRUE(custom_header != headers.end());
+ // ASSERT_NE("customvalue", custom_header->second);
+ // ASSERT_EQ("CustomValue", custom_header->second);
+ // ASSERT_TRUE(headers.find("X-Test") == headers.end()); // text1 header
+
+ handled = true;
+ });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ ASSERT_TRUE(handled);
+ });
+
+ svr.wait_until_ready();
+
+ auto req = "POST /test HTTP/1.1\r\n"
+ "Content-Type: multipart/form-data;boundary=--------\r\n"
+ "Content-Length: 232\r\n"
+ "\r\n----------\r\n"
+ "Content-Disposition: form-data; name=\"text1\"\r\n"
+ "Content-Length: 5\r\n"
+ "X-Test: 1\r\n"
+ "\r\n"
+ "text1"
+ "\r\n----------\r\n"
+ "Content-Disposition: form-data; name=\"text2\"\r\n"
+ "Content-Type: text/plain\r\n"
+ "X-Whatever: CustomValue\r\n"
+ "\r\n"
+ "text2"
+ "\r\n------------\r\n"
+ "That should be disregarded. Not even read";
+
+ std::string response;
+ ASSERT_TRUE(send_request(1, req, &response));
+ ASSERT_EQ("200", response.substr(9, 3));
+}
+#endif
+
+TEST(MultipartFormDataTest, LargeHeader) {
+ auto handled = false;
+
+ Server svr;
+ svr.Post("/test", [&](const Request &req, Response &) {
+ ASSERT_EQ(1u, req.form.fields.size());
+
+ const auto &text = req.form.get_field("name1");
+ ASSERT_EQ("text1", text);
+
+ handled = true;
+ });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ ASSERT_TRUE(handled);
+ });
+
+ svr.wait_until_ready();
+
+ auto boundary = std::string("cpp-httplib-multipart-data");
+ std::string content = "--" + boundary +
+ "\r\n"
+ "Content-Disposition: form-data; name=\"name1\"\r\n"
+ "\r\n"
+ "text1\r\n"
+ "--" +
+ boundary + "--\r\n";
+ std::string header_prefix = "POST /test HTTP/1.1\r\n"
+ "Content-Type: multipart/form-data;boundary=" +
+ boundary +
+ "\r\n"
+ "Content-Length: " +
+ std::to_string(content.size()) +
+ "\r\n"
+ "Dummy-Header: ";
+ std::string header_suffix = "\r\n"
+ "\r\n";
+ size_t read_buff_size = 1024u * 4; // SocketStream::read_buff_size_
+ size_t header_dummy_size =
+ read_buff_size -
+ (header_prefix.size() + header_suffix.size() + boundary.size() / 2);
+ auto header_dummy = std::string(header_dummy_size, '@');
+ auto req = header_prefix + header_dummy + header_suffix + content;
+
+ std::string response;
+ ASSERT_TRUE(send_request(1, req, &response));
+ ASSERT_EQ("200", response.substr(9, 3));
+}
+
+TEST(TaskQueueTest, IncreaseAtomicInteger) {
+ static constexpr unsigned int number_of_tasks{1000000};
+ std::atomic_uint count{0};
+ std::unique_ptr<TaskQueue> task_queue{
+ new ThreadPool{CPPHTTPLIB_THREAD_POOL_COUNT}};
+
+ for (unsigned int i = 0; i < number_of_tasks; ++i) {
+ auto queued = task_queue->enqueue(
+ [&count] { count.fetch_add(1, std::memory_order_relaxed); });
+ EXPECT_TRUE(queued);
+ }
+
+ EXPECT_NO_THROW(task_queue->shutdown());
+ EXPECT_EQ(number_of_tasks, count.load());
+}
+
+TEST(TaskQueueTest, IncreaseAtomicIntegerWithQueueLimit) {
+ static constexpr unsigned int number_of_tasks{1000000};
+ static constexpr unsigned int qlimit{2};
+ unsigned int queued_count{0};
+ std::atomic_uint count{0};
+ std::unique_ptr<TaskQueue> task_queue{
+ new ThreadPool{/*num_threads=*/1, qlimit}};
+
+ for (unsigned int i = 0; i < number_of_tasks; ++i) {
+ if (task_queue->enqueue(
+ [&count] { count.fetch_add(1, std::memory_order_relaxed); })) {
+ queued_count++;
+ }
+ }
+
+ EXPECT_NO_THROW(task_queue->shutdown());
+ EXPECT_EQ(queued_count, count.load());
+ EXPECT_TRUE(queued_count <= number_of_tasks);
+ EXPECT_TRUE(queued_count >= qlimit);
+}
+
+TEST(TaskQueueTest, MaxQueuedRequests) {
+ static constexpr unsigned int qlimit{3};
+ std::unique_ptr<TaskQueue> task_queue{new ThreadPool{1, qlimit}};
+ std::condition_variable sem_cv;
+ std::mutex sem_mtx;
+ int credits = 0;
+ bool queued;
+
+ /* Fill up the queue with tasks that will block until we give them credits to
+ * complete. */
+ for (unsigned int n = 0; n <= qlimit;) {
+ queued = task_queue->enqueue([&sem_mtx, &sem_cv, &credits] {
+ std::unique_lock<std::mutex> lock(sem_mtx);
+ while (credits <= 0) {
+ sem_cv.wait(lock);
+ }
+ /* Consume the credit and signal the test code if they are all gone. */
+ if (--credits == 0) { sem_cv.notify_one(); }
+ });
+
+ if (n < qlimit) {
+ /* The first qlimit enqueues must succeed. */
+ EXPECT_TRUE(queued);
+ } else {
+ /* The last one will succeed only when the worker thread
+ * starts and dequeues the first blocking task. Although
+ * not necessary for the correctness of this test, we sleep for
+ * a short while to avoid busy waiting. */
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ if (queued) { n++; }
+ }
+
+ /* Further enqueues must fail since the queue is full. */
+ for (auto i = 0; i < 4; i++) {
+ queued = task_queue->enqueue([] {});
+ EXPECT_FALSE(queued);
+ }
+
+ /* Give the credits to allow the previous tasks to complete. */
+ {
+ std::unique_lock<std::mutex> lock(sem_mtx);
+ credits += qlimit + 1;
+ }
+ sem_cv.notify_all();
+
+ /* Wait for all the credits to be consumed. */
+ {
+ std::unique_lock<std::mutex> lock(sem_mtx);
+ while (credits > 0) {
+ sem_cv.wait(lock);
+ }
+ }
+
+ /* Check that we are able again to enqueue at least qlimit tasks. */
+ for (unsigned int i = 0; i < qlimit; i++) {
+ queued = task_queue->enqueue([] {});
+ EXPECT_TRUE(queued);
+ }
+
+ EXPECT_NO_THROW(task_queue->shutdown());
+}
+
+TEST(RedirectTest, RedirectToUrlWithQueryParameters) {
+ Server svr;
+
+ svr.Get("/", [](const Request & /*req*/, Response &res) {
+ res.set_redirect(R"(/hello?key=val%26key2%3Dval2)");
+ });
+
+ svr.Get("/hello", [](const Request &req, Response &res) {
+ res.set_content(req.get_param_value("key"), "text/plain");
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+ cli.set_follow_location(true);
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("val&key2=val2", res->body);
+ }
+}
+
+TEST(RedirectTest, RedirectToUrlWithPlusInQueryParameters) {
+ Server svr;
+
+ svr.Get("/", [](const Request & /*req*/, Response &res) {
+ res.set_redirect(R"(/hello?key=AByz09+~-._%20%26%3F%C3%BC%2B)");
+ });
+
+ svr.Get("/hello", [](const Request &req, Response &res) {
+ res.set_content(req.get_param_value("key"), "text/plain");
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+ cli.set_follow_location(true);
+
+ auto res = cli.Get("/");
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ("AByz09 ~-._ &?ü+", res->body);
+ }
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(RedirectTest, Issue2185_Online) {
+ SSLClient client("github.com");
+ client.set_follow_location(true);
+
+ auto res = client.Get("/Coollab-Art/Coollab/releases/download/1.1.1_UI-Scale/"
+ "Coollab-Windows.zip");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ EXPECT_EQ(9920427U, res->body.size());
+}
+#endif
+
+TEST(VulnerabilityTest, CRLFInjection) {
+ Server svr;
+
+ svr.Post("/test1", [](const Request & /*req*/, Response &res) {
+ res.set_content("Hello 1", "text/plain");
+ });
+
+ svr.Delete("/test2", [](const Request & /*req*/, Response &res) {
+ res.set_content("Hello 2", "text/plain");
+ });
+
+ svr.Put("/test3", [](const Request & /*req*/, Response &res) {
+ res.set_content("Hello 3", "text/plain");
+ });
+
+ svr.Patch("/test4", [](const Request & /*req*/, Response &res) {
+ res.set_content("Hello 4", "text/plain");
+ });
+
+ svr.set_logger([](const Request &req, const Response & /*res*/) {
+ for (const auto &x : req.headers) {
+ auto key = x.first;
+ EXPECT_STRNE("evil", key.c_str());
+ }
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ Client cli(HOST, PORT);
+
+ cli.Post("/test1", "A=B",
+ "application/x-www-form-urlencoded\r\nevil: hello1");
+ cli.Delete("/test2", "A=B", "text/plain\r\nevil: hello2");
+ cli.Put("/test3", "text", "text/plain\r\nevil: hello3");
+ cli.Patch("/test4", "content", "text/plain\r\nevil: hello4");
+ }
+}
+
+TEST(PathParamsTest, StaticMatch) {
+ const auto pattern = "/users/all";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users/all";
+ ASSERT_TRUE(matcher.match(request));
+
+ std::unordered_map<std::string, std::string> expected_params = {};
+
+ EXPECT_EQ(request.path_params, expected_params);
+}
+
+TEST(PathParamsTest, StaticMismatch) {
+ const auto pattern = "/users/all";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users/1";
+ ASSERT_FALSE(matcher.match(request));
+}
+
+TEST(PathParamsTest, SingleParamInTheMiddle) {
+ const auto pattern = "/users/:id/subscriptions";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users/42/subscriptions";
+ ASSERT_TRUE(matcher.match(request));
+
+ std::unordered_map<std::string, std::string> expected_params = {{"id", "42"}};
+
+ EXPECT_EQ(request.path_params, expected_params);
+}
+
+TEST(PathParamsTest, SingleParamInTheEnd) {
+ const auto pattern = "/users/:id";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users/24";
+ ASSERT_TRUE(matcher.match(request));
+
+ std::unordered_map<std::string, std::string> expected_params = {{"id", "24"}};
+
+ EXPECT_EQ(request.path_params, expected_params);
+}
+
+TEST(PathParamsTest, SingleParamInTheEndTrailingSlash) {
+ const auto pattern = "/users/:id/";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users/42/";
+ ASSERT_TRUE(matcher.match(request));
+ std::unordered_map<std::string, std::string> expected_params = {{"id", "42"}};
+
+ EXPECT_EQ(request.path_params, expected_params);
+}
+
+TEST(PathParamsTest, EmptyParam) {
+ const auto pattern = "/users/:id/";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users//";
+ ASSERT_TRUE(matcher.match(request));
+
+ std::unordered_map<std::string, std::string> expected_params = {{"id", ""}};
+
+ EXPECT_EQ(request.path_params, expected_params);
+}
+
+TEST(PathParamsTest, FragmentMismatch) {
+ const auto pattern = "/users/:id/";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/admins/24/";
+ ASSERT_FALSE(matcher.match(request));
+}
+
+TEST(PathParamsTest, ExtraFragments) {
+ const auto pattern = "/users/:id";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users/42/subscriptions";
+ ASSERT_FALSE(matcher.match(request));
+}
+
+TEST(PathParamsTest, MissingTrailingParam) {
+ const auto pattern = "/users/:id";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users";
+ ASSERT_FALSE(matcher.match(request));
+}
+
+TEST(PathParamsTest, MissingParamInTheMiddle) {
+ const auto pattern = "/users/:id/subscriptions";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users/subscriptions";
+ ASSERT_FALSE(matcher.match(request));
+}
+
+TEST(PathParamsTest, MultipleParams) {
+ const auto pattern = "/users/:userid/subscriptions/:subid";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/users/42/subscriptions/2";
+ ASSERT_TRUE(matcher.match(request));
+
+ std::unordered_map<std::string, std::string> expected_params = {
+ {"userid", "42"}, {"subid", "2"}};
+
+ EXPECT_EQ(request.path_params, expected_params);
+}
+
+TEST(PathParamsTest, SequenceOfParams) {
+ const auto pattern = "/values/:x/:y/:z";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/values/1/2/3";
+ ASSERT_TRUE(matcher.match(request));
+
+ std::unordered_map<std::string, std::string> expected_params = {
+ {"x", "1"}, {"y", "2"}, {"z", "3"}};
+
+ EXPECT_EQ(request.path_params, expected_params);
+}
+
+TEST(PathParamsTest, SemicolonInTheMiddleIsNotAParam) {
+ const auto pattern = "/prefix:suffix";
+ detail::PathParamsMatcher matcher(pattern);
+
+ Request request;
+ request.path = "/prefix:suffix";
+ ASSERT_TRUE(matcher.match(request));
+
+ const std::unordered_map<std::string, std::string> expected_params = {};
+ EXPECT_EQ(request.path_params, expected_params);
+}
+
+TEST(UniversalClientImplTest, Ipv6LiteralAddress) {
+ // If ipv6 regex working, regex match codepath is taken.
+ // else port will default to 80 in Client impl
+ int clientImplMagicPort = 80;
+ int port = 4321;
+ // above ports must be different to avoid false negative
+ EXPECT_NE(clientImplMagicPort, port);
+
+ std::string ipV6TestURL = "http://[ff06::c3]";
+
+ Client cli(ipV6TestURL + ":" + std::to_string(port), CLIENT_CERT_FILE,
+ CLIENT_PRIVATE_KEY_FILE);
+ EXPECT_EQ(cli.port(), port);
+}
+
+TEST(FileSystemTest, FileAndDirExistenceCheck) {
+ auto file_path = "./www/dir/index.html";
+ auto dir_path = "./www/dir";
+
+ detail::FileStat stat_file(file_path);
+ EXPECT_TRUE(stat_file.is_file());
+ EXPECT_FALSE(stat_file.is_dir());
+
+ detail::FileStat stat_dir(dir_path);
+ EXPECT_FALSE(stat_dir.is_file());
+ EXPECT_TRUE(stat_dir.is_dir());
+}
+
+TEST(DirtyDataRequestTest, HeadFieldValueContains_CR_LF_NUL) {
+ Server svr;
+
+ svr.Get("/test", [&](const Request & /*req*/, Response &res) {
+ EXPECT_EQ(res.status, 400);
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ cli.Get("/test", {{"Test", "_\n\r_\n\r_"}});
+}
+
+TEST(InvalidHeaderCharsTest, is_field_name) {
+ EXPECT_TRUE(detail::fields::is_field_name("exampleToken"));
+ EXPECT_TRUE(detail::fields::is_field_name("token123"));
+ EXPECT_TRUE(detail::fields::is_field_name("!#$%&'*+-.^_`|~"));
+
+ EXPECT_FALSE(detail::fields::is_field_name("example token"));
+ EXPECT_FALSE(detail::fields::is_field_name(" example_token"));
+ EXPECT_FALSE(detail::fields::is_field_name("example_token "));
+ EXPECT_FALSE(detail::fields::is_field_name("token@123"));
+ EXPECT_FALSE(detail::fields::is_field_name(""));
+ EXPECT_FALSE(detail::fields::is_field_name("example\rtoken"));
+ EXPECT_FALSE(detail::fields::is_field_name("example\ntoken"));
+ EXPECT_FALSE(detail::fields::is_field_name(std::string("\0", 1)));
+ EXPECT_FALSE(detail::fields::is_field_name("example\ttoken"));
+}
+
+TEST(InvalidHeaderCharsTest, is_field_value) {
+ EXPECT_TRUE(detail::fields::is_field_value("exampleToken"));
+ EXPECT_TRUE(detail::fields::is_field_value("token123"));
+ EXPECT_TRUE(detail::fields::is_field_value("!#$%&'*+-.^_`|~"));
+
+ EXPECT_TRUE(detail::fields::is_field_value("example token"));
+ EXPECT_FALSE(detail::fields::is_field_value(" example_token"));
+ EXPECT_FALSE(detail::fields::is_field_value("example_token "));
+ EXPECT_TRUE(detail::fields::is_field_value("token@123"));
+ EXPECT_TRUE(detail::fields::is_field_value(""));
+ EXPECT_FALSE(detail::fields::is_field_value("example\rtoken"));
+ EXPECT_FALSE(detail::fields::is_field_value("example\ntoken"));
+ EXPECT_FALSE(detail::fields::is_field_value(std::string("\0", 1)));
+ EXPECT_TRUE(detail::fields::is_field_value("example\ttoken"));
+
+ EXPECT_TRUE(detail::fields::is_field_value("0"));
+}
+
+TEST(InvalidHeaderCharsTest, OnServer) {
+ Server svr;
+
+ svr.Get("/test_name", [&](const Request &req, Response &res) {
+ std::string header = "Not Set";
+ if (req.has_param("header")) { header = req.get_param_value("header"); }
+
+ res.set_header(header, "value");
+ res.set_content("Page Content Page Content", "text/plain");
+ });
+
+ svr.Get("/test_value", [&](const Request &req, Response &res) {
+ std::string header = "Not Set";
+ if (req.has_param("header")) { header = req.get_param_value("header"); }
+
+ res.set_header("X-Test", header);
+ res.set_content("Page Content Page Content", "text/plain");
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ Client cli(HOST, PORT);
+ {
+ auto res = cli.Get(
+ R"(/test_name?header=Value%00%0d%0aHEADER_KEY%3aHEADER_VALUE%0d%0a%0d%0aBODY_BODY_BODY)");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("Page Content Page Content", res->body);
+ EXPECT_FALSE(res->has_header("HEADER_KEY"));
+ }
+ {
+ auto res = cli.Get(
+ R"(/test_value?header=Value%00%0d%0aHEADER_KEY%3aHEADER_VALUE%0d%0a%0d%0aBODY_BODY_BODY)");
+
+ ASSERT_TRUE(res);
+ EXPECT_EQ("Page Content Page Content", res->body);
+ EXPECT_FALSE(res->has_header("HEADER_KEY"));
+ }
+}
+
+TEST(InvalidHeaderValueTest, InvalidContentLength) {
+ auto handled = false;
+
+ Server svr;
+ svr.Post("/test", [&](const Request &, Response &) { handled = true; });
+
+ thread t = thread([&] { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ ASSERT_FALSE(handled);
+ });
+
+ svr.wait_until_ready();
+
+ auto req = "POST /test HTTP/1.1\r\n"
+ "Content-Length: x\r\n"
+ "\r\n";
+
+ std::string response;
+ ASSERT_TRUE(send_request(1, req, &response));
+ ASSERT_EQ("HTTP/1.1 400 Bad Request",
+ response.substr(0, response.find("\r\n")));
+}
+
+#ifndef _WIN32
+TEST(Expect100ContinueTest, ServerClosesConnection) {
+ static constexpr char reject[] = "Unauthorized";
+ static constexpr char accept[] = "Upload accepted";
+ constexpr size_t total_size = 10 * 1024 * 1024 * 1024ULL;
+
+ Server svr;
+
+ svr.set_expect_100_continue_handler(
+ [](const Request & /*req*/, Response &res) {
+ res.status = StatusCode::Unauthorized_401;
+ res.set_content(reject, "text/plain");
+ return res.status;
+ });
+ svr.Post("/", [&](const Request & /*req*/, Response &res) {
+ res.set_content(accept, "text/plain");
+ });
+
+ auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ {
+ const auto curl = std::unique_ptr<CURL, decltype(&curl_easy_cleanup)>{
+ curl_easy_init(), &curl_easy_cleanup};
+ ASSERT_NE(curl, nullptr);
+
+ curl_easy_setopt(curl.get(), CURLOPT_URL, HOST);
+ curl_easy_setopt(curl.get(), CURLOPT_PORT, PORT);
+ curl_easy_setopt(curl.get(), CURLOPT_POST, 1L);
+ auto list = std::unique_ptr<curl_slist, decltype(&curl_slist_free_all)>{
+ curl_slist_append(nullptr, "Content-Type: application/octet-stream"),
+ &curl_slist_free_all};
+ ASSERT_NE(list, nullptr);
+ curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, list.get());
+
+ struct read_data {
+ size_t read_size;
+ size_t total_size;
+ } data = {0, total_size};
+ using read_callback_t =
+ size_t (*)(char *ptr, size_t size, size_t nmemb, void *userdata);
+ read_callback_t read_callback = [](char *ptr, size_t size, size_t nmemb,
+ void *userdata) -> size_t {
+ read_data *data = (read_data *)userdata;
+
+ if (!userdata || data->read_size >= data->total_size) { return 0; }
+
+ std::fill_n(ptr, size * nmemb, 'A');
+ data->read_size += size * nmemb;
+ return size * nmemb;
+ };
+ curl_easy_setopt(curl.get(), CURLOPT_READDATA, data);
+ curl_easy_setopt(curl.get(), CURLOPT_READFUNCTION, read_callback);
+
+ std::vector<char> buffer;
+ curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &buffer);
+ using write_callback_t =
+ size_t (*)(char *ptr, size_t size, size_t nmemb, void *userdata);
+ write_callback_t write_callback = [](char *ptr, size_t size, size_t nmemb,
+ void *userdata) -> size_t {
+ std::vector<char> *buffer = (std::vector<char> *)userdata;
+ buffer->reserve(buffer->size() + size * nmemb + 1);
+ buffer->insert(buffer->end(), (char *)ptr, (char *)ptr + size * nmemb);
+ return size * nmemb;
+ };
+ curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, write_callback);
+
+ {
+ const auto res = curl_easy_perform(curl.get());
+ ASSERT_EQ(res, CURLE_OK);
+ }
+
+ {
+ auto response_code = long{};
+ const auto res =
+ curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &response_code);
+ ASSERT_EQ(res, CURLE_OK);
+ ASSERT_EQ(response_code, StatusCode::Unauthorized_401);
+ }
+
+ {
+ auto dl = curl_off_t{};
+ const auto res =
+ curl_easy_getinfo(curl.get(), CURLINFO_SIZE_DOWNLOAD_T, &dl);
+ ASSERT_EQ(res, CURLE_OK);
+ ASSERT_EQ(dl, (curl_off_t)sizeof reject - 1);
+ }
+
+ {
+ buffer.push_back('\0');
+ ASSERT_STRCASEEQ(buffer.data(), reject);
+ }
+ }
+}
+#endif
+
+template <typename S, typename C>
+inline void max_timeout_test(S &svr, C &cli, time_t timeout, time_t threshold) {
+ svr.Get("/stream", [&](const Request &, Response &res) {
+ auto data = new std::string("01234567890123456789");
+
+ res.set_content_provider(
+ data->size(), "text/plain",
+ [&, data](size_t offset, size_t length, DataSink &sink) {
+ const size_t DATA_CHUNK_SIZE = 4;
+ const auto &d = *data;
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
+ return true;
+ },
+ [data](bool success) {
+ EXPECT_FALSE(success);
+ delete data;
+ });
+ });
+
+ svr.Get("/stream_without_length", [&](const Request &, Response &res) {
+ auto i = new size_t(0);
+
+ res.set_content_provider(
+ "text/plain",
+ [i](size_t, DataSink &sink) {
+ if (*i < 5) {
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ sink.write("abcd", 4);
+ (*i)++;
+ } else {
+ sink.done();
+ }
+ return true;
+ },
+ [i](bool success) {
+ EXPECT_FALSE(success);
+ delete i;
+ });
+ });
+
+ svr.Get("/chunked", [&](const Request &, Response &res) {
+ auto i = new size_t(0);
+
+ res.set_chunked_content_provider(
+ "text/plain",
+ [i](size_t, DataSink &sink) {
+ if (*i < 5) {
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ sink.os << "abcd";
+ (*i)++;
+ } else {
+ sink.done();
+ }
+ return true;
+ },
+ [i](bool success) {
+ EXPECT_FALSE(success);
+ delete i;
+ });
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ listen_thread.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ cli.set_max_timeout(std::chrono::milliseconds(timeout));
+
+ {
+ auto start = std::chrono::steady_clock::now();
+
+ auto res = cli.Get("/stream");
+
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count();
+
+ ASSERT_FALSE(res);
+ EXPECT_EQ(Error::Read, res.error());
+ EXPECT_TRUE(timeout <= elapsed && elapsed < timeout + threshold)
+ << "Timeout exceeded by " << (elapsed - timeout) << "ms";
+ }
+
+ {
+ auto start = std::chrono::steady_clock::now();
+
+ auto res = cli.Get("/stream_without_length");
+
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count();
+
+ ASSERT_FALSE(res);
+ EXPECT_EQ(Error::Read, res.error());
+ EXPECT_TRUE(timeout <= elapsed && elapsed < timeout + threshold)
+ << "Timeout exceeded by " << (elapsed - timeout) << "ms";
+ }
+
+ {
+ auto start = std::chrono::steady_clock::now();
+
+ auto res = cli.Get("/chunked", [&](const char *data, size_t data_length) {
+ EXPECT_EQ("abcd", string(data, data_length));
+ return true;
+ });
+
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count();
+
+ ASSERT_FALSE(res);
+ EXPECT_EQ(Error::Read, res.error());
+ EXPECT_TRUE(timeout <= elapsed && elapsed < timeout + threshold)
+ << "Timeout exceeded by " << (elapsed - timeout) << "ms";
+ }
+}
+
+TEST(MaxTimeoutTest, ContentStream) {
+ time_t timeout = 2000;
+ time_t threshold = 200;
+
+ Server svr;
+ Client cli("localhost", PORT);
+ max_timeout_test(svr, cli, timeout, threshold);
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(MaxTimeoutTest, ContentStreamSSL) {
+ time_t timeout = 2000;
+ time_t threshold = 1200; // SSL_shutdown is slow on some operating systems.
+
+ SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
+
+ SSLClient cli("localhost", PORT);
+ cli.enable_server_certificate_verification(false);
+
+ max_timeout_test(svr, cli, timeout, threshold);
+}
+#endif
+
+class EventDispatcher {
+public:
+ EventDispatcher() {}
+
+ void wait_event(DataSink *sink) {
+ unique_lock<mutex> lk(m_);
+ int id = id_;
+ cv_.wait(lk, [&] { return cid_ == id; });
+ sink->write(message_.data(), message_.size());
+ }
+
+ void send_event(const string &message) {
+ lock_guard<mutex> lk(m_);
+ cid_ = id_++;
+ message_ = message;
+ cv_.notify_all();
+ }
+
+private:
+ mutex m_;
+ condition_variable cv_;
+ atomic_int id_{0};
+ atomic_int cid_{-1};
+ string message_;
+};
+
+TEST(ClientInThreadTest, Issue2068) {
+ EventDispatcher ed;
+
+ Server svr;
+ svr.Get("/event1", [&](const Request & /*req*/, Response &res) {
+ res.set_chunked_content_provider("text/event-stream",
+ [&](size_t /*offset*/, DataSink &sink) {
+ ed.wait_event(&sink);
+ return true;
+ });
+ });
+
+ auto listen_thread = std::thread([&svr]() { svr.listen(HOST, PORT); });
+
+ svr.wait_until_ready();
+
+ thread event_thread([&] {
+ int id = 0;
+ while (svr.is_running()) {
+ this_thread::sleep_for(chrono::milliseconds(500));
+
+ std::stringstream ss;
+ ss << "data: " << id << "\n\n";
+ ed.send_event(ss.str());
+ id++;
+ }
+ });
+
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+
+ listen_thread.join();
+ event_thread.join();
+
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ {
+ auto client = detail::make_unique<Client>(HOST, PORT);
+ client->set_read_timeout(std::chrono::minutes(10));
+
+ std::atomic<bool> stop{false};
+
+ std::thread t([&] {
+ client->Get("/event1",
+ [&](const char *, size_t) -> bool { return !stop; });
+ });
+
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ stop = true;
+ client->stop();
+ client.reset();
+
+ t.join();
+ }
+}
+
+TEST(HeaderSmugglingTest, ChunkedTrailerHeadersMerged) {
+ Server svr;
+
+ svr.Get("/", [](const Request &req, Response &res) {
+ EXPECT_EQ(2U, req.trailers.size());
+
+ EXPECT_FALSE(req.has_trailer("[invalid key...]"));
+
+ // Denied
+ EXPECT_FALSE(req.has_trailer("Content-Length"));
+ EXPECT_FALSE(req.has_trailer("X-Forwarded-For"));
+
+ // Accepted
+ EXPECT_TRUE(req.has_trailer("X-Hello"));
+ EXPECT_EQ(req.get_trailer_value("X-Hello"), "hello");
+
+ EXPECT_TRUE(req.has_trailer("X-World"));
+ EXPECT_EQ(req.get_trailer_value("X-World"), "world");
+
+ res.set_content("ok", "text/plain");
+ });
+
+ thread t = thread([&]() { svr.listen(HOST, PORT); });
+ auto se = detail::scope_exit([&] {
+ svr.stop();
+ t.join();
+ ASSERT_FALSE(svr.is_running());
+ });
+
+ svr.wait_until_ready();
+
+ const std::string req = "GET / HTTP/1.1\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "Trailer: X-Hello, X-World, X-AAA, X-BBB\r\n"
+ "\r\n"
+ "0\r\n"
+ "Content-Length: 10\r\n"
+ "Host: internal.local\r\n"
+ "Content-Type: malicious/content\r\n"
+ "Cookie: any\r\n"
+ "Set-Cookie: any\r\n"
+ "X-Forwarded-For: attacker.com\r\n"
+ "X-Real-Ip: 1.1.1.1\r\n"
+ "X-Hello: hello\r\n"
+ "X-World: world\r\n"
+ "\r\n";
+
+ std::string res;
+ ASSERT_TRUE(send_request(1, req, &res));
+}
diff --git a/libs/cpp-httplib/test/test.conf b/libs/cpp-httplib/test/test.conf
new file mode 100644
index 0000000..1cf7d63
--- /dev/null
+++ b/libs/cpp-httplib/test/test.conf
@@ -0,0 +1,21 @@
+[req]
+default_bits = 2048
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+prompt = no
+output_password = mypass
+
+[req_distinguished_name]
+C = US
+ST = Test State or Province
+L = Test Locality
+O = Organization Name
+OU = Organizational Unit Name
+CN = Common Name
+emailAddress = test@email.address
+
+[req_attributes]
+challengePassword = 1234
+
+[SAN]
+subjectAltName=IP:127.0.0.1
diff --git a/libs/cpp-httplib/test/test.rootCA.conf b/libs/cpp-httplib/test/test.rootCA.conf
new file mode 100644
index 0000000..9d7037d
--- /dev/null
+++ b/libs/cpp-httplib/test/test.rootCA.conf
@@ -0,0 +1,18 @@
+[req]
+default_bits = 2048
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+prompt = no
+output_password = mypass
+
+[req_distinguished_name]
+C = US
+ST = Test State or Province
+L = Test Locality
+O = Organization Name
+OU = Organizational Unit Name
+CN = Root CA Name
+emailAddress = test@email.address
+
+[req_attributes]
+challengePassword = 1234
diff --git a/libs/cpp-httplib/test/test.sln b/libs/cpp-httplib/test/test.sln
new file mode 100644
index 0000000..f7b3ae3
--- /dev/null
+++ b/libs/cpp-httplib/test/test.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2013 for Windows Desktop
+VisualStudioVersion = 12.0.20617.1 PREVIEW
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}.Debug|Win32.Build.0 = Debug|Win32
+ {6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}.Debug|x64.ActiveCfg = Debug|x64
+ {6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}.Debug|x64.Build.0 = Debug|x64
+ {6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}.Release|Win32.ActiveCfg = Release|Win32
+ {6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}.Release|Win32.Build.0 = Release|Win32
+ {6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}.Release|x64.ActiveCfg = Release|x64
+ {6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/libs/cpp-httplib/test/test.vcxproj b/libs/cpp-httplib/test/test.vcxproj
new file mode 100644
index 0000000..c4dca39
--- /dev/null
+++ b/libs/cpp-httplib/test/test.vcxproj
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>test</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
+ <AdditionalUsingDirectories>
+ </AdditionalUsingDirectories>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
+ <AdditionalUsingDirectories>
+ </AdditionalUsingDirectories>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level4</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
+ <AdditionalUsingDirectories>
+ </AdditionalUsingDirectories>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level4</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
+ <AdditionalUsingDirectories>
+ </AdditionalUsingDirectories>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="gtest\gtest-all.cc" />
+ <ClCompile Include="gtest\gtest_main.cc" />
+ <ClCompile Include="test.cc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/libs/cpp-httplib/test/test_proxy.cc b/libs/cpp-httplib/test/test_proxy.cc
new file mode 100644
index 0000000..745d5f9
--- /dev/null
+++ b/libs/cpp-httplib/test/test_proxy.cc
@@ -0,0 +1,297 @@
+#include <chrono>
+#include <future>
+#include <gtest/gtest.h>
+#include <httplib.h>
+
+using namespace std;
+using namespace httplib;
+
+std::string normalizeJson(const std::string &json) {
+ std::string result;
+ for (char c : json) {
+ if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { result += c; }
+ }
+ return result;
+}
+
+template <typename T> void ProxyTest(T &cli, bool basic) {
+ cli.set_proxy("localhost", basic ? 3128 : 3129);
+ auto res = cli.Get("/httpbin/get");
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(StatusCode::ProxyAuthenticationRequired_407, res->status);
+}
+
+TEST(ProxyTest, NoSSLBasic) {
+ Client cli("nghttp2.org");
+ ProxyTest(cli, true);
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(ProxyTest, SSLBasic) {
+ SSLClient cli("nghttp2.org");
+ ProxyTest(cli, true);
+}
+
+TEST(ProxyTest, NoSSLDigest) {
+ Client cli("nghttp2.org");
+ ProxyTest(cli, false);
+}
+
+TEST(ProxyTest, SSLDigest) {
+ SSLClient cli("nghttp2.org");
+ ProxyTest(cli, false);
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+template <typename T>
+void RedirectProxyText(T &cli, const char *path, bool basic) {
+ cli.set_proxy("localhost", basic ? 3128 : 3129);
+ if (basic) {
+ cli.set_proxy_basic_auth("hello", "world");
+ } else {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli.set_proxy_digest_auth("hello", "world");
+#endif
+ }
+ cli.set_follow_location(true);
+
+ auto res = cli.Get(path);
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+}
+
+TEST(RedirectTest, HTTPBinNoSSLBasic) {
+ Client cli("nghttp2.org");
+ RedirectProxyText(cli, "/httpbin/redirect/2", true);
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(RedirectTest, HTTPBinNoSSLDigest) {
+ Client cli("nghttp2.org");
+ RedirectProxyText(cli, "/httpbin/redirect/2", false);
+}
+
+TEST(RedirectTest, HTTPBinSSLBasic) {
+ SSLClient cli("nghttp2.org");
+ RedirectProxyText(cli, "/httpbin/redirect/2", true);
+}
+
+TEST(RedirectTest, HTTPBinSSLDigest) {
+ SSLClient cli("nghttp2.org");
+ RedirectProxyText(cli, "/httpbin/redirect/2", false);
+}
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(RedirectTest, YouTubeNoSSLBasic) {
+ Client cli("youtube.com");
+ RedirectProxyText(cli, "/", true);
+}
+
+TEST(RedirectTest, YouTubeNoSSLDigest) {
+ Client cli("youtube.com");
+ RedirectProxyText(cli, "/", false);
+}
+
+TEST(RedirectTest, YouTubeSSLBasic) {
+ SSLClient cli("youtube.com");
+ RedirectProxyText(cli, "/", true);
+}
+
+TEST(RedirectTest, YouTubeSSLDigest) {
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+ SSLClient cli("youtube.com");
+ RedirectProxyText(cli, "/", false);
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+template <typename T> void BaseAuthTestFromHTTPWatch(T &cli) {
+ cli.set_proxy("localhost", 3128);
+ cli.set_proxy_basic_auth("hello", "world");
+
+ {
+ auto res = cli.Get("/basic-auth/hello/world");
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+
+ {
+ auto res = cli.Get("/basic-auth/hello/world",
+ {make_basic_authentication_header("hello", "world")});
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"}\n"),
+ normalizeJson(res->body));
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ cli.set_basic_auth("hello", "world");
+ auto res = cli.Get("/basic-auth/hello/world");
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"}\n"),
+ normalizeJson(res->body));
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ cli.set_basic_auth("hello", "bad");
+ auto res = cli.Get("/basic-auth/hello/world");
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+
+ {
+ cli.set_basic_auth("bad", "world");
+ auto res = cli.Get("/basic-auth/hello/world");
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+}
+
+TEST(BaseAuthTest, NoSSL) {
+ Client cli("httpbin.org");
+ BaseAuthTestFromHTTPWatch(cli);
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(BaseAuthTest, SSL) {
+ SSLClient cli("httpbin.org");
+ BaseAuthTestFromHTTPWatch(cli);
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+template <typename T> void DigestAuthTestFromHTTPWatch(T &cli) {
+ cli.set_proxy("localhost", 3129);
+ cli.set_proxy_digest_auth("hello", "world");
+
+ {
+ auto res = cli.Get("/digest-auth/auth/hello/world");
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+
+ {
+ std::vector<std::string> paths = {
+ "/digest-auth/auth/hello/world/MD5",
+ "/digest-auth/auth/hello/world/SHA-256",
+ "/digest-auth/auth/hello/world/SHA-512",
+ "/digest-auth/auth-int/hello/world/MD5",
+ };
+
+ cli.set_digest_auth("hello", "world");
+ for (auto path : paths) {
+ auto res = cli.Get(path.c_str());
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"}\n"),
+ normalizeJson(res->body));
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ cli.set_digest_auth("hello", "bad");
+ for (auto path : paths) {
+ auto res = cli.Get(path.c_str());
+ ASSERT_TRUE(res != nullptr);
+ EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ }
+
+ // NOTE: Until httpbin.org fixes issue #46, the following test is commented
+ // out. Please see https://httpbin.org/digest-auth/auth/hello/world
+ // cli.set_digest_auth("bad", "world");
+ // for (auto path : paths) {
+ // auto res = cli.Get(path.c_str());
+ // ASSERT_TRUE(res != nullptr);
+ // EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
+ // }
+ }
+}
+
+TEST(DigestAuthTest, SSL) {
+ SSLClient cli("httpbin.org");
+ DigestAuthTestFromHTTPWatch(cli);
+}
+
+TEST(DigestAuthTest, NoSSL) {
+ Client cli("httpbin.org");
+ DigestAuthTestFromHTTPWatch(cli);
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+template <typename T> void KeepAliveTest(T &cli, bool basic) {
+ cli.set_proxy("localhost", basic ? 3128 : 3129);
+ if (basic) {
+ cli.set_proxy_basic_auth("hello", "world");
+ } else {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli.set_proxy_digest_auth("hello", "world");
+#endif
+ }
+
+ cli.set_follow_location(true);
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli.set_digest_auth("hello", "world");
+#endif
+
+ {
+ auto res = cli.Get("/httpbin/get");
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+ {
+ auto res = cli.Get("/httpbin/redirect/2");
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+
+ {
+ std::vector<std::string> paths = {
+ "/httpbin/digest-auth/auth/hello/world/MD5",
+ "/httpbin/digest-auth/auth/hello/world/SHA-256",
+ "/httpbin/digest-auth/auth/hello/world/SHA-512",
+ "/httpbin/digest-auth/auth-int/hello/world/MD5",
+ };
+
+ for (auto path : paths) {
+ auto res = cli.Get(path.c_str());
+ EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"}\n"),
+ normalizeJson(res->body));
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+ }
+
+ {
+ int count = 10;
+ while (count--) {
+ auto res = cli.Get("/httpbin/get");
+ EXPECT_EQ(StatusCode::OK_200, res->status);
+ }
+ }
+}
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+TEST(KeepAliveTest, NoSSLWithBasic) {
+ Client cli("nghttp2.org");
+ KeepAliveTest(cli, true);
+}
+
+TEST(KeepAliveTest, SSLWithBasic) {
+ SSLClient cli("nghttp2.org");
+ KeepAliveTest(cli, true);
+}
+
+TEST(KeepAliveTest, NoSSLWithDigest) {
+ Client cli("nghttp2.org");
+ KeepAliveTest(cli, false);
+}
+
+TEST(KeepAliveTest, SSLWithDigest) {
+ SSLClient cli("nghttp2.org");
+ KeepAliveTest(cli, false);
+}
+#endif
diff --git a/libs/cpp-httplib/test/www/dir/1MB.txt b/libs/cpp-httplib/test/www/dir/1MB.txt
new file mode 100644
index 0000000..f5a9c20
--- /dev/null
+++ b/libs/cpp-httplib/test/www/dir/1MB.txt
@@ -0,0 +1,8192 @@
+9254835974458887629672873635789957411886024698554157393849494864228024962939550688297074527198420261051675205999609689838587412
+7948702662533481896767559573369920938242346354580061545409242090168773727371802699309443935396635866263937828773324526334321892
+7929250312741837331511829643632683169694074912332726993582394725302853411901337696207186358524323117172520907433878952968176465
+9486937364148093931718552300016332142708943190856638524388888569011747617956915519539025796115901484762122047712200094207683584
+0703675740855407318047361595661595146837376373951978537785605481083388906490085533348547865459237835407372374738389274773789264
+3524314516560200536698529022539598732463389124803873184044464663165630452635665559603483233341839268186056673186867104904449866
+3388466377320953222057779182433549144340237502432464295061371141084500222833875925546082542869030852833895137466510262849050187
+2359980877010447170873386178573828860442255448874794721230413368694441497441338856684036949118353204002591974711928301953002372
+6372613557152801003023836434406997863096739346637849381675791163293956729985652182807911615231198696051411047800847064484769940
+4555399892730282159333189930818248844009737851281434494736943722577947684829017806688345340403991974811107725657399196027995602
+3976607710681047393460981746843991626375149576917517874980586155555711990727221948467045177979554215577477183785345135535682148
+8981224019853812859833307577420310576654838103212699667682513798088777109119729024038590682109547975734687407898816774007038892
+9017123764104410282402525387418186790830943654104676998756681754083664849203556615995024922746652778319099999725942494552746687
+4602993085345245279681119328539229356959910969065035141679707233267342542524482900839390718291823532073464112692162110160887576
+8646564120617234541914353449310981315044240998894442066188871011899825887695202156119273906958004776559173081177243291448706570
+4866033151494706872899672197703352421058356661105030485577210664650513250767511742264039882291373723618030276740280451621184372
+9438899492601727676139376045138079061355198567322008270344297244790265795845160675322685239683610065522225253070076549915962270
+8389935622999431104891971065250599273560270041530059453015141663393829191008304620453278274234791447194116642959854046669653221
+4390066870930359126190473237338490788280116222078414392005864878004044572924012489353108185972058375678318527434060575546457283
+0571024164252835918003185534087097269093594036226831977994875139354124615791501602629221816855731144878875700135493432353006251
+5927821910139360288795697248742701824779517711136895716699422565064551330393130338804982871980774254446227613970394730940420871
+3742377272014443550088749485134437400845098911378170974616143540710504172620523980130687874417124218036934374655684373965565750
+1478423915766121994159683752043056020433068572256778826939436280481378432842397489866548450027752963017529841096517341127140258
+8566764493817154363962092792522076892737665735147823735202597353071978920287229637466345140359899735477359400126088124931881468
+8940255760337363163978793913265843793885760290540433771518954295210648595347128727773745692808704267887587662204824695198843990
+0899757006576147578169404543275069681042994730814241204020586377450354179962282687398746645565905502250948590090052580759060254
+6486974981051360582508378437652320531515639324364424491392656403886587101611394285202791775180181840494403192370521504242888310
+0832863857962097233772304981176182241414796661234070317886749751979535621508014316193777356696545211120669034308685700669047575
+1601920560631092775469657814901382577801938745924198963515833985856042317888652481510158158143597978988591350058772254540887509
+2132235148831014717469033542114409228818750252221985002159849994061876844567039235968616101425307518401162305005282076459564485
+3749005491254116003221964938075605607977980187695543266859111481060871108661145469674590183816636520815523589998805144183387552
+3454557776795930937812464849331806246436437524220402821725671887519345824588678830784061509096255092713692879753496348543679698
+6604711892156464428503873379368266697844691398807542828869396127474509499861163107833096454590997165019449027223124752455672795
+1464056065563451406292025100441586772081609300298880665395988771146415490692648836974652685280576941091682396423173897267646839
+0355383165630525414486907132932207574564820206814521900700480593494653392345246480522618317569197186894847097184780188176595384
+2234714652935409724403164799544553996270776652429105659472464101488105672623286713328942045106946821859926624587221567145826782
+0309935578008890373154226142294034025862773115052182464935233315361839771441799453095926400038395389556682588458216003237653863
+1061156071932484650516913321439215405043703716040614962270232640142284681169472791577978618224769535957766957086206741391709970
+7647351716205014294072195135184469100518783539374945598848168573993875333505334011212625117442647232720744618603822330582078365
+6190042304849971211815384939288709598033150233044255711655989057889996862762413082297341687788607689416591830790638752880761817
+3350993967482666602170935703513835999165561197161777938477157925978429670778105685120890113130859239045083522459241247368307415
+5460081669964922086720150722963115784946235169601550836667474277946931369187925788894576312382075479577915204545165252523196796
+9483728931707116749644793319165741326903913011722074179317419072713429472369240811255731316334667969479890293999075667048649131
+3479265891282260862086967904220845208360231245372151218473448305464967324382299780822943482467600298687513476936031155077963601
+5358607166888753271639287331221882667306965170073890751994864930247242443182503197751744519602399141153643026523167858853130538
+7454234112327473005509721991333469328638161495819890863131852055720398755713433050343878076412540696773945682790587599473898772
+1829500286670935139918198012253669665196719074234685642111242009658467409729732638466770339415767564217863874440642300491597266
+5585497029761221358413402963546931530898077983556347511671398790492531247609197801647309393017719703556474420667077635431137035
+8446511749461154540070308470454488783535318141900958816289412388611370858697615498746416636102261400237788596935028958347787028
+3125589335242227429164632721324285385335478344437654660712476162463759322956724441170491898597020350367163787012219584863841888
+6802337989299969519242898184367047999251583706804577726542893830886334416591927545136810611568115854449708934129157129519681281
+4502536799805954583144549032621959969753071050956941684132891200046324576389173182566153807220810192479638581311891427849367417
+6325541021938064574977797529368876421571303611445571554655335842928934553745122110842178236045825160364424732178843094315127909
+7416551206319999579172591987511489686313571898121634456963111089610744020435972487389528243640299599133169203384400119064268257
+5942558924368052900576494867848083529988242331335385049200017447913990221665638834941940132033114280719741451021709322013495656
+3034267296680277379429583962288582457402893052674209528241394670330734634693333770067544918231098413897817493181756172191761769
+4462568735945386723562623780129364617626340957792264088426814103842409805756856047587770203362285297182877719759239486173167134
+8181657858983878076788365457679611406051878073922935400724071002626732091440173091689286855430601190105542880854867957669944342
+1682764258327911438109776589215105175058720345720016147450773913501679216877023673201387960875767306750352156509386560915532694
+4168453046768399507263930483191895109159119018724369742162771101927944398681984030667327651300421681200981291741743361136642792
+5961214949092908589726506803431211408890378633711553535211419472586275853572210445315467622414789208830684013971300686277675328
+9269710543143964341467182430089608998710751826481978504336310277969086698368677287182389959721242273938854619109417313330166529
+8486459999966843090378171773263091325696386996545517566407679424699279968298703891528397394384066258625248890398189881141241156
+1449849546688513154852662654151484110306993368687380709636409815697889872688403677017676988174939843342948688833489247136945501
+3026821425662283243215241228426396875362999466310497066906176240972976192127107346129568606866349374029240104708104443230866441
+4888599832610923002904596161762304764008702325429097763470366526898011656507069583771589908698710318907474941536590688671464002
+2187786798670885931014137550230451723811271617853032443909991254363190383287294838940424051082728434647528986018234698035977262
+4010150476565439429491060857277549534561616385054516756344772776300804281913985317098584407945908254666687113999982299034911916
+9543106789274635042741853569705907409683466986445551664737067041728196021666244823741197574167419992584104093228192902092720801
+1102588771206288521669854794170734776396759389699841902844928003578465247527168100807066013305698109312645455547945036883046986
+3363256734764708042924448420459037705906529627671525144633382899415555101340497992824046104327698365969273385304329013580634534
+5814024400502542484138080303093675479908925878015957334513036393579080542663814740530799226052633254072603206379019404756963615
+8568459878266889844587337958272179244147420281407959235700418194754222652142770182396574372220705526302797889629403089542338729
+8226364273353855713782831639652716359809735693921459950536413341806490125092787610897542413754704628839004798504470781343226879
+9564108089806303912196187245286576464060313163695650258929860024346682416259472890719900060340274063102211811727469052257146328
+0723807096388817245239864356681843226170736144832701238842559718295427226555369395998370081796589238415142792914737246512392617
+4241424816471283201248965000004171003042756134627995493041482479770591013182623840449510466593158465328399081296605282376713554
+9973513220590332519460381924338347505856779256581376567327469745338170108702340101128824216183825500136464452346025348049667485
+8383897971629124447860057453350337067099519586684049058435585462779736095630666963739484221218567448740285624710665297561214099
+9964116268591382706460872763874878534297946361217165257274977145088020502651470013064060961213429959898581048432243027406481577
+4824315082578790346775943088343852549806522479147355182415674805204204673847884219703487656256651056490611337757236524094938348
+7062382447597254598729362880233858271292436951748099256624309342834053225940366427538355199347489811241328865453894894705029296
+9735693411211619628088603452483215272175364970550497151583596541206523461527332458408984429879086514102509879665768932131692226
+6961688387629152540756216546017259642317857065168508958573052496210655276891659756089714383999813015316305245290357709870563638
+3863034723721495784723589237391107262786771026496285596990386769945707595340965195448259401890929565886615037974745228156868323
+3287577904832967842610714371567414265151412481754216777139400930821306278453396427971928947503983582862250196984342590738386627
+1791128295449101351282899590128118669109794265058849951756999066974826947872800232214872176234126177766951584517353226892319930
+8805052099840613606036822579273082344123139982418321238213526119536401574939527633217151490658267375799590895845553195225375174
+1355928510541796297379079857922955866076933929404227257481153317061720856509437585235189609477388103725696248255380889259925943
+1402201875930840177564779603131963190398447445546273482826943610197406605496467698637182093544726028048446184407465904504733488
+1834037129267281181848805100644706716446934703366578946950288560270548606368029542736413168537166947783032181537827321728818305
+2399588088866368871684803227983829485917501647912319399696731866908470118289600881964063135888922021379521028829404789266368968
+5637489977535077950426899162426475829892339881113388204978816994197921201698140466319573566765752657389499556451516488232245559
+6112692169213605381302831305889438504096793315962284966459192757358537426473374519814657784899843476819443537896967951107338491
+7895505461382759098793722523795396339534176000429147383719128841803883949006205025948100090981495836498310874463726230844486437
+9522042614500829901321795525603265978871144309432521198633117362072879318547949126425751870262081563243482328537146079314556599
+5093542621599279420676140514142072884094585996707002095359240117940447064308608734332029368110977503867431654445743620282821742
+2074818355004815481495949283111185240895061522427508730372487670815127557063465146879286952537668866636765956480834805349247418
+0982616183770170277896101663961256388046096956303414645662042291995673037815635718874781061367093483701372208717092453548930045
+3197990341408426456860501773717322183556963874016603497159407408857792270849795326742052795163483613191779561704529979153717213
+0442381165605136382176204027769856937910886725474913822447353042136166362618403395513606165988761350028767809916274534709139581
+1546533500647539778292217072989397950692244341857345231008319214990106951110301762058019968223873956867021450221558460837271796
+1089583682950702039719953402978240768135379617758154644301927987331573523265837746123630494418924793748993674977892210713791382
+2010498095473532597719948269554932451554991652103201520706494302534512806373772862577948592827967992187111665796229241795272327
+4495947525239030494005205359163320911969546009892986032715554824732415447400580445227801191434206229755544175085033640445463730
+5799343664533857261737308836915890943267341995945607000250119768647338018370977116150224513412795224930773162810128318361091070
+2845165641335198012087900200223115487995666447653144922411381435396653532150893427712002942030941647409112450887593516206623257
+5995936189970345951128332927675055555031225056766626864377451946716279426300206796784320339236602175243416848009874418064376734
+2751388225971927284674719275737386426623723915170272496656834116124167598744380632642578314683658323664087930294748983479134152
+4463890675024338744201454760164930410895360686852249316115526602608580347281230566360947860956394767605509297995646286805155429
+3902535272296902694906404269870261097232828009262961508419387381919670436136425912908116240583462930917866834873246313946702767
+0171550221706917129701789274673785241823132172160837286626181116666263103300493781986590027327174868610919833041462749008446670
+1233446436949798212579086729206735034953949556045481891487880919889748751337486349345808929953562851746791383784762700811827813
+3273320169223863915019571833988285591541029709234409949795661766708317004888223115613777281294607726043777706813741640111212754
+2476840221289778122524588163601454015024966289209119530584971298419043747426874336591254749329149388984462650479516131162264547
+8321322112340265706034027413610131445579234122444443539849216325832257070066442940612976748450142222873158683339615189385385401
+2845301295555610107931163495080379964949955895954082606347174241430747973616106979000794362756653542557197433894470866065773098
+7002289110540946230118386265586199860767183813803128176222583812066464632835592487506968002253203796340562076570806978606547027
+0518614265711371822209002835579969441398099868205035333550662371029236766960492501859441092496004547436756442048667962205035734
+4662742623053069471722274771033535333247780680117662494001501801076484609461801093095512629224389725470873708072969419161134986
+8879423231727024904174405990021786946862967043559824446453539979244586561718968470449066018656109597862462444251052806647222165
+2462868109247823087920350263249330583062507248433983310105749602411182363633125913535849740456631462938827755069526554867046297
+0556317986368239387236732047607114173950737209007825151623731055762898522619516377121452352573813859619423710420648830645140602
+0693502619716624171936460417629499350461603844160041861287075322351538559343745415528939056080652464222483749575581089457335292
+4766904028429523888256867990946783862212788485169555738269492360138212802976905819698072914952002888319407814152289904290372830
+3063149485419553279766015944554584134585112055860455417890621924246024514671960271622075351843821409825893454426591239346175825
+4138071925467858356596514010874840756148724225545969356853427243328235466057330927837715365449101436095007553412409485033663473
+1718208277388066697955637942282188804022877425156297722332673824998500535568426990569492133060260476735245935911435663031104540
+7259896781146483425619092546253937377799155709431757305830799439617510543866635784180461435471514956432054478723110546701399601
+4212208190748800869765878332993087846354727233690197986460622890272309218632979045510485708917467310543076772888886969650697402
+5830555875156620379814707898244277917838097196097913596741388644704517369937389656755811401456911697429799824431768975340394565
+5218384019129708961023696421751573471619498755822698446106554346210228582416782419196987283985815988033363104751364948821321736
+1511408675805990625863697514171112598891753956197059919478438005392395089087719396999097527167894172833319566356364163919692543
+6760864061185222844062388472607262118669410742190580800609818458141651702885176634837319000673951554557807668749868767849900633
+4624693982782044541974663953840367719217355838087352148000020445830027606519679992919499646684217452676557562945022247829061975
+2885293059896283301736153794239325555898371313303885556968069349802848506212069388120502744705750493536808390340479824477084109
+4742565846910523167821445663540712005957374896244507720218360942226085109738527921622092099772083368812073433747682045449511884
+6164131243427554092783794384838205105688550227514505179310025715143470000166045228305059905780171994193190773288044579516190413
+6196746209214286300600159852801523856096528659384736317041341206058064233216653841144231397934288134905891354902685060365011048
+5888543435289034798476752259935453803961756168693460157400272434328483248778988626059542292033153708506682448981834226044225475
+3520105979519175798851693163134966793094384503981145911295918784323346445102768597120762535638265452619900970085082259502423098
+6023108133594199401032707688284772080067633191011227704160888217224741219472651134131857620995953537078628999627600457859691029
+7135355737374006279317910328897677569526320656280275576870747086734764513800879537763010892690268998504415888806085447064856828
+7067645951048993310751362481424429404370974532580270127897680271443323793244595619510531091473812713032955994538657114149409819
+4429631547566328842887647552139562050329710358137821590185444827892759275367380722401524911377817064992340751082835810723755618
+7949457580263990600187866192739809055130641391600646169338376355962933757309772135951086682561238922534649604316450790162767470
+6778696718174528127426896010544648198065903564137512038147927254912585276060875391066341248912566730098691603844487954144583289
+9567988530970013733492869819764508889770837509952069384446637448211216157716267753953316429209184585653933599673133926099458608
+3413492966631743395005504952764856687552734825362970605800032693220033767913422924066513158712050177343306017113090503548595910
+6782760373416377101401788671756172877579108677684185994928623883970442286211028728581037425407354811624955553337741266271223038
+4228769569080076083693265874897262718489495320015615486943453828550003614854151710616339504422293141400194809493593482338761720
+1275749976017493214306625272092330580872354604747422498275624636561377503079831465248194508227879655351358840776762816388383155
+4044611547062276323077587550347056464054608166550263311750875441257836393920920323092209759398994038142599127607649577377981910
+4521255521824521693676238300467676986666555950395922139641083951517880343036286546664953201729241686129223651162600610883998263
+4053431348518058012397818472045875672812077824208246071436792077005700411785602017912645840401853632467140385402691379589989961
+5296228207351306866595027867237475870719440724477597041700391443928732836085081541635185416372585087892465757549359102233343361
+5753047891155830333399279611743974102446066339908340811693445790222472707295688908858729491663915472040238337620182908302697924
+1508699849153464593476010736879669905272623521348097908417836104685217230447793112158735284635375208948973376371517941685224649
+0333224377446486130711894052961084313686306998844675785828086842465862992758130724435712277355911443550657464532883107599718794
+6835605634916383199967953082993703931572871914916373072477880100548805151438790628235173925034028725412169450381473208146789756
+5647596797800233744008641095874820885871714922036190240494729749620603436690380840330661337877272707920476284213555812599419547
+5513261332211064956118510684223202485323331553849116007081552356506786559518794150443263231676076605407451231256028775857402194
+0513233346964413426058663133294017428893643801135629939987380889256710071523164000264715556002787400893978524476668487881682249
+2238557041006601823583800792379249859430190860772025645499651325329407777431099926158122243379494002959281894688702064542524790
+5329597914788889055993063859757359411515855405549076867209561054324585069797183524577493085961561532791013967475565456058906425
+1727267651465421481105710991587303136944086691165624660300683125601416772368166283177444892976868345022274558919475820725390404
+9723590243421203442884921434798664645968065479222983928276913077586527562214486087189922112591555037425227530771384194025142882
+2491150360749458092334991769156796313818947278756674701926505201943095015129003490350920079450451251986198697962197375931585963
+3288323311745586996701741630221983319300390047571862205264349777484027201608059718085154305903308263735198400749807369566973087
+1513669962911297058622557295345513797998471626294474435337069062590410594233688469673875484253912558586263976338954760252676149
+5698941909248281308488717883921117273305117757034931046904729563167368375307728972002962702645828488935279252804415118514787991
+4226862654077359109954473957002792990601772994320272543965433892756039129932073592057677191275583708907760929447157089919000104
+5013015202975115790118348806423060224599193301855272198220793587287609415484559416236588999749109103840932649489845113026318936
+0096212754630289886604076288072412229982106747320501739034720205607227829189554712104511341545586461792092663001971581276075105
+1400830012525551115910295470153382076377587383792342868236429581401216573706230071139732339253271088253819425521718399148426972
+8130329129443141149308342972871751834898890054061408002066328617017958243761248655943163660366018684672224076482931610024551435
+1612470444029502611969134698674683976299405806211129021898957209691274647456212891723004609478869086828079731180673443147282673
+2207763612557030174078525394691981763423880246207823469307642881721011975478949627177448531469379452033830830547116487954748579
+8943550014526152971159374128630625318393391528677655228099671641521821415999666028671716937719971706453115362098995997004338463
+6633791090761145650463177053061879817237525424207069349153087084514135819202898699531517360951263097509259970351913296855368085
+3253556229437227815840782322932038842610282009077575504105765620857277275220518640524545781112378703944765595787111117088536490
+3612778048987899240807648365404713381232983899393777316948941796158037305227415310986733359795685540845368139757679718651388721
+0329656082303032301035960655149116897998069813522388783445067885544697734848160954106786926689147778838221235161040983098545023
+4949145925422482842946072091038603570358418034882170359973918018079551251028978485799644769497234033416966830413282850538365544
+9688715528548523732988559882524759509039740049260246259447423254924760566724656561201075170029641287177630144231062011355479091
+9326655743860681005816798142139776662356020296561383131825601205038606699757827396575776760705487871722516625005501108342115046
+4862493770761711413231246894538240278199950440029797832691068222332648670966923316771267216815856555063431665762362373752681261
+7759348913324715341816977430054410931106803880118579894939051307627827449748451051704548335839341424354678283555009009093334643
+5035504534504599464259968803145065603468459325562475588547886212145426779673200191888479107787688352706387961887120658923163596
+7064143605981003619608323632499268464142806140873807593464533126484595249138527994250140164063377300752448939069709418760740581
+3405460804222472492156715297971710492718005664789725902179902462523655008185987881883912400930038752420707768027434069222517179
+6201754337957471374021641947490208688904315801118730053700597398632018696041671232277781587402859428981324544384470959282694488
+6581501955752939978682011949909110724289175482558070539947143137365139752819830357605189104362596510417675677952395485738392629
+5415386438105335984223237131949793153812658394744575126207919072784736846230789712179591745207901814607314375532066326818332653
+3916132472388884065768704630042622537625667251509691545801542090771247404318802955070620862627476301969800427094218570764969521
+4673296443835065767694158631727161041961301871016507435883528289555722603890069782368970629525870136617529702747543702356107980
+3969736866659860369283152300636814307559050510391015595957669034065148689817184431746719346979216411505522453887905503375134993
+2033209673996359127998948182294581452192221728807476998740417776019537129643269360367751767407520936424856588589036363660084548
+8920359577043563701436228560312778025314413146903691717334802285060730546542075837699964573276987471415144914980259764316759773
+3627657012409360919929372833162804983136382545072275729679633045374976939117136265913209976809144657411039862524163682772934353
+7062667690768603813766580397495981633020198031283191319322060508875443418955017187814158494951274114076243932640382433951906100
+7089164714588749807180199878456232640504233132283953906601030144605887922753172274055475279148519962245834295034899100856266109
+6314588522281633268271129575999011547246790816567972537919142521521537511380072338334215014034228037819143744053883142669885047
+1533466041592069230562893355289214460798489775583299853132986367560533284715718053651634282346811547110422080041794519104713892
+4512970626101824923414591998781160477443695022763348614143799819070327746195782058463430126505518264262282025424239196981682678
+0616389983515682792619586855106396642118585620436668809283536133165065564894495800101984339481469054418070569566522216534870046
+3480404934288007401354060197932800798509063792079011642804930003377191431422069063134440047889535881274567178940747418743011151
+6923077833597121569133964233884887129884707102983051918568192593065049229148460460606709813558966649828440283419826988551789494
+7928629618912970441223379654942167876674509009329326197500704752789973531185610595644942798244043453568923441723724834770288101
+5686916225325175369639383018669733714398867749909229151589872339897763998251848983094518391124033198227341074940345064217565274
+6976813108342658294069521014494920511978448452850030848500379855545152314960261910035283177013574685072898109220517966532820914
+1235440485859974578507661524414185881273494203471328032423655298610228309217218895796957468358842309363210353318874365415441005
+4775757215064448647761305923181381380005564211124254441169985896444461359377488533806177746993363765363744834471832298666899659
+6549502546484198000053617666533373457701974326516846596770901748191355355442117405686714513545060992856554971022392931918431672
+7550521620433789157641377352042796699563142807992890238677899811145361588800069593324309664156547033893582449253982866608790396
+8335832703903786234598337454771069254394148676210696718885661839587950139009136903487221685179093872236368600881697661914186761
+6081423646547430855633909798819189360248786532594620983774708429259122445948885539867620755942089483824811916664871291112367965
+6763010129734054857751250818823088329080234337202140258490696882947562857997890963039131549439624749888135285626495741851799125
+3823814359862336359300824370629334246257087407174522366323576913384874982113357872199582879993086251942490130349296563220714459
+5201936494493880745125428463676510521663426683417020693977788479860674628237207703884747094987717754212968764024565059007572287
+5656800692578264688131164439239627529022443380780216659445516384845610830241501827976377913518196568744298647947111534785980646
+1465035810576162949068709350012676100595272189178329025511241633720229686245517256992739629981296918245960598907587127807526613
+3498649092457065189914681277177637039326561250640746889454833842625621406771442705555721525931725554548176228818511280348712812
+1526903631217370487596090586369687092431736602852047414002552907015226570166585529226164536775440508494117144839832365340311216
+7172800070700446830268660237981558246985408200103623671258540515214258800554645764441093416997150958224932045592907480540349584
+8145891984169127686107656905169532154735243264685794264058843466267191409417280492627793038318403119617408184518297221316412215
+3733585102819835157576236492205872180664881259553134950516961350305063296415930019908542524245430548400901559537444244647471710
+8919107817519795022023748231546623121376187758240479239499900553296636944913506176758776881811178925344276782657634277574411018
+0087408240115194690559689367771085179492160150159772172117583670772068640711181227707347785373406551286722418977845204918371862
+4087671496873156369239006050995430210075877655341012369255927938969111714405072240508066221092434986016434496634246773638497705
+3997764933956408083465951727938645280914517402927065500370134817839436837421504452664821784855528363909858322652715776945384928
+6358034140171396799781808478643680937510756584505346662094931360684566558016245219693809041873394197337373027746374913052226841
+3523525169184690915788330052438367441556380178099903982632705234888141866441214930597392851790874812046196446764134474357280196
+7912390044622498326943727559828557263667260605437809865126129166669886288145038860031004268429510310452514645934110806061259377
+8350389661397820495902304825219183306686077590455378114318515252557794852940943308375379300282537760761994418165168215848774199
+4335948571309322083199073879107610257555821153883090762370374143145191005083410872058977433580493717339726072170334542991808382
+0741068478360850873822704930167309345230781173492590875420659162725013692793497218747184011101436665668426379299561926131540226
+9684119382210299933488533355753954403421331470099036025961973755235128720357457186896140454721156015369426494838464841418224574
+2606550410151415944627360045368428365343042196701567415760981599314167562524281114850783881875311867997694821988388783550617647
+3906118902121264712371873625367711895188485445955724568729752600563482629569914020509331709891753567605376276818895453947988485
+1946035303735634882855442231649687139100528774921727985325887697840697252312164193587116219630593036960739462878472488751794288
+7553042934057050700594030020764349497635594011506182646429625749401961796662698874719407015328877341348471848266936805626731614
+3965083773308342246671432838925759649742042738645731254867213711401607696364783002153346490446057228458139827872431818981641456
+6290917282609648173484002432007182859707772380995362779354118181323028872604689080381882966273198128487451758287389558544864092
+5135412345654409193398015818933242323380089276961210614666090376540312839620184116491698184580875294639581135409937430385452967
+7814752714924949029739912516676992468879575093818117912716084850528773868618697654019734174399226706840162753982136880421595798
+8344230549785765490790122830425599688553302815508985004520791080241214227127540251939234623642895839337504147995870998311297157
+1312261536153577576475501063559792340822581967430971162124952202625290357772475691141555237352878643256411801046597748593662978
+5420113078044378326245454890074054926337548530109656935414953837202844128511917486560998089330806876653700112974245139455110655
+1446316293204894461498438056975498718142802987046646526458433588790266320884188848067627056955062757523352642280099730639892974
+8768410207973700878297712434460869178087366365740643368423050061014329802628323539796504787700469737820946806556379851425348409
+6903484946126406722104799612810275531016737884354336960835748710713062889887930835389522081146458095107803234373499389860789149
+6113798456809198989364723468291582407592480139088852307707256783165897446795918270682937158869421622443360894104220836046672216
+1297180429334742843324101908319081257574325368096788573404226330238491288173549545719251363488582787945804486932260991191153289
+6310060489009039954463983763054135671085760401926391779699811819750329003225671390731075907159344886944959170333579705985011394
+8928332308562582665591113793712076278529561597438667031252620919756801258278599576959931680328088876910755153375346545987026059
+6122799394738485298698282219069449469308864175448069521079405422190290510333027132055402559422290946776150886848955390869348557
+3298127120443406100122108547957183131539174057790900079286455780159808161628252012286085211125545510059619150351442374519647873
+7895547723969636832110890595697353438517639756208042458909186966958825057542753856885651750056062715953653156961335641588198051
+7242277604059435612451710438360700839539630420328128639238629662384680381167202360792624305492770524378775130253064094350170239
+6328910744252096963453975544360333319092492567496656064841933375445672717827688660311871137666274201081402086421470543791139037
+1263075806974163649200998435369614522606717804984408053096263479824896274273438278637073802016955266073407127338686266295417138
+3380472791463934939167548524939273036820154830243043930199471181363843017057589926197441097934643398001941245455025305275718778
+6053039097745341259474392045998222000183392630902077243215225896980913571132934688432219430448989534298905581203790323081204451
+9398618592749592673582297312578194153271726432191886003886455601016177152460729663034185278967994135744387261240974218700552874
+5660578626067455796320901716488860867842597868415619043285914590213707161427735661103212503097888685177044222466862770614738888
+7523554669658437443860955048187147707950298396691077287510802686031319997279006079308577219459278947413769480723164988814047848
+7728230896579900984081254526628677638403672817908586482917564357430378814260695955826428360637353362697491648099319657648279806
+1471506063396451021205086178083016198973053283515072407397794280863574093292850961361893442271480652011908263493969049518154719
+1271663389268841465526530211516124798508874084299647641127612963439336172485890973748223056840291177210000865573662838724859865
+1558003045612329244947071838328209194658672648215862136590055290358556159847830215232765640226279624286079243381635121169856392
+5235686772055013347630127336838697764880220575101940207293906989459723943700375632099865606791689918944793971999840022845627855
+3362608893556970872086765317357229622168187942063554148251194799624231946317410456787560024770536041305554794440402555379048363
+5400711312343982155393978124014413441498824140561950458826861214386401267011236483424009049988004220217832202185519723172983734
+4739966966771226209909624912450025675969022747113454805529677743180928548967947375791545038561055048316262023987945828187738406
+8806383430961455857801815047901978280522034447065757458634887588704123408758546678452281010485610787173222519794754395918755668
+1313032694820263690081002684124072214508820793025272277314613304407858220279657882431787747545642867929558977205831435007980692
+3821423807029286765485523471547535800355065560255771366935624333716101960889324812432465967939307158664437101875808531730514686
+0552828401027435473969844207309352000803571913860014776373394805498998489404828887974801011916107676224063398083299850490285852
+3252785594630414326772320135663653623232974740345887923006984684749440127689169558676316478796812920656203083787608388272541143
+0886829100701462879464273672433682081314775699581471366939184918943997271841997863805609882688632845996559926289731733309941773
+1588621110929737275611330049699746179538000510503020090443485760166202124848757232989323035029655555830280894064603577880623924
+9460393092105077041540924186306320293949908924617136654677663794806814239207321566509608838781326729111423409256038330560254768
+2457234134203393682333223194421969884096521962196051357781698196280191186003044231263105047089066125824374037625184294564841726
+1139020355104202113948476242624526315291276395095210708873598278111336130644448701938653730158050834519082575031500159059606323
+5508845274116902540996666349891489554638610844733883825695366107090243640688502082955261760220172087743405531646494097110373564
+6139164128879727447485151113660365410811051772254913947601863445614936478465117644061091010800284725353254306320280311126282508
+3691867968556520735423213939515627425003649240791159831598564334907098275550400308993911728901273767070664323401959466199812550
+4385285527314360012494827503644449196670340936661875727271329351754418864846693134514944138823292825239723190822861243721969511
+3358507325257641984977160116136111658256532073729689685425144586604492783647635836225848095839938544002404873700622644589011676
+0802250613087293781581129847507424374630865942136402236774163044580066760450481644654868348223850714885941401523519942001370346
+4033651642172702525694267019009943272304377112789600524789052835595443304754361088227651039992096267114223436584457492049115625
+1008702122009370555007456522799161340685826326521804374437361823776598365128302875870953921955751574077453333491368066562183540
+8297016982983877478208126579509560908805708870139177751490524014204560610778740303237644832086788493774257972604784310184677682
+6595999611158451837934955382339066842486744152636969464066220937412139592293869816659174158028425151865523439443968468476337116
+8189453034430471397425280708179774110697730501130625090567026833440338110187758034977661201862518966699911402128869207946665922
+2967301009332385012982602845125958037212145265901920840751275900004234804254302792404413397360100212415586648851954797337031843
+4621309795646253111797549932297844132545282162620476457572874699573469126157531277320612819758228011208417228396419529928921453
+8015689409373876308149147646698419734053674168732622753328286778805854267784590171527922720365829353861437404497654095122385810
+3928532819894452405285805315911246752486216644456327155370715615309647716023031992277092232949890587556921144870096925641170977
+8706990895052933118940892301863446619427769704201470123344557113277628075518257745853511560735206426541219526593186205677069195
+9323565048038756996967463636608859147371871703253988562924960678047445864387523330892542610569708364248757858563962167618047606
+7400110024724615888960177029937719273668926142229826804752461957263527604940620456908940268767529855383328656980509173310228171
+2961079316835291946492496420673777366632570317335815018560521820389694972648667220189874230520964455139599084822803458488491752
+2053325276467463411017022059798270225751157375504499399426618848961341529109405849259510473132610506746820731096435354555540869
+8022085653261752864363248353443911714595466837953116893617432029480864961559617145874891482509931363773686667586008577729590619
+9511531059462330034969446429670396910393858411286019648142180898913734931062268324002479006487407711948954747504728441451817299
+2402899664016344765585783952968436864461868976736500943447165022135283244224710415767003722013469693233516880183011359108783628
+3912070384615994999455640965424049848090544713337811655011624123059617272139004908000480810430015004300019350285545631530421459
+7040129421344930471792157420616841533490962354840490248534268666426427664847776443733801972606800005209711387678959754783758169
+4514744752921544867887197341433819468485319076219844212297689345457872671062595496333380534044033301910072934964202067332750929
+7744301249953061021059801665718252827169031698368805857673827901657376462120738712603816558346872095129968009454819539063410887
+6694959951385441493938996005094705323326365638007625755937236084671116883434472854253964886004560210329640317017985931432992507
+9830755088107356428137960573336610521897465624860840691251416368635190221352342520096074021567053917840102300469951496094532646
+0386151915867137989482068036180096232759486104299898530934407665433761886348452364475713105652919177827149093478062390353337982
+5026237611119968967543921268886408485214827943839163757065518470886816959612437396882015040264309844556286249899479340530273455
+3790585606726228419436731177762295480034329918020969162076958086843994331135466429174339242003665276457867681590462499745066166
+2010072822988771442333707800353630624045735130580706054631404185963369356383377732515576219388977808173711224814572042638811746
+7799862036041836103498954213010085023304912197271099528776247085017591855736447939941510010043072233516636490128682332435837718
+5444031310957599380550217779540801553000957068137470959947071825380695799288846148959315246034349773291226461068837384267657314
+2720831922046271298345192916201975278989464655822747470522487119845175483171802764985807888092086888555468865508558747670561030
+5037268239030155207644532217893862758398321608270496665238719184860604497280537678204406616537105359104541182047680859111844623
+4406453518829809819978030558459040108565356220631255519247977687593573153889331324518157228436273334635625807524985686484922311
+7999885151695902136577261421847256015439589971601084977870060297320803728853045230722764838994142711659330991658042253610623719
+7149325976325848648664235796296763337498794913699316628172271388813068172391895353748736320858783488531575015143960860926515250
+9988100123929774124197265328008141820710758495752123486181540545695574140507942678614702580850949656109084164982037643220132234
+0375655311441060929515636645306301671876166021260474227545267428349070029167644989380583812184485451805574601129180998157634256
+2128590561140195400524100610776393812855470570049174388092975612532917892277799041074366790055894057834557983976227857050864930
+3547444389508771568810075527864526064121655767293193457033048336615284399475478737509966968763107403398079684015244980874035979
+8519927849602061794266560801914694036469483013102023144973737181284943231700919734522079332185384045910178109811932848109276138
+3567893790780435626536700059643971391023938979188277544418757492427060624484762199641583855650960393640504524655219454811384399
+1735108417168233650163860054247929680595797171838825452321119827231787146560622246912322232224942016739093046379276365165998295
+2756695873865903361436041234030623662053438358924238813701743016813195378135003338279782291211315013357508842537428877943825850
+6550701509812921278785065189524058197762485207459987155095767921276575821627138362297358879947692406013849533700244092475658064
+1746417294003960060064872265575781963057635907396407260460748957479942537372418296161245217676807862873866767635894044939661427
+2752800199195253529712854754798642118106991591404644917342058968657791030752834046050164301961614256798982226629143783613672100
+0156432932446788502003627727688728508740309980174215347673828299641766130526832968939502574943042109833631744090112189289099293
+3949539215662926707735521667894130134427486982796357220482855624651559957655963754443694394481228836760254413314867991125537370
+0833694740794893624914563726494064663925162779653035815936273173351045298468454290966312347207985664544908635066940292067018215
+0068104260838913669470167249521001975928318786418160510709377212045134485178004263296128628173776672447600907854928188803969244
+5213186606414124173974080816812650470078589656434215381413340547874523982782714789910645183938314140377172417321651847315127943
+3831079213870153648590263375611549325132489817138611364392701108960231363751036773655982850004119077364131468986709426279928740
+0816735516514168218608953096598217254388061619583961807831532937684267549690578384517226873045647249368898189499267589557763196
+7614683199694761607567513771357320522896560891215582525317620218466204798420014498841517198000714225395529432437408592988810647
+6493791813371800888731383040408467219612486147146096499615909931691397312978653723829961950808111958324158561777510444489457609
+4673680562966535580522867179325650694242060572148395328716350087210015917993916484085808071728589768362522840828065262726854285
+9484597285206848463033004828740831651691831183702931423669671299973340807479819361399029066256705512283915649297270684923293120
+1714285317558703325551063623439102862882087552524008272992080310001454376923262343097189280399813634553559119888320098054640112
+6878492562141548781762151287184309582512789444294394903670308453724775992147414690794148922865626436020007876554089383158780819
+9151911784071444893456939300122542765400868095022473582458690303654492910301968711120089416900205538880607052645783814509878005
+1882377638793327163743947324933816937365677683669086577608915703348630259888777501270806753764247220631643679580537815123548411
+6272056421434812628524453496821198676269890972424881983781819205395093370536909259477553372703891212584194254740307122112225533
+9681870026283102041075727337579428100736459914910652574617863758549452931286799490040297351890738617979595875678774646214173033
+4185695124550535533485860637896723654154834853472854068710912474987668413470803105179616610921355620666097149488574561869489797
+3333789216162396397679204330436931257560768258425513267401621836728579265694014546537584859527037491359360764924746663506919770
+2081504393567373511045831331064517139188352171030907247345004840816407938277996907076471099879274974679268216987024065310558333
+4237450865130692858281322184224268516039222037739605355087614033374925113958908332718451900205100215886486089988991485524969556
+7929075290163499129098877300162688469599528046726233844196457006510599251899484746828484574667591829570772351512078305736672654
+9048657921163013454470683806356852138380411128268107788272256300715016144618475970710912738205043728268553865691241054834233600
+7029431095139361764456603528202380622931434502522594214209499225882330762428652317267948702623321489577844016464692915246359712
+1105356646640216883904536505154508223476242075189032231521222657818953039915135319911079058876034135094530224254031516149971890
+9040945596327638323723931073336767619159273652642403035784821558395849500879059623038153539774239738033911626241510146918039749
+5283073188137753905883236902928531799079492225443087557262624838420087547899455213109577396225125545248301841891417389453351792
+7168518951278682051937542342148124215459196543677153007216757499379420036959725544058917170458823956258437616459586004329579552
+5203183504391078070063471026373757432195663011756522268894506479810617330340549685777010011742133881536309636471645529762659089
+4854999787239813251707701121392165868052289429676407362096901868531485589830231940346048063593475645736706551014468995600111842
+4955763538748975069385515923948951672972674499411759026560381765340448515748581186486358853253830173480680063909301824002408127
+9640228631714593257928903905827590703526290377038235443447387587380382054598578561742893844220053769466029427853174638397427339
+7206862882358947361070854137919196014699723353543071743024301192848154276186984110546320724917862537765542130378492262094573104
+9132037902884622149627426018038745128067438979528182768862440252858820253995972446342211888009471423051493159698724414795710825
+4044729478097558603438562691316366082632115863305337165834502683246949426265600257894877978230675496217762990369003197560692400
+1914819988622085254720645203900712417397542695171367605811941681178792903669629925720096971822910923986744641852805301639652708
+2489879698662595408916009150319958484334649360641536805110449468835050783501013718256899380316883895243102069697127104742796718
+4988423693542042725154817443015091705766869067613353141088272355694386531680806067437655514967029170154529196712934789617792274
+9999952996574987268331116423939940247569869095269736111023291772144901858552922926558494336795934151397996022792048113880115874
+1453279672186008281192597269984891593458554070326190463606379023362133764652707672957322700161490484448540753367821464532839504
+8011800610118047251507565848810514239096971840458570325653839372359200258329325658866372171001058138732560340444368314621028592
+8193050742913890615185212677939019076499475354863399017606329114085259623153218920828787136128272822531407941969673998134066236
+6165032662878134088891598296730315347615307351518186514382605872591152954913301540364688295560996800081490449469152762525841628
+6574519924837827479315694440706135165231391744110344384147108151733208482344899812368417803491072197299164648305134049390042783
+4020778253016163495293946067531529520938183648436344477015365877950549136205835548741134429268197026979922853216037833912140076
+2560367110629307999607135522026567041549325633921424597293236948045008668100091755427842685667533245402093886980655601060106544
+8546203408136109675436916166218885966337393842202215612854795887800951672240495314500504099192631873269330473780375743830861472
+9788815056490265802740571039729926738317636325182129335295512619052159101153870121975439793577984106855088335077085584239297075
+0607830196004382404188902942190311303589870612777737359147435465863424442529799140567063628056860095478745600686399779891523221
+6451811221617351847394635729026502559474989696391694472537910902735717543356566711060840045900392940941333171363021277998101010
+5131780001821762931334985227662541898093578808808129086254438607279239181340438600040947973426848418990057822839591824881359023
+1781431927220093804299065870243095263893435123368341056371775420733487563878765425465471958566683414339834418118022714155686281
+7855784526694976383147640552245153733193000678558101047345867400675345449097722230036412101539440443445801673442840764573276547
+7277064664195765848534013590019916383557749169375559963951776576181466602296914352536749809247940247872302329782226925806468043
+7192135649991318277247808266477765244997880386860464765070023950465490749600254005312168230797058556941811885358619067264540155
+7745942254017380214048240376624237449522972214173349323588251697136718540827110673334670762835744617609275818957162829921297194
+9308025524075793350930587214905796399488049433256186463627589329393236892726854692113712455277309297788479077266643487682416715
+0884436213404481146144542589017779230742715119840784000653264872459751590076369675379177572780987987657953814990135600852985178
+3730124530298931373240431341115710398974380360265132276809345755075936226833617497570877144367390338090832665519341170114016004
+4487614165841966483390809601332500844989818602599615930254525814591372642009685306021109318297597415196166334778397096512192919
+9738135052767202788355804851260065753666213740432424577877433994081030576175406007197406894692674226624886870624390536370450115
+4972079333970854412711805268652812255100648740561624233549801666164086630826247751458218621070591048081789263645429911196722042
+6264477153602121971771346665126521727114186506364463613567938860398188315590497953212091430368302124372365408850328299694402187
+7096923163132078408222622634338258654575603652287595704602066710353019363339205986259588116309830845020074124235604674290929803
+8620319232582906151287500817533307221837336344013921731345438451489042597967502976685688377786979657248449082964352894633940456
+2338290774645460787964275902190755185934483199622353782037807590665967507775691698706742149485822727584225845398159573488959138
+9690411512559467787285374715845943612220011261976368220307963458032917206195128934924351124238497339947198608551639030163894645
+2522942273087160899325601687017261599086953489151039944965907240532011926664847298253352884442034273091440472287878013270485552
+1149024375555901235741559582840384810679491209306220816791833779666244374445454015124428345163452944670223052356961455086641846
+4911582198911887147216938492382715818668300238279079306283822841054803949022104243393368739761683072273825914099989412306146198
+9386705286204083264591504191247314048641049210231970001783669995174466309042384199881382505454205575494098905658585266777083412
+6597181522016787958122306510209743227930379650431716531860926286813430719462209935654406493573792531684209677728726902971780496
+7454713877871827759953186012939103462107245349313356776395316754209733644734837949073664445059496108161795213098031298387675255
+8608951097824554197185243937211248657800767047324365682759725200979621123783045604563185385990004228189141941283634284151650878
+5110742662179788336448957887870922104701629467080657819437644833165127617594897707891497065965495615130086622172410875337801320
+2393400609667414757827986008711153834467770780863121443973568354701559598965757992398836770293536284505657099974035105460765424
+5696578078800033701889220099620389665546740070731873354278406253021517777757298261519059116566359233204858968015644380662525991
+0719487243613892918578289524307174160805716406329931625803050285847534463223682481335815436403441752588538391995273084423051287
+6507583132575286651290896026205391515246827860101127710478694329951379556419208073957900692792049817183622267407642643093594278
+1377392380718866307096826670910831948575020464783957275980748872622490677834200043136176315679139636646826582155786548373039619
+6270395893591295820132189201839068186418319333704429754904087462921395570639063307809781688462251183623162844581418406608429879
+5043135604579355727135840436265306254474995931628655768285052525690960177800386175175072542969753822246288489006113161219380471
+2468870042718971405890990067722938578347935929978019468025646064389136067817188723296206441343678326386730657242344326326352583
+4850753963828793552300794217123706294629474328454245842829452531896699931041364932772984481884556840376569123447688057207356583
+7057042541510451935323810217032483925746383540989928451101483213770975125680075200108338616874937924879361446516778250185550748
+0832810498555353548220097752070786325088219810053096162098021215047558250904896030368053916311890910240442204298949146112466005
+6040761853883330139655359121858985041009457655416978338162675746762113717003221699855200571002086517873586911211646864010901906
+7256461701161490507120388412005575681572262509069280090655692691681966297281536854053796037221572903258227405845942489932658062
+8784119159896217889610742272823513831023300901198251714365380671379756902059751391678189474782942687418296669663414454093527211
+1713004342725426977027637006978967397759795215758374886596544583647960566243025979142738914314172995528789806147213520151545065
+6148932160477331319836946915602714548850688076504811022908366977684207197869071392739615383347277286078886115107459496844571114
+2443445647690017845788068401719782165485185661849045242867722200580611203950026796072201135775981201642969396670605705878495845
+1294371619212953132417647548708472622197636506856370676160451382994700324005284453279834375908065277166478082791508699598722770
+0053575986014268796134989286247216849523870686352637864684792640382519878279886269694672196689841813884729761559800125789968281
+4079017492141445585825743793710894771763718871198578437956220555470157513268225528361787107561094227364687598864249537846090985
+3335615421853085612471428388452383268898317706526014807014690533942186796242785098624189594771605450015209158202436565395838528
+6313851017796457232684831975868577197008285743175695149676285515896251363246115689779921987378115615609824156064808941150859547
+2765806218554516717364886537785391971358807028025829434420213828068755277959823238847926003687327479957197440099922200245318093
+0743837871847609090197592779267491068691643664874076633968061486254606691482824855693172784961663018432092989740850414577990750
+6025684120312451259686658587433694029989987324349789159690905104220972232002229613273265979326232104213906084669828970966380427
+6946689887211552778830098495751925653354785324514999092963991842666284889259310987400348941690948665027526678850288865496058905
+6762732711489921976841952967909655635081188142889946182277259409310226741889437458160117435942945024450654816897944448992096154
+5422044978529069360644478126257492572807446085424868838210351520631277115650603746786970481265582987466949165123354295111201812
+4211276624640084315612918421177060204230299421803486633824592006573340606615889580523464227765304350439006450951838160825473751
+1889210243603037535646067281045805960008570285172891727145769267831573879630019508324069996866828486890146852983707941528252170
+6433944896458400005722683036542919674416232401927258992043251760109983309622060221449241884161395267285324969554809613236559401
+5926828496890530602862162152396620975722541268836002211191264684743325984168877494942640619948750726132999624105124012640906283
+8437529190279374121273890161340277025282882572337700420322280964590810755716568643364840307879983400203857287989101011632690781
+5802276041061620122710926329386353739806320420710281218622737558209391349689462899753335081329268758815057487656715890733084223
+8915069186666442083922633115688459542249351209368361689010535548757066038294153139851377020698884275592572198938097053313533421
+3618393873597153740469607428584632822338908997205070091595456519416863149036488990139674096344263132753025929808588767591996177
+8414765535715090848046152050822658084473018911692025473276058620384118863100457752482347145023516317250246454398495927754913591
+4409298010504839698734131748484717641239465901635152376312170896985346043211365815426588368753012122770591860188057761705660735
+5937603186684235090583457539320837412342393238618817530913846014346149555309319385019839106489932216877734882102311404478731716
+7896182092904946306296521788524236999972318921384942071102716941043024956484573567729385887708261561271188936395359650621440543
+9381772394748371157597820184835066654518409316544350915121960781236322808659004922335381181699829103134517372303100027463245782
+2615260350961768130102419692323579521155005867350775325462551282112894826272075572040191002407099324856614539494210810480930402
+1838597774381264536500359028476517592435681239463143604712064430411599943084702827260512914320943321785685269655653280527187527
+6303497221483801786682166005068915785511014637493079986822276972242808097676862236960849777047832121671397043713182928176830651
+4198254431094795957177601291882860974299955452519675630067202852553365287181631847719984611318356336562220811004590160639271651
+2089050062014249099555113392986787327862396528284354504971691665000330719435672605372528268724943691397193582081997337212460855
+8717657741330116057938366732697730717547522872552360477855457981234742653137379848417305649320084599648948083741462795882532206
+9986804236567371664160082803763334644507241277854017370156980387812678877717978239570818728942909512587707736901227099845780710
+1187012467446764171881903676699687486363209718049359334271085642494010609014855350532206473984262423560106107436149534409159662
+2848539362765385732985316450544140366071147981646641820740677994697597799634870260463776941968992688323272637389950097251845343
+2181340059702615616436136969810778034448257219485660110664564303142589278244498041564775661983269433643752893242421364842071587
+6511475958145031560867412663572535560224504744829799500512261131519166232318015397419472829178929843115481631831351152969869230
+5907563295429072630722334129008428981723806690819380400545768764609783317272102244876794754684900328466037092277858030276039049
+6371121545042724094475375695524854871280733127714683231595927748253222937280791764025222016369882957071507439090065827190758754
+1326490274618829941454831367643360383905788459550667904893538378442057279259437234426288871318674319032806392619399812416955409
+2775275011488829091588325070565060813564196841900611728756018532857865700574781000487644896468359788252916194701281784442869238
+5475404321259151425741175250657761031096608313986258427026901467928877964154516924617882931075782136380173762818340243425882456
+8098506275539721604499982773326806644420333816118778369209316210417120818431663778002427348509174034183157653013145092651819004
+3184928471078890543345386093573923680647427432807794321314997911033358058808825224490515008557540951525337845495688169454435522
+2663993815050031607786993170355950506772886776860845172901406916363156294602197804936561148186445731375733299997098917913770308
+9652206542382536216286608096098963262843138133196068261154952924480494400928138047212132673039123404498669742532274932056703877
+0803886057269071094490544437295692503919136095718722047240291609927251689451657849380414877514143018375735518559305335464120670
+0151936480170888759767939879997438315844081206201757776198680712499035405650084830184555439755477818487911581690050566831394218
+6229367230673286153903588882341483871782570684557378319370079577894075314574849976163949953230620503498800993353619885098682722
+0775734990307483598683533921005381003594918538823910337693583925400749988570440308274068133400598419503446320537735625031687287
+2279164484478563946971740937436182665660391281989609876479617857522997660917074445342075564734477309946731477007826609533166522
+3758123683039815493345731508244661356741376276550143129350958441510802897891765417564525850067802663207435432004216770694226804
+5619370786333060777254420771287566622455383721762137194440628363338996839313233289419808657699323597544032060605130001017679348
+1117350732097568268814555936831091979923626150476679569711035279777989299558634893220687598099570940599334574372587146302188862
+7465078440908857228369280211059007709404158916443923372217270156208307015594931088483508995735817533317081734115339967063512432
+0277551433478001259984748926007853394677528181409165584238991766092184666080139589261333280556946872045412337141801061054086949
+0700754560549557192840941960533883683916477333049889110496053434388836650044089728945956844381845980096615663986249384912038818
+1729833498846421646108320742580046475400334773592611265395391377127688594599285540845684396076777993728243626683212706942573378
+4323511472129830807288869567946309250674678068275114664508496611904796208234885435751853338278854135085398181237686024172180393
+1312943548505486065871582599174831836548648084308970713256187466678464307897110260321658188877464727357499093515658589884692245
+7139584610276191442567513021000360376560327542398104492743671139951823728316211591532169872633220764756742780779371664542606277
+8013300125828426771757381146217871760111879193645766888697436656318066675243280906292568248974540959337990973627561398675008197
+5419373124232954726590126551016645137142696380830673731392642951542537238565961064580394978042654467730915963421765890733361548
+8922925533382884854249653772799918390864697404746308525228860651400300505857310156341812355891928439789989969029099008533806665
+0128219411137135309941467559688405403979836275303036131774092714874831957845954239946311223981403764141665925425006138193699503
+4023035360745761142363755560440975222622652382698883967356728120684964102122995320575139970015373461400690787473496703365503109
+2193654449177213661881030975620088565679413977376323484863510871705861613106991010472484286534395967108522932664799263272973605
+1651932770511765948726250021128129739307128956256839990590743197977037091662728274789578774568077274689428101918180304889077378
+5017924617218629587957879829522315523692604428645809008208520226544692314383658761425382226132125228054011492055441635314272210
+6749666157481037578188762106676697225815856020636806090419991079970372071289788209874954711658011019178097283297120172931963024
+3867624578607959056494862536265389313506274108084087969185322137028561490827818437756426384470803080867883480797295503488443754
+0266755732085811371635896735784706558323514361613693558482118358007540674486152236347627273339110326422500120960164943514979392
+5851591583094022546650594344855608619956936942520965617453776819147723734709318492888126759979035908706037791854416714517089588
+7488779820804386679237327683610073367094612676999550051056279635818725821831859618176236859057491859294403215135785905001415728
+3397867405536078184923760377846341551636533657104459673180071634565287960125731400588939475716477977856211995657191117602660471
+6368419292461966253403926350187375212915416793685707098775001247308325202429711397391995493844090131420300451991006099818565158
+3171884061798508018743336874067220372374917564318502076615548912819919624484325005878069566693150527749974672352053137075239471
+6765298415501192506923578604075674679460732604669110708523132941578157177568853063216936080050749029655642031375231708316371762
+3941656184595817536876952668926168956461631341364895778129612449325569155094729678326528659230305783051788455638170048468709384
+9344704062107618220092102502671070488066523904860951808964071896990152691743696929206393427492236495869384495623953241985933433
+2329954473357680885309244441022618801570174231106127708621760839070677029891079166854592191885991850284207932518637882898896696
+2253197905988134418498970803242763736997197997987724202146481273276883471048373064146605033007993208986500108914474101742235859
+4471673346443282932636516218151183887721959139730007987788845685281052854907139082610271978365656275535187015151917676999391516
+1490454357895502187362105850833658593130025904397280081248261243837433753996643256759896119495710470799362993945917928340275859
+4187480193910225053682324326478852139878506761849860931936128187212907303727615513834095500089467988300420504891523377586019041
+2552835341088538861109696869815032626256269959324139802181242249722241877212898021098564840649196902417063584333206994390607317
+1538928060054617317449920025668989345408124114562616395808759769278572186743963855933221653177548947045222630757626854233433755
+5185848360760696218717214816135397052477034052026614446970415328439572221368707488898468973353428786860987024947961924953899839
+2985590716831731870038599668250152561736463733069492744631154471689685148003517537536069537952391933185169671069870236035572482
+0858819385615354860719000425698572982937868475649379251912477519089804489107469755432874178918458772943168929318750385686530082
+4333886362870957848081259613648289163828064171655224322239708870842553708643760011978783227657321411272976905508646641961780912
+2833169683733846355069467452629978104797868384861004576520122658047677739451418977045812632716306848990938028931383957425588061
+6045777379942977654526927417023844498064089452756699867598470436037381168815462649457696613017471951809000988548875034178737874
+9160331824383077463591927113486291567227954453778702317129507491730495740733772073822607464672707613182092741352901404225499494
+2171629178354382148962537134449119312001738349076684871759101972177169632459401670960405086152157843086489006781537667287047896
+5465718260392150704046827088996611582230320415786650066647900151553492798388495126103785840394545507668150495076747239741124643
+1419544523318047856148530079232229449051190304992694484547233964026124081035121194889038106213961089629592355710172833338936041
+5735074574334557161220421706612819925561806730824425800383474349667304718298810588448596848386045836391940535442755152772209476
+4477743831927353467775816826229193246462805293097367869721250682503407993182691455177890744118461259199550137591872314970843570
+9614009267031215091375702771630372739884751484563943485109876681877458872527820916316860531787616767154557713108421464243252888
+5725244451595751926785755645396186934606833650722629688279447836080615920686865486122499155337740847620671316549690747377719416
+9886724243384291436035548475563689452903302006875551792856774087989888845839795026561561511158603968657727537570783565987096483
+4338269257625836943750609173139824275314999458619895874921046346622761766613817248643045610302260828228899586867769128173831852
+1927251435241586742325643335703829021262110618516121300640702167056777723519853174450793473043913595814696522118527504244796457
+3599578411448167894106533981801012494310659214850381649569414007781396645447499689729938374104814729448345077680781325687345087
+6129529633831819171439689515282408943585760656344118595138870514119273973014358876594274788901442968142994742135926265337385656
+2522744449484255252321589542733596606602045925005526885282459116039248444399754430448309551058351839870771919853241700908753171
+8095397674156020153025647112643503525783203561945051043117484225509753196255050991995918313572389826508756030729780202503607157
+0514732746209410237098921106270758705122238404358107693018072790601247661147289735400790334022315641411924147791473123654604067
+2183481353624169330708810250088442996270202852800382852132922090252387617856118236197486397057001588957700864557493511482566082
+0159554686938426672550427425422201760923684567404107605954807954862252513544057244716697622930133085009155635119267747535809775
+1603870374074406842079458547774759610733574985005768921583657069449807861035511349884403260777475545081121567326386609338253275
+2866478551802452645398860404273568244013340206033503958336009745540839717584645607628126532817660071722429335530485083943886111
+4372806755879104949087031501622642625790498233747556727536449464577828956704936323795941826197457122033168971930280473743209480
+3510521745467987614604622504324811929598409501462197588604391588467606320835512728358214802216357643065451820237801293132895101
+8869176817884529359989957422435201680723727230870849702923220814297956988224073755455624237386035731957272496882413670632312027
+4987041709615070926110617696999725204352784063869478762637421619822949085893727644701242995534552198616152209092394050930669848
+7400973738218421741284556096408600962957422728138542260382229658265717929340410249216494966480842797114656043729408022372140555
+5357622280419421430680077268491817179160449030679507850055675685514803114136633487732178706581280425610186327901499849008080553
+2063614935667238312237638365326101007587181929899519898020565403780654677915752203035463564958973934599571280127628650025231204
+7510339610097271890758575355760181313472729121504677949019841665976993380277166759244310422659174282752504901557558455360101043
+6704624590746564335785852066839780043541376118703961641315331313655337920280405840841448353766789935381787637277026193365826955
+5718584531080420228299782199614112550723022759714938401551695221278973774269123526563402857239118115571007974128747966574892058
+7406616537246908705363274038771943716880888382315653131428051669734785136535017075892856676521312977758275400592055721561155447
+8191030503034523458658590430731690106155340044400945735308786298326190302983231623869556707507267012762969572969229893222326020
+2781627756283482808592633115010135954787388098836449433663074354764942592857302479394320001436105974173300167981736974256889069
+0749889909665269146510382674032370824445149525831032970035921874308716508078712017288693000420564774687445800320014347768102977
+9500582955080504298493442003839451470653349230762999448413032412395803444854529134420395637374428892260393652466859653474793248
+5578683404816116099839255848388989533623282136956100112356341602163894219640627502458957004434668830525937659394378712613593339
+1328818081682559186294868249152029912791110338139114004470380993085670292745974492137182403037306610656137695392960137614180452
+9752978688889728250401766859342517990190156836045937377483717028864519242478723992053825465496992411244434140736698055778811865
+5764034558119091657996034001136138512460220698471156208113839665880299241195462026376651406117658603193270831455055313097779290
+8887190533917978952783942478895262358255953083684956216049958401478271139454139129915935858174062762845986202401574727546757519
+9965112384492455902741039666831644918325589401840520355227650968749201419553213336728867559952057316374095495633674649247673155
+6547477349678905420240149432846633096396537735337479158019850832661246628844505249719392841713290257003652108726047676880419068
+4709595063724483081528398865202332209399887790016225322294096330311019868576291990108551198704968033034014495019187100300731545
+3677983555491782274707240632393630038558613476413675438434221141668472183743225033730344641440692723378405837243484642959062746
+5604991163272359834040422515862505640037839519050818603112192411600677144216422234215431187611787844494127075718764452791848799
+4854476179924301594123281798645361490338402536310431288082224776520403651635476604940174850365038818289755315902382966023203577
+0810744335357702561567797304986145218660883831691187353402861163846458499952189536879044115452318681728624510324860015033788398
+3979771283995380891938289539381044182171976827997056764348788204187193621090041996206584024348644400402675325221299998818648561
+8560553235856018013965529605400965645682933039991913219712272084018424710938107420465401522172404020985846364794336906931979136
+4463662321945447989909156167276620401617659159053053338198477063314745749076987397606793494767276193523264007206178167936213596
+6945045570777520341473278974105523918485559285787445842507870137014286454851350178004328369233461521852484045058748849569462881
+7175394733133381132769602280613000317015438488548919976504824538838731947546613872200764083627777984989422833194236427886436510
+6841401583932488101726607361270514543381198032082148492961394207816779730163687527133913837138426969504533356370971942113680465
+7438297763442758000905394998453798098283316097089007654200747461809281986645383560583766595972712154827834692097585224878349332
+9365726487547590990433290508632050107564671461069290060500347861396555664994103630437491491318643117772003180597703910105848664
+6611643426610581687045714856705413399193072506247927181637882082436528718891021527134176567154185837899481317325358321239700678
+1557904502034099580005949862058754523860889792700842593217321816597173581797908357156234792521428404814333336278006477527454771
+5551300020237036342120897324580866490216118116991149735001002790662102209629270626643498774459628186650438561401066616780089887
+6490963755355736580386978526346909059361347064280111211229508805478817906115930155049278075845715671257641653870466615953910939
+5214778972551839841667874021257601195235129654518890488743898996335333591775608284908553206841411120044347642321931257964395096
+5963500480745033263837415489981452116756935833729630104233601643805643301868453891208377454731826714298746739883158478178624208
+8078825488224820778954240186836158374373671746556003072588357835036884385547573916766540198508057742745190671930027702184464479
+7807519854130748159210155879811678899722270728200599689770154189194726372412310007746266228667023082290285051427818296004435318
+8849779730758648974379073101178990211676693852201291929217145528640734853429497077571161674011066495817276757324157483849716817
+3827352998411927949530005101476246283441759897176637008058185334546170312583858564041585383266413483217734023667361663656510262
+4989459887640993845875939547459055523785574975836774839383442442772727790780196274204446558595371067248953971633261788681833422
+1430260652446882399259326117845029992780579944482914613560754920430392419419801174119306529200876322246749783122971752437529985
+1073402550916699040362018956704245437401832452382196705545206547444352132288265525961915924743830388330363555452775455714221746
+1446616034452999060536906307198084433181209978784238878045014349105221877679941993115397416711191417693894301857690745032510836
+2955390019036983033546377278387952218996955027373523655965784118029086980123579985775681000785897246210289721704232358897262443
+1116899333926038276430989136011993311064835969966384464160468735201645112827713375177166600414004561963808951457633980244174631
+3365167597668328545027411315066184915713562624842225290359331084124729347322094220584503855828183282959730835678676639554531692
+3703132630286521554741077336255711977522731641435705473997030102644612053700886241315456330580773390018414386585814426113751822
+9217494111509421272989272558690493322060649433443466464859990829891612802636240902558280843106767641519024486333577210250455758
+1991150751561946927232491146002439007601543254992434751580119323409611022604175456900099304707614992483865118197257172247468485
+4718289269042762658615396540607439436267108037664826892947523927247548349191063673761417193077849996352799507438421286155035753
+3670003174685490297784963434080516316824119943018705327982929605778412196093833118187456471893403114829335230172542023511761918
+3530299462397538994353624879221057016014513591355266971800473995195599575301873296387357918288523036075230002667564181209941862
+5652465756063919538830640228613516853681348031923008502389424015416629283480087157633179737963541694567718976270634283296698772
+0628398273786061322495772855081114777882254155541640367813109541283460927308493462443462004237680494256941289350455650052190389
+6530923425528750248516830645859529161548508001636146477492907827739674571658452569696309864671893300056851989854105052764500328
+6377838408857911124605696723808145124469491655188029699697020610066790779133275460162800601521823852930699312176096876169139587
+0939964825101402137367079294180090650010316165686145129739428563266232844352675969324123159076365905057635263730951535508592474
+1811804823447992196520518580949056544426238843325335935996032408627339563545875884333166832898448807558706376176980463476019811
+1853671195949445539340843650229575714750539986544526174232405759132358558190475375028485355385394868549681406717987759935904458
+0905656451763972780540932190579104438556329939472118207647554428546869843074735432587357981463196272333295652269129883611649971
+8081235587163561191593283995607470950948702816215035438010567011848029435878836700192088876498542980088266248768136664360732349
+9048395346539903256416069243232533610069691095414640231288922049229368354092313481960519237230458713935632653201847905841902926
+3586899375981532151071970206889742452371614510846757239619094223086588901204291404135214382914427118575565088049023826713070734
+2259183814776114935570816268571424671175423119794189492522671432476564901966405647187984087627618260356094922535155595764746633
+8775939779211866982932257974707044029673787248018990390269181484731175023868082868637570701885688930003111950730117366747034776
+7292037040878433775921745075599110933471784681597260046655966261287697859339714368407310137037826533774841074326027111292219013
+0255740507228750627788675142293353045696200562639503837065555027761345191438643278181859657112500994447007605647817675710357329
+2976075331061106900800437561657304517961915727589721564040507512613786451696450429048216474153539650176719572123959448008900012
+3408433706045747990792868143612079234278596536479367304972783738238238625919742682436942402201332632706821698633101418726786131
+8375660756604324838036937822438189146692980841058943655646096987446498055875487503182581651007976496878268593478897138465125407
+0302161625788138941756180586844882835162635784547013096553214201480525116709804815394793585124634598219195269074280104207728072
+4667838900407600665351205946634451166183916253892825653381319301710998507256107777186848085957403008238368100522944303632213848
+0568234978451633682200113830676859774853569376506354250671989943595147694543341125278943952146653132296950198184251693558754266
+0837997184654618266464229835853893240382511414642926848175904359357425914225875122515607126936089890130506925127703951001817058
+7698607971927804322206607636649779969047920064098738740542516881736563449825854806194526365935192809082449412467250570813092077
+7597321887811111154968364298503454292989382990719881362442172931187037500402048057328677657705369081382090672410230632333022578
+5702691344767100466202486216169170905325756285673048601355109036801723677816257513289352210067825399512675664902709627155754391
+9534899164623786842509061739505443727104012615679366121874758009252764781464695793453679090140639672566086270483355150124722338
+3629599380125790239429932208245186801604452556987851483665390481177058173633973798236252529147955843797090679456499291551397899
+1654839141753372209578242837530384383897899016697607163271741042796206564645006293555562819243718356635356102675076651792712069
+0330578183767799422174048823749345411130436371482070584047136107077445803065143356378310883097325525812461948426463818958359831
+0535837083229949247061916351323305805073161284351843348700635104127671026579915150619625693973299904452300157134992421628495782
+9135533592025422741289488252334208635046166354163256661447685205945401888767478319569656787569357811074256962118550453119004362
+9301751134736346294356523345255306657038167822211402293117443464784840025659169376501953957672727051530179579688902595680131766
+2105969846665539329882900056874716520798786759023512793122449365556804018453805656203040461898429839786920406056455733868681013
+8994359707951012841246179634189829024194191300675090705148350390247850109295388787831386650321294752877084504137894482370739618
+9241947230769626839032573755018849701961689378840022528468670515360403514925600595045782712624516468191893178057825723173315417
+0398704518600034083166938112120280977963993296425790225059839016038745051472686938943167918298644018861694001602670324180907739
+2829253174521666979009820015551029220993105373115142695444414232286946938928961493390386858301002697320226848958500348592987936
+4933376341875898717948810316592654389756790528913140902980810511129982071300880573916140408222881362220907631175682400695211957
+2728405831786952505365442116971677026094675638127255014104635321119617454191227198408175192550442007477181962648595382032863011
+3335513609023390087365324523236604049358730860336918649941016742564809500323096143070248679219333226141951672644858949079743290
+2564143013685722767288600853878709769356311565059463598251742499173323941411533573854915762183775988798690410191696639340413240
+0493448733483595346076056156947860868081377709049727106924154044343435604871736849228001533150906569243527614792377672885378205
+5757247991130415486385859064419869200094851432494013487858837812428585929428086640566084149796652609672519627454844564932256297
+4669558478660881121021903646645372020041434507907448258764267056511994202274610206718051374682457426295364768694292186976277202
+1564360996091464350826834839280932166253903015206256531264131271209638480781609315412345487344374301996139188255108960560840234
+9176534815648639973257109408451729832095062649822000160147163265683826755303899059727567592934572490764864402347275743547218198
+1866055495605517210298107031806201932208987305284317169767415130763125409722583393741250961695800822861253047933789380082578910
+7563809612558319699283127796207634523042191451596228205984495682290513031662522019531400901314878626864267750108819514332947951
+6013217317646435086018804719571761416592333129643806900438788455325630320446510012694647580590342912656641492584092556696246675
+0844610636935384963725961540456988648961187114742364338486232200258126457044861826644153851981432318719173242496404738484829592
+3080829363782082227074488901159023270312983944302028828324523976099006110195688729810726298266450333348633619065288392022236229
+8005690472921247866581261895577036104640057531331680489329654614207889686295106419176764455962025382611644995861348654828098933
+8502321967575148172006469677676125932579572402208147927471694132908710196626265784804209764246638587086749717612279459712731943
+8253507041283227562754413288994720899007749153170225893148651683553291625294974124954074490050789574119491844797138467527966227
+0130509196073119104402816135401821552059355465255575401457469499625193746950815086568670490180348072693785487568778765124602003
+0665248124119376664057125582265850335568981888916788294854156077917276025925880496268355143677289608433935345978812154208855268
+8995137970182597573167629723687168196388018417038021858197249313810312106750976993518701591284371821222304917627037046364482239
+3380163047424234535936046961259910243886634603953810906816744443879125914109276466757734603864050055610106148478096732039481501
+0050863632424997195774488430947153709833716798293363139764056905080948883372556055175360309201107604690863026027029304809129018
+3159045522676282622055741762907017038764983291766901157880220174438440331565498671114637842462602216932285417970008975756029800
+3552237063449291059014349162828946704972597219745549772402644156576458713144836954411568696563098211658803621586740322438123527
+8553792749167921622407818214329886287689794104816641507269131593430918574387850051670847355476478466155909359159406347347073422
+4529077230987714405406119382703861571668341576429308147647968381984164008665288474312273798880569173169482210427510225857144151
+6873466267196323702969428729542596817149488353193513581368049814798979078196465830515246880993440065883452528995023407220294628
+3423764900702625807926494346022071251875105005653050523263476206366063134157656968651581937910705560688575444683225925304492434
+2952113637739291573792177591055762311484591345740602655920022962868733639951191003783483933798477891209504511076833970415208477
+5918285063915228730571970492875778946493408022023485280196322884176264848374770469091671934052402742006902024842930375953314997
+0188283754328437589051211543538670804314085522712102214064193375644277314824255259794129098802312806481056628400349306174297818
+7400374465412082001463306963438819366261869661341067811137716763449961651069723995940239925017934226230532596999220744932707685
+6210672490680638537370704393760193333970297977253365672997212980801329671424210333810500664050546692669173806880821364438329547
+0441850655848799432631375117017035628999017015487913470494267041654835295714453029034648907258088418618148803149605119491595378
+0667709470097778550996561398901373747557627918533058120957567808028277879620594852014529739234370013800886373620787541449928329
+3125515897530266841998191196333295200100578758020333846745697177799969213733901430202219148194889600422499239512275441137216920
+5650415027342249979224454839045392096843643602822206652387425455763721764312986203030589819856297909492941454232871627676382600
+9334860923952422719693805188600329744718934283065130982713900165662458916981874159673444880197331666542991521443060535788337790
+2260464469972488038180467803562022523783671731570132720326212442908194344858555602668263231905684505806559421525279834670049624
+7792295078720351079690690721334629651981883246931635344717773193932081371713539221551527543695110154112122644215377568071412160
+9195473483543180179899660415512485164196998646076213127620507751563271324222304453084630241541418631528227182134165081602418516
+6107199131518105376224811112336028754695240510430182476876463353393744511821873843541677824666782764783493452855094114804483949
+4681701662176678506643507046144062278379351438997367570137464357422720669913574736380880061893275748247043675527436431955366100
+7149553832033242764660394022295041894654956152213899886346680985491273200086975419330405272293533518246991447255727068177450390
+3655198436587622677364860349928319378663047397528676907239140945275682820405657108502041392682979560846597921188888907265931036
+6476533442276806500783053564071177712515831376234094631885310570178318133342242810813665266902989059805523937906419013727894188
+5431372487274298724777517697230193875880937677668764659986523658830811826735084723524757461022654674192380627828684371745612348
+3820846618376083469895407196241963862417850743410179248545973893510278183277393709562656195366243761330452232662018800107769440
+2069720833072682115347026542393190511365870201586051736004598121210837565385863777323843786272509797134422300430192141780468920
+0442031082909423594641218252063553777303614020588281829250848330051744891712248697144729676289337492695365177253047051776547762
+7268639820077382077506959745238922291525171731315329144119549984484846531136030620064784882237444115815092112452964098100945835
+9872606636855509027099907122315750101939814965155251567403611737103452272009598076995597635176083234788901670535978209531433759
+1085327638195333244518594079295886331726523118261222009427508754702667381643585015276186491128806622593525832828640622269002176
+8000558812466886549021793247340135947691306446427709528028498200426365682563584527832696795214569479985794618339152398807896264
+6187988847312530289136504030984674599402925257102785831329312431749794271223626066515601194350356075536808657593446997124519277
+8221593778261506773470868068030158332034878924556789236087379527748372902142937754401272228850387450354124993708739623158789162
+0522225048132576688432285718958345124544338046135042578516691967468794904627442698787375554323557096004260191198734997094093259
+2462493092358156921232365706546429643442698260566011347797207644508552329524610339812245114706710736520675636593241151933904714
+8168806409481440220552654041925492552985114821706878419857282323004033916474011864732600044228285384350058041710798941857144196
+8456183927145192331984325229219292792322346278563254801756089348717336352552507588302857665733398806159165657708323657950532344
+7959027432654889449179694030583164431534165468437531025326379868797173494533488353046359898220027884040904102921916878818230634
+1572671474039612214962772842653777925720919829404267236601529791378862012346769450214240286963754895280462160430824808649254296
+2713235643749557564532205594282964657763877791499599519104896455051738725475670902079776954156280521778944415643098383791627273
+6105964254598123007279257593697900824845572590247120355844905046052760198392683039070579501029336629655707492386250995234644336
+2615762358163929247483738668566291188631481608731204506773561888479176007728316484171079619334578564058039995926257045933155309
+9915284962226636771930258072321745421222389817234966851925987744510291810977458517680205953227386190750476782698954854970577352
+5673578687374046860672064496277781044455548859373704110716891640260365042726694184132711815871762240294031220477588483951772686
+8668728817231201425334885333412781573848400038328099971193361147160493544335456580227648349461318031327984792185171580102807503
+0169567182553246331404084202997183149669206523460201655479386533242862563036582654644409484005992680312894606697548079677284436
+2408634459821807360135371085559754639951676453609356475891807606645289547821918227592956096670383760258316085039325249167270345
+0639753426126492725051857242781368140995333223012553263382165242568922620303770347983405643905206504900791961601071942284936427
+0871588895354801816598052309754202243843057099627863238724184518284044817748295192358320828895054008513930794283973928514112196
+9798654324310664456635488952439998180995428408476235283937134417681364575355417817510233366035067348678178856527757300827180944
+0038123007290989063863175985592778519488056333171045377703085872568160778246582018586168915869948568385646644298618780983546355
+7869384600764512734048062223566504717806018441987433044570169614606144975153300488119826197625737171672582011169222743563965980
+6977293818241046999651425289984525444775996710580402650890897413638457082477468109575400763448366802872239506128418904706794072
+5799904603862986594106662322483455329279349540532965537255861860553280872874108710364305979053889159756036410545175996560632213
+1905113425852351684154357685504469533745516493501062212340862826870385326709406031686063551224557399310052952422838419329227931
+7546871961833002037605725905779115533289685288706841277287949763530450546184456445185142124516259820881277398739985868903009290
+5390552777664596373149764240028438950449670876087502765011571015373476441820757391918243018050536384628502031771242890575429423
+5602898175403670523511959645093602460733826479169195731008780332981500631244059144423791577718260284080812356359230721779826632
+0282070388225563293057775488479437333861437827295440192975141284220068554470734762243654683900921775316128776798676828649464561
+7044919729960370651911034098935618095727733916533962937362197410606374931103363062973825850629444853848346339446960413652519614
+7923852433886365419446901963455158024361204561948757781294971510735411634498000899993250692952771388573089449720039510778006556
+6448339128502198442312788117252393804187619178631365039260121533649897690132658417974431016238776431953884429473283621621760928
+4796673454480093007496675559950785558242785307210144883418877108437084521237518409035829359990440607609053004656855467826840969
+2539967222010309449705096804270772495367746726394308555148839954759386392982542739753442093370829925036983594533194718249508227
+5349079635800249074525176724894658939051245265345143033311987922668779171808073614407324686649849960572890952798590407394876104
+8881074380416317599148271017700792806364855765066986663556628051754736630602571628284291106232498605571402693983906331712030753
+9874937506608818776772074340810498838067037288381814044995123846119534641571274807743575095446827709625774292925956993651483030
+1351712538266765203986454072646816009684736475838189392745470191271779327758375268068178391759551780428792430541942252314370156
+8407859484892460620078868667802179357348492180685724246644370230014476781983275135684947107880402240406891839259873980451085903
+4906163533191850256268583682454988749837419823578079473319346296433799092047235338380155019552271132115175763259341940167374009
+0058465924482070913500147064727037054124622100326796664614046484792704959337155884709332716325316023891570424872580884952438266
+2436800291590505288180953642913700972896437288014085488105811040747638787748114199225450616098949678241069300416404785919318926
+1934599170792002326313718708164205938810092585230289681773510059324899654472028348104884160918328871998687720554532160558923223
+2833310668093246151983045850009608661418327316614685260920047242208439507520352050936476946684777115573214252016051709311522733
+5806306154432125296361988853844471579270461201267503074861984238054921903008010783021332277527690547871326604862832931571535476
+6953887201338700880983597387777946758689636635028887005208234910693065403037992011989492126099118102129494636864406808581750418
+8449828487903174265578895543349223421139970247142747092518020699819810023484608128979286359504168816826179123882092074937458466
+8429190917143583035383484835202769619898592015997875633392860989349020465819040052129531463007708159553740489427112502433350259
+0015541288911157030703391088218525575081861192862772160417721389983310098584001488671913042391958271599517521875772879817883670
+8715721723667422477987285388090627370795114420296274720333968016528373376502351404697409435351445641183117232448408900877983999
+8085119600169893659072473239891529571989304915800525658372770589231187553832358134049724486998092398100951195327740893124363904
+6825971614998820258858203237294363381385260403003703481866209020749805588161211696398124406863222077112906818160524737133236376
+4791287439396340287050946270382309108183116290058907007033269789030152170762597022242414148156450382489069745048352057183456698
+7699407910303700018163871163387977417734630895740976320842794125644044206230844211892365927545147294624099819954065586859396532
+3131672188768311610064467750350104984282723151135474654890501043106825950749943883966630006426594607652504022624213316206819824
+2381097970942205624530028578508606408894416081148567879895026246182144217645044116693226312513033539646866882479709987958089969
+8906558060289356651604127285059333055318644242901255378341192868378040612451560944688746385088366187655524363293058496259834503
+6045783943499511329380195312503328218913377235931966010737751685331040259612353101709972563764048165640905281453608759750462107
+2697778235378791219808122722229257971170129904297461026446932149333464400232434190909889478146390656698937276924878791295257123
+2803907707992452534631676946969649948134841465957319668276815925648168701088565169944440306293458637327427324437179025248962792
+4731713616143649458304003973798123909714421863335575637937266819992047643342146589405067966192841049385855050988705354679370809
+5372002945727744156997261317197525282324231196500161732336217784763019914950265863384886596392669097800628799874734609235337063
+0503789478310331174915570738552836640716185310681333898360502850585012405514745303614418697185463616197057663173866523087604838
+0675037169916204490298120588020089851962810662807481941976840354009840553886735946987601156791667665686995459100468477453975696
+6834794049663185275577105102245452812771387897018848470724588835525127031721746222497385677737902506111966509521044773531500357
+5329174285407427305661763207997349560549428910454568831186538339414510256938492615597532037011523362904523476314189986503671291
+2718934812220309630578226399896956440076865897466517017205703733213982937662658920267819470286608114781834913036578565065677437
+0292082835411024840424424503720769844545589088751119682651139453690649901159394940442554457210310520610468908232856172200322893
+2168944494860484191151489757452268440986053558799687398611861491809004454116677153114993411395893222172780575772632409234094898
+0022046237220608888434835342573839194475118566063006131560443847533169495969846042538404623478526559762435571079702487933385421
+2451919192203771937523596048769324041291130793137730493766482430142235410357050813575163787479425148259744336129889104511577631
+4142550759732390528563707063152034344178846568888223418447224601319163578533878251799463243956174732623278426810354689051255154
+3970640202120158350260730117870456696154229567633606514596475612129033212370234978048801831781364493706668262862093481931515716
+6561924140099494620364526936808552193114041143469574838371934269300545161105733392695711211423415123016324534422409169998476243
+2456534483029530345127697481939835893243537886692901492470290039455511175154304300500928667293566968811328935461117311498383274
+7770989718625939764088550940976599710169478296655836026852130278698487150688281647540447530622442916288092929799874814879443957
+9848763764198437026743206591847265528425238321090574928951078930719540533808196681934811602035009442951951047723353414154858302
+5787946077159159168774450433330444862738778849768023490388074911496672265084989382578533753038885946437129868548176233233930301
+8580017107399342108923739552269357825947129658651850931301283981215557531809779053507136238066452267893979878894161383251981836
+9913766525707178278575810543038685579648619267169136094328824697618419625108889858389235878109542078438921757522374605654744287
+4829229647563208502985033637245591132219509835319418276937992741995767258780935271942567981080789563695276467555561800638017448
+1643138233933525491385701115282638884356620775214978523597941747167932566311974729439511528404991306505854174907409034566035713
+6143827997778747391148759316186369744390378766441792907186485522361511087226349625577289271875444080879557771349971812896783921
+8151037464162282243454432112145953184331053916340169687740205103102595400733446898088691425582734935373310066807019088114280263
+8729904943075565576008704186063345542320788733990798433124383054387825974302546390620173375209936756748717665874520884924479185
+9888909645307351789982700065033105216388788398262734159940626037880383673919937047828435841493103609687935677331602519191613414
+8850737384099163846794178899558085730334694261907207404022320796803770107876986360807427894048245601008966306481139963465178636
+9603978263464022093387313902323305847024620528667574592309994157800256182557220046954796119376040712963053063896476690374286989
+3405947975994172973640043088019552492100802303545308377567580689104604977659913539104938989315677959717470803854511462658064563
+3191162645413432233404183050706031855638390349798393321645475424393193065096426473922012746067572812705091078572123464528104522
+5754070330806062132016998542325199869791387417374085617357171312577717425296247007640670351991232446756043415004205160478899347
+1725194535387949369475223998736399458938442651506418282232173272224426998356393475616690357433350683532939697909185050724112276
+1531609961298179460965979011464443408544699180131732903518616680630569852510445519164321486062756903290742218453214665562625462
+4277461038526097907874522581743597670466704734455633690080575913829222964025366450929288253518473640288917518499198469245997685
+7420143434734074307744766434941598412413533864920547945213441905542326713457623437002740516606230037868321117285609425877483514
+5509703411252690324400121230820675240247540075031296148576782911392574907974824839505516956261324207298130826703943230789524466
+6235427271350178310739006810179034776823843871399578101065895786301705049659021548642844679899589499916930305008178597329009228
+8708376738514576473422684695199014327164139367786002985515660277291737951903297112627302613852418677997201436504553518932602363
+9576506417537859055584148204389221076679317163739081159093922729562344633399336320523856409926599959155324451664857304036979342
+7821519375657055506931717396389844553686714012907465431386872822303418480617283652851337727643122589592938283893016029851450741
+4046931470136635022512650864971382510668763279223722442081085741561189482186827034926915081819290103926309450155161557982601266
+4715454308438516658794722092196206636934007267582801367477453071665674490724227142539801920570519231994847446963269786268119916
+9168041401535492095223153393392138627537574429611826175866774713151956729343684934892542983754029148830727112711391973335239513
+6515970901191127073416539618442535739664555006336299291335206114647465786032988393861387837528101930282563813184667131516357399
+6965025115159934457674823672748261872585621777883115554117585206762204650484234255271173958058407125541367807442514328611570278
+4831064230665616198380860322957982656881003885916660535633639193463684058409926839010861838915803748651536627056017889319571392
+2850377483892889368048618651662404196455568541580082178826055899571765132140934322132515590245447090853398672580050380575567268
+3835035801788676880902622563977805200108581423258706942731469718506605351522050771195525463348620059942550507473397926975656075
+8170641249931936194409801838731827726032358290235160889838261562910412201128942409820711534658779929527668900047257962358847821
+3914141889006189906618830872826326907793134446571712010041037077410013305523598603376182060668984447359850821728080727595426748
+0524288363005399115153078597028593878897064055724890623451683531614421839812503951731500983120346087995189240459208148107096125
+4155453406508028056687037448768955586471685200246991147018630064209861444093780513311415335160348800209398873165630411940689888
+6507947702834259046810555837139361937816955993601288388902706347465220128545880169696095175041923698015462911423095653174399855
+3762547022058799188111929405215622052455625552628888943381861262479627747983891009023031983537685246888772136743333720092806316
+1214549690057757944760791464294073960482795674578197576015074847454616235022841464586043262062684847644609779311315421146732973
+8541338437296411555067873828147460205050118794445175546707442427376724688646895066999337376018755680130878200128406968859847082
+9053903102817499105181101245913670467308052365562812081988351351621302283720868904030918069105268441314194378171102376175885834
+7390879175657202991792721024454048282348887367327525251428650799473344325817058656761335824140200255463527106801978883972849023
+9114858631082305511415208423205161099795092979957887353079774012813446208145355233313207283275642795951235302177270570702859527
+9437270466650300884205636449007422609778006468400075137707364599220020468818147412256802671321760977139033664343323597425197602
+0302618076580610803854795974063518981909366239035024103586093127902225268380234904318024257226627138837362185766291678782029207
+3947830739969480621126671162942463986987058328256455824368521897685045168203062702288692030759860685197940546125045250168790201
+0514803654436570370324022741742361761085767189089724981006110323674867393784988265456553747645514420643289677440464150052019123
+5223236088122199447858422156052424410894574207990368063564291905403412016110145065374098953504598451976662453874666981008325424
+8373293703798267046749026333095880042002196112554036817370313956674653924174972808775910245525212215059736970917924397257890308
+2688275927997288192485396746573266295779844438202521819272050705543165472702597009969819708658965256689368204413111379773538064
+5084094239742086467203807611090720704742678798346329233433650521401666169943202745736920597870661200400002701183019652790391816
+9022357095836768187469229301323281507939417769215045474272231522798590708421786910823915726035891376298601448255283206715063088
+7293988737791411397897393109492140546674166871313197493347838700746175919251207836436115320719048184023218823514733017767389387
+7188783211699643174822974868235729901402276203893157987109644622416046761772620967723823455916506713613144614196470266830456333
+3793370001173936142455344055973062003252783611956485218268240522116090384604646513391487197827194186399975132117817107687082668
+3534299426891086746037016872943029880008565862091417500370811850667508670706496943938696062708498042156433801209832903518387378
+3612904603444715041436728628573199366360323396870491816934924984624193337784171063290043144432026274325167439913901462851257791
+8301153338470277907154944290430893973748596163892611069628643761048471308522954471189690031882490684526895423581669049412645780
+9532276724709021001315582137581907800630208033706211952374871095930264465397182584969831143514075753862615083949416688307055905
+8388236378283440896890187881320950399116639874885181013806820276432717798539692296166413239097562927693580121835296266376329989
+7227163697631743317865706478603326970676879690725149096075601615664615649563621319796915072035936935656249230727588009066864898
+4030193127531435008439718127581289588778728561167418433131262502679346011703797827534339742404719888498611315489306325294200918
+0822596041854995877122241367357937629640300673554434225279391124715516842541288461765835730255187409409295964047110843143360218
+8020810762143625695211304403500380226297593451193440072241550883222759127723312388393491431821749019440262383840735943032001195
+8318237479489554100626369597427649553987985282444811016365279010859228891440704149689826185729924642137537603090218575037482996
+5366847590778547088514990246112762636619967032116058526965593868078207507263589910269699995373744003756645473632293041062685541
+9610845056170949836472700450287286628803643135098265884778110832410350875689137416100768678349522724998316556986352522714663266
+1503726130267377258411268772164465860231491482249362263232011498460531343555282835085236658598989040170763967052694908347332552
+9494811816089738912922010509947751572303760145536902984045309394480942411502821839970060527331347541450194445987076121267053844
+0578064800062529101700072602908332148334858119123936457716348054959136175842817084891684097218981249238233949488256020176601607
+8655837084859592004656876506460130727405913211331057771278893395802267144808219629460783237220481671207469404413079770236276202
+2474357024202046544233057042050406320202093782109005795759352430295741395906001878748884723478079164300747108788119563090468194
+9729275772864119080887672349769974091030926766697899488139685369926038289554489717497100438993101868557613700320201349470541544
+9690121476368923069792412981332423045488814436625785624017824621004713254286195984412682695459029135822031307061078889173619865
+7378777371791906660635984844468930766958298884404755753328140351948727806677530013266236008432182713748064589578467419387451399
+5958115863312505525587296099572988051567717080297066945899741469832877228284562546192870097158128338501540449059947967484049806
+1525360297576645372782766370344139731393001666478941675207716176663153356185352097531952067180451056483850877049391450796637643
+0957180541118429393622724140553758348088782996643755097821436674434023381251140872906157549968145359578492278555879752671991774
+6216547228847936682579390485586625009476953902113956539812453553726263850745606267922068236416232274799633682965858910518609181
+9364762411101864870815658017284551581396524871993598349274914322101521556813705161096159781789698091708777511072561306773711005
+9372502462001712636254133123395734859574314940832644465721405982847453658518168263698099694805090947049141539874161892364044592
+2081215406680382103751369362572309567943724594570823605875011736925225634106628852644577321897191396835476563249653975626106030
+4349971249994089684132392481061788229278189139063384564147513903173876133019427848009965641301113400947275878225261721625731279
+0221661121010559617008273964451895647239826707650461656354872916410348912631911913485548662828141859786059545072528125011374221
+4423053386826713852263693496635804173362348029571154806846975163821408623542798104298751000786068795017683260714515841078366993
+8161127671355970070573405532186939626037976009760161070135615665381704277318637283166773287886342633146869956929128780714287331
+4724406673554759228867043031026142833731777584308969100843251135369865682593955020981079390823701606661557011686336153922127671
+6320174341401698137531688064847461308245007114188039688579142931690284251799997677320348583442367762054912291140917964811725137
+8202757825011219494192886746445679726841310275929718330630078072572216660349917135633404881654966136524906313940172149175596901
+4973259052196790674213907468121479716985489021755170094314094085515986880378978689367545392713051595516162518064260512413271805
+1589006020451052603264805726624921702203140540281094471735610296632014298925191276086205769087410850492910589262019474771202876
+5301512438781961299615681939122770744864098845659058825055415852695585895078281739508660406939859772275150311279745599614771126
+4288153404604175490400855789649207035885124038840820254085618553577028061229192741635233861987354455133991517534727391845052478
+6258955556704090814031626148938140929500657324155298474719121746871071846048890688770977276676240866370191127535467056926311394
+9986426460698287989606477786579619338308357811140009068302509875335795457387693847614672598016435455104290716649294340111672025
+5987575195605597807571132149058303080863960035941811196802177359118666488648716460574884370433012992324776906424681910784438914
+3212828929093079665577584834614675181147027766122500255332258719353578136517199306847607401381636227698622152320466280962873067
+4298697726297500762842637031315949284066464528353792900058970168170276550530718742305480231641988165044232612666352048235992340
+6528595274852601267138855685497658048124785482783676783853867479073934060681129115971059226209525138395957477851256838662435594
+6333253678417649760854615241319608105505866305579272971991684020242948061790638726814427247631657265086447512599362760504729659
+0050552281101516551597310571530814588813676939570968218933911952205870242379775297989531959401920856446210979962385790387518282
+8767289958783485919140054170755933223361121752964753574235200401049015889601531517259131960751322512615901642287582440268512260
+3451721805339224609531183820195682695971871204396323817335046115539455320833063731322682287797699412707522241064736997253801427
+9838095438421652946093122030638044112929662006537527680294782737078006325003341225082530500978086841673076833294743067222781678
+9343880589742192946487883613246357871516859764774916328816004546765194900049207055237803648799342279688804719689248327413730472
+0721971662815930264205326239766135366858450956630362245585637639859898001993676716328053273905567456704608882800064784850223773
+0571787432542029050900323916790197508546510517976343882254348928206749045986326975042209032481347983325984442399998495068210198
+6252008138898607709468342620809002496223471138515742069863151888069692871096460617937300581107228988473399264367167623204729419
+2797770513682558101443641688720044042871553905410373246365721075390692021825457052959920292945148726156660506042073326859993576
+9943199450035463537495910614331149365062244685626306093678223057245690588586113869249388996930139917906887631260478153521760102
+1950460426985566320913113822097771379876492753786278737646554639417059453209917138732302032256017931681335738155323404263671794
+2838332702415027792861677040542052438018840283865010592299818970494138350530560217854544968425238656792859418734080761867272852
+6010463746369529626569768506440616846423788144981864845682008740038225629815725166282753185272670640607060429451038753678650440
+3603428316928538153550803942955541314085414603075220414550257874931378714081625009020301955524753074400211685480928675879412454
+9843069053870715332522840750526561812419932672015609424516373833579891793837439080150576601064726524016745608185730860593580037
+4790338120349419657809887950279987231778879709683733319593125286240898651454362025515251496405484678061036071464115462928635106
+4812436174990135339020055889098969606774850114068102256726271424987296420443648067709292253692100724695627779636510134753572039
+8737165463831035630144985978697481580718872897801411679391604620458063323095158841009595789901639579062186093555920948550517282
+6684194497843892923374409974962663409557384721186689597945008117535697913915795350771799536776499659499378233933827449930665824
+7081582116471192658574426394048422901610749624872891986363877792779389085331435286663561611309448994925468965045010492951543901
+3680646340800173339218788077063204059241257097481947777145409084202800888856762009180382127277534304230302616826742040805136435
+8971885064485253090204122142512764196490013452340872579790701372873179615012971724582237981895972101835369658929642000295179467
+3378697466160221993719637822345980287088027594206423215053076460092623235649859970956549802453476198188280999027211336510921505
+2652711751748836279015697510746966396333400935969997511167766407036252126460465825405459671454621493581082715193532241502957665
+0853017906034458377960386056517204258262136080721053029202866891152909200067791240221407899628896204792320935757942824137109755
+1860549007099165197284140872678756594535459353075535851412365063078974696027557562375802944288504306767016261985686187927040312
+6976439902255838121317145194266076485068757990450059106045155783172858632535344129113251970702093415466811410640476211193415639
+0223864295074452283847305560600110714424512989818888930888094361164360320952698546375108408821282297940103191521862113682311023
+1062349856533324628662077342594233105268417141054370232872638557841382516201012169119621084906023902818960772903834214834404456
+6774964345965594961633616650657071025352025214474328041017041037485163730502274877992356272868337521422636796698369213270452116
+3863759791559426852045781221052728648632252466126078672480213084512794723010528131976170544126507023866299598547784848361822975
+6029193859923289086357438220756059069241393076481467455226491973473927966812070493726378405565631775752820893408930243604143389
+8322645429369121872596731546622494472770504292226778137537611049076304139170096181584862462563435300455143882748092410271989379
+5326365807733260201580801629433084263428632745627040818781791453399164548163815232430786017320082301681273560908524949863305250
+0127708812120756378948747377847983639315742195284498126386446424753766099623540522826797908737477298768890173160498925727449025
+2938525448223494002554985481215274772014195861665818544594199880542548809977177276693721985173829796357491362226406805154130568
+8969218337326188250536163628581836759650127208671515917790854163363077352794417610106050375787449708519147175922505361662892084
+9818570904194161360123724397774706465600642465735373239577049512865171271762814912171304543676985961805640424586977875904966200
+5504575938770959529220023577243022588499122259144158193746005510614090936240126010183628014128216077152330048541538274583951558
+1040854914239994126791549056393295346381943572230033663200164558894293446713116407420635913349055999596494259230893231105260703
+2206196014061006612340848198814409910794456229071521204012047591463330479752534343609457402515951279901699854399989958952429475
+7726196843265136180636204555752895156585913253117092477574090168474904085406088453119889514918675712220848883891583790692329162
+2932979781809321279966736276684170473868093894960203921581294390763273096543783962941941740885305313552176422059326344349963187
+7716303606885535604492911546074803956458411462697046763121884171908019143640932002882802971285171891988638807617682091180833424
+6415461043036191035529625558425951185907448251833755623616264167570352631169542482639741527208649286390063877760359771911261699
+2470130258381358062929085215957585938262216089039199788226601264737025509814505817029779107756588940453410080897136093992799084
+8707632659399021754985431789449236853018112947892026429638184953314257900880019675773825490255337783864219014358786450842397851
+5533932851049276649253727477601106534672571299541307151668502286973847937896722437084410916259029864044870523541806218077954614
+7765554877085157744714903505492619912731173476480412564678818534684847115861709661320561820994876787782948571629974821128726525
+4958648468242228861341995358858962307381366972784922066788447146487993304134477988625345942386711833780639553271598395688961584
+1195610154724201767373227499183087873970044260009821201260837039944092568903479517438262374212926002997007192595185854104973828
+1619364472726153539242937799692428699593667255284692675884347709702639988899768923848970457805127213116307471608615036594270036
+9983245059851562634241554611084024908123182475839572134087792577459483664336562817481606414919540980247553055009390347181343478
+6678203813070191242843917525205623295811411258351922528980269188922471356248950351834938277372740881478275242174992792567496074
+4143356634732380642139347869145766266914672583108623737574556686979737703412637109328384991661662700191639112734811399558605096
+1208518184191671627470570937029456222980556566946874634805220009038965108642318793927711482497435062563764442708954406150308502
+9023312095876743701169506435873830799968604505754154998579861924311377960500475654542205202570979796896262463835446621504771900
+1307938351217139321342488304983730107947723886674861520928741265078308049241789485663045316829261201640722069914290181463616514
+3662774552959414495906707805907185396346911240417542898771207054497319717662592108767592192807181086654802759806348618578837674
+1314737004679848142363776160351558775692327407524329957179113590512266999745499877585915362625510835561292623778541138597816039
+0237557760056059081432345998516737302912533244471786164779569231630397999149258259824248258872090314272651220971111732309368883
+6627477978424025488072609778273019056422203214910145966781125727030515618065001832071393756745595983343475497495207623260839724
+3342966216908293442342817978848639488604191273604917723840719378411000753792919755939336669416561658839344042868764649850515740
+4843734023345647692176295441180249482639581287413972097837107583698158034620661397371501344888180961705583629809207419852455696
+4443380077789857586353070023335893700728665808003439355680624696628418230215872552816714310195766329481088338871468994321119252
+9699439754749964974015300163681954912050318298048480045612220669380962262620582805353459791375378214164628533298845978013550599
+5105714350835688155081910384711576767489399113130569825483778697383765314872304014753426304269107388256780976698871683305123430
+7876749639965180153007689268468639912304158853044482532644498399416286758021429281245070574658924487014301816203665832428101533
+0785808281226435244861112112960701400035860271883263300268756398080488577467688265527817734331234380039587960227981962626600939
+3364281430281513574894870100381156896475296131097244720576919647275082387947394192830802845871083057512101147458345259973497437
+2352548478260815071941762637203003924467368412816659772061510861905396984310747338352315940227937768901334141297190271981978620
+7421497155149250772882271160825127041610751435166048440557936723442915599683580765855387190581730147042311189334715395286473607
+9469405090355283185848987802133089556363626275612421572132540664555746805117424373802421917096772214790891162942671883468819382
+1589417274385691408452755936967864047060787328586473526198572660582234669906554955441129992972950187613542002387015080229290084
+6570356377915672505761938151404215475617807815543585573009407518371861507851745477702147309937407690084987324419699405440825645
+0612011361559116532371585728822626979903698606786712794256913394582020905043090461211508518273342883931278463866340432838401156
+6760882395086214518227285005993629709889190889508417455761844997600135276044719721514847763212602718036483323892756763864051034
+9188515996754462022639889466629680669832215175040501200558563344456278764716592388326318156786971890684957626542747491478209927
+8987779229113917038185012511339563267826387201889188999106457112243660191988731669456871109523244231764354533555547239773405699
+6489667993193399907320056380302219372587627376810666191791189051092938301013845696380002825207303265588504074647639636023424359
+5972299897263342080767319345606033144822159869746010125714876643532020183420706758750193523599953077555495726481141414611132824
+5084488926501974380578938135730935789462111699625550813110845128956753975680460172778115855586076226024263960948204752675321380
+2481196609759725214010722486828189087368975741750919937794099496934509151874334791821893377695611203497436421390537165843568949
+5731231776297026471145248406339411301301972034255825750883890535679456779763247607668575953175369910078981695492172415999716775
+4579188403021146726016160128342968838235818738719371073259844121400672340573224465598262036627730489472180977859344538916635018
+4072803135751982897056486221080699066662076832459383392956264311706786163956015331215770418998634239350534320417157397046765970
+1201062381226118587752910736476250954770728984407318744902312031409265281863798225473350200683876473994417794886956931818743554
+4970302735301544243501924330552682090042743013078749961722848840311456198559231934700094783625178641374367971636230883796585194
+7528520099930871600504738859526542685454459947737830229008160696355714649737859829804718726706633142812661022345510571151124118
+8421496990755255433515708880870288195255467739826209142506221198099596830401844825962275951060431553735295340571732198670724017
+8936767354220444343191661460546264683941090169583805460925893859976635128662736335459378982086771782291262296836018682528094985
+2091822408378038044344571653062122443897076701230437493508375904957950547708046448886825832044918141237713293307448531246301325
+3809577056439308352524023850120731400555497421961772257434416551729487887916281181723448155709611102047050048200739035199609339
+3691135325949817192195090067443211343266627775946016712851865749742799362777412328641698096396095788341581675313236780103509391
+7728571205866997785438131913054881617576104163904406501238204339704104937888486853321561284077020503299289883355914615218277880
+1111888880906892863133264981628224969781528602979570581183128605546822078255116005933260161155631478832277334536041066268750461
+0079412603436706091984459336642210703864450821510237108480924013766858888811236465849216492858539373276328300134023520401083981
+9032711135936968864615808603415924938529404508326233015998723558019026312135753805702013665081865026922455487474085399902382380
+1925270181168851392094205156290625337733809503843149282248914199479920984244708969137863994130437975788618973591803506088013062
+5670224338144189138135191184201868809626683864671529567267492650290228767102161777058656146469480714765930525720049680179040530
+7230690280352425636146176530879993888167423730080287061127174186402752375468464868170738182852209838339454679149339529988407952
+5792512066685362806154726245973930382853685512688261188341000372263049656702777229779863118583825044769296407053427341340382043
+9064288699746230367766305172967912478546347888349770026780079432939827599619309710342120385387650986045115258506762134679333064
+0440596074705090759141142692292577561658123037036520266673482910698027486128518652316613594364723726387332531338654819095216165
+6586405699035556181676379611570196812319147084489164717015394853295535428378692362698265567241807453037131148384149957093387466
+9613627657031243653069021006489437859522461371334813124213550061172753326963975967858093098270917873153645156857962187738174651
+1136920419639517807349446907609250529925657860858085930986434051082566457439789550530915328824048952555143480521491002977432620
+9723285190605612751574356382595987410097040493290287438645066768564593720132821343589116869402530302205558307160327389977244390
+9364492329019171456987187525681281472110463501074399197748223709921114091308897093844593961700969890959904837552334397994454560
+3052838056301761186571362672662664380662089189821373489289767638693120179754848616628936578638481820222476538767896516701765186
+5650968841999476243265351662185220984505585094177664675790716289996388896832182868460012463094065416068468660526498381293391126
+9133890615055659775962704691788335028541094043193982847019337250184246131745395473435608325229593796115617156815138186553076713
+2129458246410892733861841029801352092648607760367150219892460311630359921628868730343711772190656001417014669173768985351029224
+1665772830534776231474157241609092342166046079774561656411248463883336203142778691223352454530469529359343352214726777533890124
+8331713345182730719576279806483123633260411891324365421657390996528436543606816818186451009421810586108827795803801756029033502
+1364037207944391495829014284717167206349222584053304291053816472070825719135329033244226893785498596526306122826589748158594087
+5166290726387661882217520391175991236803942524737711932725364262567914513184343152964650814367428507369519194246642124353850820
+0827084375654733169383428093676562471650179031999648254047083978351359301318312364388282400723012984805620892215650029052432539
+3941456090006715583530315193770635520541951076921761324088412023106545476103418543330517872032796586561611105128147089091776975
+1738857734263197422168561159954861725900337109733462635773133902960240600973009046170223803445433108730659547191448827977753217
+2930699447354813297267803165810088809944869393780407968089194813574507757841359950100327174854511476594508709317805723583889020
+7143123510044372032973820765560757174132206252079849711539375893206623268969901549499791778646394614259993009419795504303081399
+1805751816651443729216778302694093259724338799262345264750249439983832664270852123252647682716640466581767974713902148881103321
+8726470726559295990593930464431140413396151555993515614244807290113117258035592083195115356107951148992883803789239385817695980
+3921614672869622892796645795274584202330027636891305986908354816884938844639467554178364479042973665199423978535726526806853994
+1879696934764137925030122852767473404168885624623810742903886724883175975872670995314600387454933128918537822599476294544895031
+6035100939350635436051361083289099777664034736094529995818610825799950536521416106176327389907566363175789821848187634785837579
+9000534727303607788183270598866205796784604375642000912263136681354291802540390456321071569535579301082240092546052754082125140
+1036718094258942656960699558474884940333329012199962569808690163604756147670835128428656230386743308384472157735698077816035891
+6071364091704432824311172611510490775020204802190669441798310247002139209451209194509056421614671635249279135552841468497623698
+4388935023201010068076632458613446034376062184128689428896319432854524321580911853120662708261911385263651607882193115809188251
+7169742597495615052582018265793684790742777650121858370707225197495242787747124696863007018741360971574027831332907655096436810
+0422401456149077117264566129183248282220685815602963735110673297177754943137791219212563311879171990788150209340116758159767140
+2965862835354985730344339045722772376955873793360410786309094363480176270871774839639924049136780870709007238189898961666868275
+2861817902533679195525000340605947416733205573982037034681250485524002724047643727596821058644083422061496633576063860945664624
+2693808963859011255454082437160794171986401169181404558686995397058453911479501396355062702756373669284391335723793677898504528
+7653550559325583799147678302921854984957213549656349312970370601725315750255349048113259251600824306253788257181726835044331139
+2669198588461532129599972595504488308041821964826043635029559596161652526633086414778498340817442875389328897830361220046753460
+2464008866849845585427596306460289186014718930150794200485697147420894155928351507966633760981788686260275637265508592186109230
+8485080800308772606343366155948976547130610312843499421865489766584635822710314441085925235277117540126323440360094147819765072
+3284154124684872982729898726330863362356401302174583854830959819131037571458234265917476543549149369136036055331113709805046443
+6448518117737425864310082406263081225358862769781154236900286043306718901307704827192440877547054996291784365092391305036785917
+6937932081779624691771675203207782587255392167526245881985222450132700822827458180664476166098376639952639111122762216172733126
+4351428226863320079499951081487882664115198758192473811033557945313783704183329712942802900894464150489698398293843181571708391
+4008673285830233165375165239225902635382169451174378889470574573298752951780171507430341658864697744996790183195739971709305547
+3512291497844318467447674406573948587271898370849211096489030445902905335005315909627516994616160913716819045790842998532630215
+5522629798725110629827671497041697233370597035945650285606531591280806838835367751631589755667302233305861288279338186531242009
+4038072792258238775154639697267095650759428219766235775721809805667537846787229698544718121429627243715285966487077144477541907
+5934583620628679989854657650575271470278836721346368661646073065566282621355114101575479793022577251192819889432201758294108462
+4480564984351469882094948004921988867959440174254223793056014056869119031094103106976186436427858310194322489736576393894678612
+6908132113303990201784965196474475898344897609537622286517498106001289334026874927830753197509682053509801560482547631691338408
+9319954675495203754314132567507992211027517777636008035159464490278748417535817989110579370702464528694578198640300697978306801
+4761479515872183180982458008106034482409223233605055754850233921649363735633967021409784641062684672780275455212963103609820201
+2564622328254102204752883685136476152747302286902963024211546476863845751873654900973840371931652957066788857238841473470464835
+0397866053032166080589875219701391296400993039583315649582052801128849941725263617220137826074241870851980225112051857130648469
+8173011294494728142605327204039773210726054522101869637370867240485919811250566145341338527471719086407653593120324797075262800
+9276563059829040598662749592867289249306923572562392127787551507493862417784430100714677869547866344355462003505196714057035937
+3281114518664069193538073304543737277406653201799960331850340753228936196208065150992985287938425817855366760648223669372651097
+2101840795886669078503855800666686104431608113029414404488344962534581805317909553125776693807861855300451192405993773968098583
+6961316934095858314386858284332606626453618369372169846037717301254036577518610498824984225850477019844523165578520651885370736
+5674574044356298030636615794164061879134353864364329335297710010416084563498871752753647964277918366926080825456181880254954413
+1539836063070409136278143569348758593204080100329208721008698517483741296128676983168524689365145284941105915339931290444395066
+5870435438526474510831874542069716476806976094126759545431524918894521691790318139213265279009865120135936482961615836310836321
+2764563926650270576320235999861005882574146665848294584476765322933617549606955812826398821817999980232276039438569048353472002
+4681622264311366983045853037646736891614380849223091345272419576321258005567715693518336948951455962926248349277346106557405718
+8956877856487148384136234859130353374642270367915456930125213227196134161996004529594088595345226945903651779962975528996861250
+8929969605933523152819203271238663371252277051363612117118809528465712440154903065164514629518743371367297353604095710696093004
+7157581534746462952501632250334837099070591121491848742704449306300549604064489388204805910975177833999231196480535164260229721
+0485019965651431731437912577838502867419408108382589212055345268265256532718527981331506279373063176342764821347791812231845829
+7209745175723014456091749043194092299024100594164185069424964912279120968460389124726898963864775282217153874785467678332297469
+6065725443439620053836394925815928161931638271242410865193688681337289422879252019985383178533022928491349413174307090957339832
+4700128875271375466912640968373319232662860319940601106545249660353269122104137983304514576260940899048020820371598690778056227
+7730285573414592054013879878236163258148114953801223831916249666510471398921760574945529246282567489263612670937049902168944246
+9130285817898813367964618316152272977147568779205131506356566544347370722993791917334237866531951886887339933938523558239665651
+6324176517408834364349803908520408107012550850560156082064698531696664057881361151779666150135225685603149038329558618588277296
+8952307375129199935262885586527056730554419885668513403462367686079193825971303716999017662160537275706617381132201851911575059
+9097939471326158030329763386527360778246814576714519406324120582675890884898234797792200042538307916074737348191079713801271431
+3543558395840050080153435933135880595590305720081325097084551423268599148459068228435603649060705649929053840511309887473304515
+9764838954490408335606543556024437767253488401288444187782685927977837265995938637882104106333802927203512151240662538609957779
+2886694819124240943375973107339251767858923004989669776842476259662336587537006376705925903350515688363082070599436191295014286
+4373652465925317661858189411340138062597385913063993168012584788091469995881494867908911062927314918797351706279530078724029778
+2064997451678388426343449295809472909654204980492286328038224332702407992526584281413262450071832225709127884717383554674100721
+7539736814358108443787011442956856478411159063433502735600777534624427911961386455371172130290891500709946519469882478498227746
+6726050228227536316385485897543745820479149980410361188284581130022635250330849613983713225572081803265842903422696226592604564
+7194667876267325769087238008916325523655281922437602110657822708321617107090571364990182422106391457560890252879023326941272951
+8084067244599983014933199534424787256031530896533024441147175887371345390886210891424383817784357384520863399170708018540336261
+6756491974545573085147283999623619067108143004190487704098038956692693217789059190015343978239812814528286370354978428552071154
+7449780712548692282752907313327411787266027754878897309843460775599392567392973717717866266635813723308899529146352109375925165
+4589899290541494280337702591008141258629373350544520604291218705671399173981123075630121451176103241759370092474254377359262199
+6674505740657078583031897307527013973936077370107324719073133704686647880878285508608449940595668407790459295575945823755660650
+4398342537751131171214988271811959189579782716426212830903406974442463464257365397952526980356187741927953055943122410685033921
+0094907389935032343867848721405008172219352354700721989014087040463745373039712419507660947640188922848825854691917677041514246
+1508958586684510982818262867790308592204381251380001158886369026776930843982561684403451614590888186936500388011892045824866501
+5793657116945434882250299286723935630635472763043771513002492162136250578168782159984593375232995341440779322489270838200480406
+1528263927376996749090311110890532617677357745138138771708962614857985706783193215918275341078100860497124422089882672715412665
+8047862045380193284671628316345513578527766132655289631199372572297400350940186548315099505461109159626804827405877434015762079
+4497649985437114106619275583585240709212568170308750996103273375973255643809512987167799126855604592582070720993954457629607433
+4115202807426887388976298359856110123402007311986746450130132490988863002251413157990023529650615874660044346489668889392287152
+6927862701563682169262409452072639909156413247108366389659864970583248090206725794860315733927719571533833830245401473668394282
+6642155549542044431836970672852504846515539364245490047433571110732970388069323446548403285359639096781185191635964711812010789
+3758505500262572544806847683378518452890545811878275350915244958015902281380798955282380990829046266914505428380626717794710699
+8543173740869008063671194651581188030729498726094049008714991031352383511909957936902571701241692397622133551499445586152966454
+8558201709766887626106558682087493174247508346751479027758498057382070135663052096489680200478789301589881335174285636803583368
+4021046412548985259286576563116974009718144433360698911802741759233868394233863822972297994024437477811572624976113883122932672
+5381918891212001167216621281602456221735226414991801854696667000136111863626404844152191631832767778925457352443210000412625595
+5545489652781686362831418324972755141214447870296324256972282335912548489681306938005662008761939913552064594595349128397481698
+1089524707879456280414931183450523776892076608328015438392554074880142678157014194242067164456688702421957600153913700978618426
+8305117650117364060258714900356625435051024551440455926273115470939757929013176898347131589373525848240533670222323888613399302
+8471548092796793462446437655496090111004563242834114582368336961549825665258690557364306703617109594457055331363141186121145408
+2838670852038846380823335210551520468349670239701607224866707358833084563155287946007354912983177147283657585469121005219622389
+5789402261399916318681167359698620197070246205566424633235135391148334480479925501535906551354569207810065959398048065712057919
+7261986944279592176600370192037825062903228830667505762121478097517284917101606104242575975523312739096999493662697366954853560
+9155879998783130488358931786153797296783212124287955652349632245457365996542148509944356865191456587886152913113892875578626974
+9514039241881963923397516312505696923391431643577404694192615351139994947842245479233801981061807552927418310904314043203688694
+4614887134561403862531573523675942563015366589167507205886559178959551755768826801165790017789960028672209846259757000436195062
+6712756378314975481834508159845487505561014170818191973740730433116802799842074666829329785272494733308089058087919052323067808
+4343294134478763284253795500389053885558601278822120237277266312668433120502431917455874080753529426382802888951317455320771924
+2376278290758786366787499337556544479743289945243171688237218372051181305516529407353834157305915645651032848895215696121925178
+3277461207520288197080048258823569914990769314412444872094153856107817656040287107340131396038173497845042121242427193089822818
+0292406985223320173089591545488895576256166382750650552107291481212988120961054843360076945546651513119822979777064017606102333
+4155585975612603215642148373485509667928447809166188682093526614287990594479841858693261264552895318696996233565563963262273017
+3435051958110889869116245172555488932493678104217964596210912258968214519860568648927109250277169274770553939366194092044056400
+5580589234840522431968399852060022338678890148720329696753155804394492049184529967776995091977565256891476404577309506725891693
+7335500310521157522656023934693183042792687707804385279531540473816692277059506917018062802407212114266734977379325447178574076
+1771613660964024539818471437377426571013833744798577093945387086328616540439686380471290881092187502982926867793090143460960995
+2854310614938011180157233734163443946405910506035197343508210254223120818772340019254546366421372519708012585990732220553479817
+1257049653581939929259306981138171825335308854774522129783756061113569283775667916315356572397505175426434698580681752134340583
+0335808023777690523056395860773496290527877864032944037336174082899748170635967157534100283308552217210895819668943595660390141
+0793041940236886441234025927232106929006722186357450970274155143635586525537995503752589941375247670685666954666533793877981889
+5778831921482018016340449172209749049865029154730502990831586948434948616688177219302113345681124510479338999307531273610240254
+0006855309162866716967524960032543880915882390415328777432560766307982993890466192334347172872288555702927609941028091228916549
+7852480060739012387300892561223523799609034777867042713542472004721462831725545348869852796577495340595446292276187383478785958
+7959977096587753530877434044450370650017598273016702141156049535064683872702373865885204993323178473693440316927580843350832264
+5711255434828429627433858416873855046302807982520306738509536092504233877047237492422270856933123651986965389822895956478482440
+6861826464075028721520622101929991628946998804166738863536077306024363695385475918930843524639833318710346078946645157384213109
+3481268732060383732986016495680958177849607099558634081654518008026716403239770966732475944721762791451888118885285069414233963
+8027947110287197529845522807009685886470194904262452476975443162530080660974564750582146126181908103247560999247950332233807322
+7124796294345362297022824568300955114164662928041497399401450052218863148267186902693402640989732333727359655944286809966607247
+6673207022195790654496166749745020173181219341922393697843282922354805033819231485054350962234180921218558256719281039871046137
+9465616068877625982160091084356867655695114307535279252535857794074660077470905649500203254845487633889884403918357791957962609
+5439735864176545493786682348080515776951063552894497267405045766639566000474520462761676673185451169867195127044329565448901474
+4077128683528317505947720920671307017612997849640361880751590889728513950754717072470243203246494346250198972938371059265537757
+1744350487793132663117639969909905883135140378094636348689423577493817809958662291757247314354678873465246383300244542531431911
+4940086036767442787655065360411221974038277063722727918083568388107313711402640446340277014461054034344740215045925518041320283
+6681118829208967331321877862087707476476072276521025702668676229506021840555589912885589031283416146794110309804988142636941186
+2405582757418961820523544833021078187732693088350227346014916968640935524755515218365262141583526578487828351593275991676198367
+2826944841325179084380122395615301242526065149184196022148551459509194360014728846066978997793718470140240650758184827065285092
+2993193263125920746329597500608467852384071869621346018318097029329594882972558366328973665134862355812606060309541457130668022
+4276324020092753413044519728088179483413580580809338027992824022071273342649903541028827269643668077697566268171224024282173079
+3298668219738409681902878367215423318085688425654045440812819269643490157963034537370434474347979142141704582114328144364074548
+3331207723416487218945222041751113899922244456772815194220564328760009807415143846017951460454941724943113249362066483407691380
+6952116171208702291147492954583173797003314720166450613568401114973391179929136073418264108322111138297086137222772204563421106
+7600975435069311874768177860666996344740802287521757586619300995824931951698677022696322801985871429773970218124919477206966901
+3780912628061324155929062282119787356103921261553217430966183645130255649596951891774470507549609157651291460007364039518971745
+3378164561008341242097804088752883493567850412617992500593780122329644848355808639540910546811625908951376798420135130564695711
+1010690664052506424047390590878204998037797666671722315517689809912733797153349697357764209138638827429140983606619452818262145
+9300376547277559089699722018353829113301128665766029981150643108015654465357713345760938255089553063389045170395343438086345129
+5388574617722177598048137212627225252667251794017646238607267836072085293351506292982031628145496634572585511875570432312724337
+2949102931084425964911707872142235444671368657598878661624977383342922503912907622387561510392479663939836372865380891249214191
+4125450850629924708967370485579795410196136664949644795471576226816969360966521409006096786481214505471016659590219454123795063
+1052876846080196429866636468392224678653280363636952881423630013978399548705549755495939234226751546533383899311389616571394812
+4742555980388054447437326569075723750771475897619661025765632486508214470920970384046022812610698865095434736181621465694089157
+8053089116717921661140443537567547341019450706571788438437303262785839761518407332728972316994708287799676864196511854612689905
+9729609228443111962917503361177873795233721041675657438816948255161968110343038443890530223545306466481706693430767571885086143
+5688308264781028505036247702821583514666470671292172916350280224873269657299593653174145005772915708578064978186214186153683267
+2204744465132776025498386899741825318473763441099667987231878067919021578886769657107832299974638025812458213339029056421384587
+2941505567992035598339903647769230684834003209355669548196807243023989038563917277881744820709582631259852618961087166384306292
+8258024223124059927265905619693379087206675705618331236606891852566067360854244728445479329673501981619440816785961582356678690
+6012067901366243313604096658402361049393912691496270752442176761357212025454418262374116671287518874273805796136109140975751742
+1773101052368269774971707329316287503544657412042811119480548137588711677240886794469483314479010931714923252443537409707971115
+6673163431438354320152064250744844641052080216051967752388682876816416999627859168211126178210239748498710723469312339914116142
+5806996877521195102255361656866436538966669931939141317697197556942791721788110932577145668299881351690980272915197702021298156
+3837290410389303517128116353347856259353484969554892124616182205192313287433755106122400179494690010200326668121477882253979202
+4517266820218197081941589722796747209204288657893693887244618207431797169277035145695561271253339157663193312460041285285239201
+9619778362364427885644889878069243475033064627573715740274290928496163757241181156603865800841856421952950186816149922823346976
+2573799739461267334017539893388809186322465134575561495883735717608135099991766507451755547789018617434096932254961072365198882
+5105319049917763260343536285268328841500875349287045804710455434303605043562842410645690374572514107603618866501621709959657187
+7151556358315357415841531703618215410583915203575998268810030381640117079961254114904804786046065507943854733690644791284850608
+8204760879007736798651157366669090166543821998311590636584404376075249452086719646757979910467231964531015916233682304625227803
+7147573127581292166990486442215222962358403851938571275150035153036061725108691622876773795056511233146161151053768550862751540
+6784559304983902886590174698622574195988266824149602039534916660889368814614010342767085921580402597291566274193343471685906410
+7880113249001482900851888199979393787162065292926067710104923584703156779327643300580458887132435255065678627456912854660490039
+1350749751135031413626228320025567623412283741939627729115634082906593503710519533248918652855496972010878915554543211009367225
+0004322455171197190670578109680045148889288778920452116958832375230435697820421502377733900228528866659062527967209953101213734
+2911494504322931801753348544419729543749078880072226980969166346711819931480214331433779640233877327672317049984114641749562870
+2396528513460618041259531318301991286281693049268735199694175803321673323893916691134629842475605991446026813330356086230228330
+8981164060702124227875449453939249569083280933393885800497807219622718057632147355043854391102180378987437281964171835261740700
+4207084959173122310540889440071390175078165835125695056930143838697501277302913507401666310496334451392319525169760616015349520
+1210081234448921940981378280200458404260945592669718748037205896059223823726981351910671794263375996276697272684781727338912271
+0029168415827572351727213122061796310780992187543596747141643738703113178475108090159020344233281790182332311601803329178285993
+3777296404075934053174216751857062118469565443797038517380817156541529651488369770373411767683949249420334108704951789531604654
+0677478972172417855596910438873967997191564526032435944553932413671467038312980120163881839182106666575810117448701361229089668
+2906070251543291085920125260549397785656115356661440571177943054793731483489419102892567240649669779614310761600563474068066656
+8852394653036692892038076417261650066148179764783605637155006560905389777668215992491194523484007340075319390767759607804494192
+5467138831557823428775541689197797741887498255851810682591799669249141593216801183262480761866825456541084229589715596536290776
+7751352765591319462216158866914539056239902442050723154683435064019845231969816008347645334022334350198037412040594819924724593
+3021915992015948439763471750840891829476672656242373621059864369709314486194930162083489346397306741461969474457136306652660884
+3810149798323432950565012468358334053474435740399651150333513841619654716521117976746459459286758520929133377210685994781661011
+4783431510440557379639204082385220913253340902177656244399207972984745234341006126872839573292250089207868222847639289722379753
+7370438575710728204326451494061012215276912157251877502908542289047363288154325283991522374002173371912625950441590135539908011
+3066350412780717315157416276543477507139338679594873856557881443518665559120844101586947952288770461228629756299270909156776058
+0225437513080408599402290104732039265518603222598728765215485627157659513804399230415740373980117223389491501554877516067224969
+6906447098674865317783282853291741419024882827886344308680586123738306172623618313185104401579759220967002703474556768483264969
+7905688354362418737693115373990150326675244455866285863285017259126406290824772728738190085605025791061658351412473817132182003
+0647939692176384124068167344966453433916156302209336971942526032217331539621915101096729732974008611758025821638418841239335586
+8207612011209373495228760846993905535758093646702045474203894639020884032055233069612162464709714659219943117947340234145019206
+6685510574753704984128082407027684573335104766797904438216667655851315902097650094638260466258758906563426639941626773728838182
+2859725751851113943873234212381842264933438665075493160334098268584252964692288511136721035397358821669241681360772178239556283
+5410817225831141636647896001039576920297438613631278187702231335198482845481821124632157811564428311298381077638390915142518664
+5603082383902365441423743060726658870177085955695406252400018823076710944733837738608757044351867174051742821082475300834328708
+8478410686281696423470828758415498795393164508886616098722313596122431017415306773664281061410625509783895380848928242909573156
+1195618788186485122683528679683670597289650244657656876407897279500115335276331331011520690820997358881740005917663903217514124
+1469313024861648921401247135353735958071127626605430535836717325791385228578496115248025350543355198105506645012545576867598396
+4272483837056013890177205566878534986867897273483516131338967706119399325076036529394304714161849476343886942682280685872295940
+6971223873405564611431588388181753597862284579604627783908270991876509853907693857394999066866716324481756490631331601939564088
+8692753456851589867469578350330459046916706027508903379244973723114291207510039578602992677933126396343784500936297228340222600
+3596764762533798756045077959160866048043299983905049607435425529900440769757414376919342785743646389458775443875643589233861301
+9939277922617044929198368291152778217422406940588205287822196961674791811253436361915620783243520085430696637802610907731339802
+9987990017965498772438500667174890865212624587022291536612477503056361052627799082687991851074848222861818981269823302761583997
+8147838382210431535807715103935094271794068054691587562868334683152631170314268604516246803968415953907592500669227061338962852
+5229815249263579089803694020966160885001383014770540554119854860763174611534378849807683267399405523325826175066050422465261245
+3718808810539902175097435162693814660278935973946526145133557384972950132995651178561319774914749271123710684959722970432994100
+9959643168956842935132972702456973644474462349184166563719137832114600377784944150813295076399096859538689536653676932352320454
+3562313742471254053603374767998733448940422800590796399248016870732131873285978468485675936836421845482343165519443520207502472
+6212070810123317420939860915076451492474105989853395883410582273920108061505858814970010182505273303507369510379631126623445635
+0255217936242316574157324758578917396184805700986741727460755136645033816635143639164644674079087020280816581372010788765004026
+8089847944137656769780273194285160566134507215012061013579883469551314461311271302478380193931275275686279445049118291696625976
+5717365181365376852569097535965171977412985242766246364289767242179344339616335652390309582781287529277190209039953388689399517
+7041440160561255381091312862643936475613988744385378977312543669992877553324112750381702041222192086102659343479767405018249915
+2110051683946677346707980171411807954606467103478530131043035978033107947826868347943468663705645386376022529329242653151632937
+3379574154524802337331393517730441276946707038997138141465007355281465799683250899916025487713716291942082244114027843952458642
+5030312724644064165890328712593254449923448331621966613833157539215136234997090424298061395610381815885285290455631522924868317
+4994969373293084869354149476773798201740005462072247291096910619119410509333790774262072570461057954016819195195682237016634823
+4014617100181465701775054953697719420102573860376968588430229723536957418028396409863878695628364581200214130204435051219695552
+9995923662150908682939564279380158287700441111607726222291472481672861788611478655050339588555615320984584521234687823576281254
+7451463346941792082220143976579354392136627715379752529027471716966012381538802459409604897867012386933986500209811720725405141
+5447700282385988297313347229401494009078606483625633850809103068410968238448493407439403040224936061985927544263475630989480459
+1276956495071860259959641422731621493130581830343261790000300846232499293476144299954615667025912420799180581171607386310558493
+5072567626180671481702538305209899197776259094898315797269647260887831166441294066368414302707370453117631015362578331461379694
+1152681127657219064376008724117880126055071670561685874051473152694654802783634954044854697360607744867225915714681210070391625
+4963921877303857727536312369203728666152509364270556408792999159107647346567121427484742607873371889230959069964077737186080579
+2539117036539210376394880318723799879677288248068497337514544989379323165067241670457629058952981263712005132132192204500173772
+6813760519782616773952896216661044250831393786872842763541388164566337619519250295645333112400558661044316307967715017816016933
+2537593940009216399181185307950727066601997003943463162691283637037387944868769661465346762713541328987499170590124382561225808
+2775885197315288545943935069058879566010060299863101752754477420864624440405321494564586899592105748495227288314078895511070581
+5073590254176183749859074321316849201765757369989203202482670238574028719679448337609628523768999643298161243528454637871645997
+4654524903507892912886995134469509913539767744116890388991007614902224668150391846827264198768560243067636303891131378158227338
+0324734826151939630626306117202466456571054839140771329647402994885021118469683547773949974151585727386291916309232652285623776
+1825578079957905035730446040937650014976367810409736691475746813209385827351129150863065044732028040265416217520597270250595073
+3855654215693196726130528392601924163490164258356468808028166928343554047073423362885338439044483545871577569335583661986547054
+7793570955613127244841652451443245937038624291178210631123294830620894480548406463322651814043971289378075631025886964612359732
+2535751039273171851827163526482017707846468207349048105786558968816006070754676314714316763865097547820424829616783998998577881
+2844480806501005182020568712353744447818200854387376634450572497810731969576672980314852204195217762355809650187750497828976590
+0779679209849300532787708183193857610170295918273464149221680774855800423860839661690361920242424552243626034568783063475060030
+0715723560396890811677256708000602036818903166537471742271498254161510038321801193648871563911124555662395779532361864351019488
+0796637275901473841659277764647010680246421160415288649143217531307967149087210418850695712273237810379507829287822942082290828
+2503374558287484037225872566037347531382781922322502069198289211129714070730191986360007963273941619249637438751324038507743444
+1257552500220289953409007738059857241268432142060119245938800646680659562080913958426385782354999183544917531229451796428251407
+0627725746927523912542272514587614535547975158991752064909670083277315643027595358743280831654266470167938798514468394097718636
+8318980485800264189777412075113224818829974167411737699158537404003402647667510002613635249834073904159437111364326870286724933
+8736390761693005617348059895960699070609999931133577397987040270060440645814471436005094800905267014783073740415604380803498206
+5542024002024944354928529036523594800851472969896531771028010643441490945234844042008320398276632902810470392426566175025658836
+7031032484519885828134561441713514585691824451116624144085217816423547864679125010423917860268671111391465300826171047260397179
+8220783551779338773320989765886440391559510492663544076020535514257589749352990988564034320388602959557187208585104844145026439
+8020438087951116022977373383495534674635129594766601601387483705748972280627013851396530590121458524210171753315286548207527820
+8153810125605918943918826453140421737748512940456044065444292520385926730447939082216173702077609971171912049413332448203544586
+0886669881112435179401237673978622874656264303143999122578352317897806033193993865036799045024203333380525337357889563568831448
+3748676570310585965679075167577833926365276411040601559021494474638574451420952356408036362315997810486031449429712897242856220
+0680179178809075888645900355703866665848623566100723748395628721560414660071214664781095082893581316152736759533950009932003975
+0830073511229116156443164078334884149650348116571315260656550335371524295132896582152314795929439939447827419494358066689706173
+3038785789686019127115381229380791436051546935860047229508729818282744657378118473627065099573727853891404083449592265655152693
+7387679714798835215773140865910355708661822160467627107526217765214393654304740207983760504979185513943991488603347106187504836
+4959345618457216694880885929572868404119594959297665383045694122211724921300914575522725438253647266552305439505601459584619177
+0467037747326795908961510775114924268777468775918327644966642534544042676564308146590029193764372898938024544197186375500357840
+8285890907673262212647988009259010379723054727978121814340184295658072413264615156697842474728575585169324914900743103535246719
+8911662589073033021628854642652750279152366994152376376433694906661951714454207190114956328995857009825646477784015810868978338
+6105850627169563438884040914539421660727931317710596144077279839188308966168911142486835009941100149861369756674171355191560490
+2993431983320455272922883788672722733898158280538086533775288120030297726075605253307507669239723828996651212708874872223213527
+2383871203918607138972250186349539349163142546547549565946027359258489597478748862408648058675393278207850385093331126182621573
+9149363763947487276724850656041160743708661373179229186384365572255499194358074217364047819850970764281787263423869876082053909
+5827019270739581666492975342346328261479975112685223225619643483040396563898673337995672909483700478627244101352870984979237732
+6998285824391825859392150613924432428270654497491969804735086552708299672203935039153979762171440238901122660133544046138761976
+9253330844439113156612382643124565174653829532487393981769888635312756386927331059248556801164857640315799609889660186200071275
+5612390497528583434894505132668347409216226770741805847223173711771542665456899372500390460954330204857624315915587829701045748
+3597132578062559495102590042788395347495253649400865738509995118091093608521019322954235222572297567318636643867386469580449507
+8425515407736939284693677162137557410259923224830338231554842919234034510500493129925331580967001474100531060588153614511993338
+9601991297057389436503665001505251866564553593237174176487901010113004032749058341666775216970685449376017846133214652240838962
+1863773381844384208184694104858797647539515137932214592371546918752008772143433088976967184397882651789039128762093118018510138
+8436667156247339295567342218063358078249911156583296510351786615409192064411950727914656163850098232887122260394676405120111886
+7683313388786537579802951656666063632278774842670516448032010207156251926218292168775800210222391153956472045994503212219850049
+8209641417161775663979384085179876713787424866821458112247475298894421880117371699371735285979992519666751909878379569083863705
+5145614759445599831570000861590726100099887859826097034388914355367729544959518374514940678332048394297378845981970826760413852
+8761767120217732947982706113384060618324856798940745761981931692821487049372786616858603289668185012412091827806837321112104047
+9255297129664160944098264261547065105677964568103165093339743646349513755899758152316922927563473869566225326724560456097296052
+8120768832977744822631836021474402079390526097477803448973026451821196612519143995594879311933463926655409414749552006489267940
+7017154772060236322937445448043347707331947096778317016923510498198624836901896034874919545286197554142622789268469355512048260
+4180409321511968885143370514200618650235742405287713769661977834572569077057120974054874981770237845015640851329981775003008191
+2674007147813616401003929214576628097932821870524475792725335810151140502429235053500438517449175945097953478389066531072308154
+2478433215760250770512406042154394331540911914042172939884164584979797404189940441889258451913067147217070836370940898306980314
+1416691061574950251933857581530784660502363969157027453652188159283670553356947339926944472421121743170291855577403109297001923
+9846364489252978228078702013876774947354134510165101268064021721322665802683013959144338916544348159574015107727356473797086745
+5487580365242793847184389294498037980764980441864399341257536426029899353090372478661527651346349015000812904186890490170512422
+0317001187750772629199900746610544979042670580491329322209673449299816557793150957519344382208574308527216206006597313873698350
+3641287214039996737900834675182665853779449596351604582635503134884649233644728626688852457677654231608768591360986911023898427
+6414868015450446904060895609231719309486232701910101120865147273052264604064433289410480856555673255517305129013544577242362891
+0524147637426415811762515415524550268148125432394280267631328443360400295790051752698236429135771292548014257090019134991791562
+9227410989021340348714125220582535723860559138846179511512191891037914244234245126229571603923532773311387103298341477228375501
+4041581080402587294355936437638145699274625343476210354812865278292813236740766242635378473283614144250925302804707242340663339
+0724867859827673965725683173043844289022888248735884487800477685080844896245015920731492673699852061747889861151283779392092379
+5909276888786182094219448158615991460321912732697015860009933234510620643391119454097956755043612428806923128306819132701862789
+5863973408297121204616907602368353757254965361693796331036727921299882051062544545347637276552415740930878434572627384251645258
+2609867181490019825132280383807303218611438271972259358234476006167125808789720811193408861105326321587061359193074883011503250
+2053550365140441314774770422273440770268402358845803831349391590570354084402287239858709867448417600167758148787965827714400727
+7156914133575985423380170082307013620095209686338890246264669241382877333719091759478776099336392938215841439510174135934515390
+4831194527648288858829733221197151800308714018772578642206404911045931696147282373784233544435117870290316107286565703640910861
+3300965303400428799995252612196866095687126018105212822125411581947708785019993474053195560005697252054488325120896486904066095
+5685043938431323336868482886553258817526871549549389321696880672458619872963868160503420041705844727261813948644337640127844475
+8437858633093280150489850618743229089133908480393577494682517449743840953324665700848231841040716763791338769325607594504384201
+5092632498177396936492730922026153200701191354311511401621705191001018224605697557158822145660532720002740219521243300566753090
+0884695364629948365817606370132571392316227842180869160712531089788912972870842630687441550199592940590099216041036498458331435
+7030125885795773170445439886698551870214797580800884149092936799091801845209138388276070168782087225547258102113578759536143915
+8807215865608701057987377248776702944861046260230342503936276411275965656745488818885694005475308409675094846381271540973613956
+6869008153507650455021791206721217199858946589909935757514740552973399919912521587008600090842850454930346920106313925959869436
+8747302342382237757458390343882591560184411401946674013753631245032512422678856746902092711874356365404625893572768808561925896
+1816616401614372016489584185015076832989812362352963164309054653174766477426767816672229374164734973950570074316503361323429424
+1677262729710288413972124464110274430459973064690910792449284824422312855723898793069294265613363135307936039462077553033385323
+0904814204574628728334178723557725337676246503641550973591704771295724843533583760990530372617065538876854581885105724368370399
+5318034405787225786821497050581659615205871549939335953839157390829611482749151979571742480565357809673956661177238715716708421
+5050974915162203984880371984109598616980412684284404767484126024659745317958728060034806278671739980663056141392010690752871879
+3910704359349884254016812391071406772666793577154924194799659346664635964157482006918898999240501149700799097400684650477119203
+0922138102426301243886965897610590765176893150415296968278489084200960754236095696787157337789651225430707548067049568646321905
+9034532106902339573322445743023271918597056331210862099117907113669633072759130199009133076195985791779283506809079562559701881
+8961339360352958868430789580169262538709387737102199957461921100064868143051486287683576990974108237901843716454745741895109283
+3895519300319620380905559168583475674843131617139726705719237185238119833221024548683898215318859806049104445070815116282206901
+3205107673082159654286800880087962054713784047147807335322961266542952563116519811400145837980005316237797804651103815235446781
+4645211086556795731679627686638624553276782440503123281227932461374131645478394881186841410205689089468850242938656791425398127
+8527652116361873059872046061450470630778597394637649835734537239971727675715042761592888819669786191505268650105293343814467234
+4729851960520632361339165114787166123924351946142914574237488059076517558856540707604936767815825051810582920267228276662907034
+4922524498676764577221603274496474839043188887553906964245432382389882944444308052516105844797654740378920402689234115734188908
+5209597697295900954976185802188459574638626316316754990028635919463918798002460967253179124238772322245122243876066379489508079
+4508289933039159505453489164861720999217265104842659882479905333119333431390108947303039851217725991104705191344280222412086293
+8069168568134508776661939124641765187854999589971548041638843098203486147656735371454412494419404765242018465434846607552127178
+2927086453284193065980223266739988186690361081906781869605569767794118257589865157784413584255650425147523732344110338440580815
+1748049647890769557692421227727549481557775151410048868814718985045151061237011017099100528551045245586497019590105694556854099
+5925541326979395577276086387515399363166724218914221343444459910602377753889752768375789640169881596578910501727353216027189265
+0670300499827706283025120061244353545380543254798985391943205942681540582832008582661334249048815794102101737939011541318568554
+1807401946172440506670841188965007674553832019157741404977051650612570825055419487071388288683499429125090172081236081328128795
+1574208400432062514192736694804153587958619698259830513687209529110862276181211516095950235354568516040903749851761677661305637
+4121149896620030430814848794433445919918770329319490730619096312332656236065824412598168467443676868836685315118978623516376785
+7498488621509709129976594981432727530944618723741457356588286547102533914121132990321805599546945869002131411100756554367181741
+2582026542886480869734858959495104201677107827620049653093381222272376273695750172303884972292405628020932588645381010082785621
+4289447606077369793749546092089501817143072386741950941157247080345113014329756464038358626070033871947884567651488044623905631
+2542825564877135509885226287724296817068865459213301536696178082552402072123707396192496897302967815948042943248544343979991813
+2226470997115317096784601264496380718265218871198752715837658374418501244345114451866417686910079224568758319235433015428196960
+8662720543840647608329817530425275416788291903848716280076563958924728751343578053506896388100895823567897044421928057610378475
+4719351914296817015503837199703117466548446025449281302558021903566930798786374684451211437854302542934198900108681526080958767
+3447640954611982803365820977016952430036387460526610055495899354375691830575753318086903113772624764685535267168082007345740305
+1797213012073375178436558221355605782112077809669165249433528557235690262339894762165301931035587761808175461223039297448962130
+6950060736132243209446984212914140861957832417030579738364918001660026811196800334571314378298274260059705895036596817108824926
+9243829747951735931284002210476722019445511064984030772651417194277223668272106134988724834976681779756839767862454568373306618
+4177035873387789691442645602142232402697759139202124087044601161733861189197322918438352811683833924407803890384828993570282474
+4594126055178872656922618774167034354795564094725497124745719061896909861368756961278327080697512762579612758334700763137442983
+5295668887669717485226390123467973887358507953479829153694623729169375830523050788966597377361980793027344718171019365784257200
+9888285370457729318303943315282858750583399490083047557333008218529891417381026015175475841289968239416942724745429537867737999
+3215943066766119309004524839024701086312759322446215895076113158100056596170634794503064752363481133827922180405978563689758589
+5959944414411467463305736849422386192090664596675188756343645002538240622043092367067855848705606619349233737685916244645398642
+3415921462522850660711019463447810831161516098186857649733922254277645246597288489872824421913456035668900907466154510857353878
+0820770271351282269897729773480908180216209552917101530859717823023591831191252679348064887785178954716044181664367902784712050
+4837078657362119194233933526772924288995857318513107274934487922952892071107573280347076419494020490239809987105400407903583211
+4566520950673320089105623215464822027247924240083971798563728505499902175676964769999078225165976694000667473401833118202304025
+6860738161875565205941822290237567447513259073024464364524976929966835518792473395436546988594137222229184152759954076791794830
+3322947265984158060992158624663708425488918876383348951122905125836522038089874259881383269124957101134232722838965307585611944
+2514815461210894795746476799700740431234580399243562016925036790171527515771508119826976806830254109945111480181093741053447775
+5733504011133442490826886677777865571712956442700084777358932735387221216646199198889278425501261656719619101527490023033629983
+6816820665025994462583833453804933866931009904653183983658207938144775757074429801900721418490709180940459786270732207357575723
+8952696642268346283355069787962809893365964014926493914452473794524489554221368619837559042723108457610361497745820672215991860
+4686726618791630599619015305428791046600757619220375372642195506961581791667069381025833026424470965152344317512976704970780861
+7817535100493702359961847958187008692676255354707895369219620793484182638707169828174557995935583658475438688352992259510602626
+7874029548817067666626239631331985390475404826024086339339243583071276348104332609325698630718922399423989995185805657290031135
+2250809137006081215712604683009748641626154723738138936917095298080941105465629041740614734952469019573555032467949707456686827
+9015780860040863502309304151201467772727168204445161990634325579174702838004535428730659838209979201561616665321137059277802195
+7650185512550554196643188069669262493680280748343975919639135449289335914799374871448334387269516977974949025899212288538454112
+8893662379603774306702720358700430713868475310661351513479439829552220384722225613968805831874918699875259504799262267715048953
+6970047041565543406988313458814942522252185061892588920654751003945616453031191382091583403673677641380943374412110595010134653
+9871101512999920825593895837672777862350486799080847951285270490204712290524251977042420133385216867854292673426124017430550114
+4761750275074356557669956909154179090706612051478635506091941757942400068895124161242203046266249256221284982009220935209300242
+8708015446206142670623126732884105024418284851295914904738375122444129503796268180002105711502782904456582492253779456800326918
+0613210293625239057781585677639979950255289284707390038337154693725678298193172844000279478330485593483147704265272812526895779
+2716164189514060813320272610067774089300292554132648786501937337701166054949053895064937132503546260829302791728809439780621266
+7313188607076954454240146509025347232689443993903699487707438769611328865209183398377855897661913914996316621615825549781446347
+1784361684093575880030474001414660619024654155783784777347697077774197795864389624206377564266630250281594010870492871026068899
+1515638387019036333906018359538519902111800466842577317066502746814101599618916383605825219038858550204877062732542814333739145
+9220084992150752811004335287492444508585899566926596972214201784424729857471199982968054884285888711269768545472118962801716609
+3225729665605184922610258057387753797602084282592399424014307116412082926636660405157448703031528431483170813038850013412917589
+0896837209572767267939653527113544043129466184693048843785638628896239995824306624383959725609177449846462355536652421863726297
+6350549459745687058464464835566280558244152696093628407065101518502946110700562358545869437041517797874386126356678480069546762
+7437438880206605630925397821472561939196877744334362718590301519068712375301433711985727209285202108430567240861306104506294438
+3997013218626793371442945794751768102167128014691257491799130532817890787884088430906840628465718832537193051422942089432586522
+5767261809159521411906210527732505137517003452232973525892796163942363843586179566469412536807588910846358095073973053136806664
+3610420406657475104037145580225980872688624964111041381549594329404718245302720059446156211318636072750134363504069278172819616
+6203445793416289171078116228949526537345367573758934511473904862922585007326728074024526181186924979509692268351022430367531902
+6396903617968213357545062076755915835538061764765669442173658896006627193712410945197598872950553456423579139305216599382954077
+0380250815827704962815549731957552434336266476872009617222288199268494650352751383734703683895685962764217150385921949138345511
+8687569627504118278687806727964146837523838460065586633962532325989849682060922414609471208083225295893531164710651416235932804
+7419608622045901350837303269139752477969857182975189849619797931283834755645259685017775129366698872709262322484867769237487261
+2446574648357299934768068561355356119075191099390351323266829442188920299959413380468532819783426950868690325166385302101461953
+4690378580819708064900475904899019106498140395743178471011674929320871266333196561704778715716963538368801024314408279647276339
+2089232113041890885410086998151297290297216269518414003124742833718798363559663862672468722436254498875698485622178498338429914
+6550115139019878137719854465346267455296956376622672210869101826618943385242099068657285404811000189142469975735597865828978322
+5550336328979484745931555695487878550858216320770924583332798110114879836414978841309407295358874518788123614542792919395667790
+0067101966073227418786203809533671075851186310058420930636457857938955159488144881158165188969895896949949174391923269110027161
+8258211496051765933329722240348370716824091139227581167499651455166693356343053246387421021603939871942981451611393932490380081
+1143232998448167618984488431281685110452032295577636699995232387576558530063365443650214541186195345336376561664260667081107636
+9153874053518331378425571758003432585952239206770799268110257888073536748287123822972824857968518689632999374391956653833541643
+5746454771428065810576182766708428737462219904665952012954717596322305804801076045993811560187169208752861306869132853087960769
+9312948167988600676884786283729313554222793557251794907465964089218336400060941052967060271657136677975942167674352571570304004
+6999898093303477247632176216594681728525645905467929567402604064471637964034911185817952376210008390273053006469300379255866531
+1000632388106711156678341302292429215991586500122697419661097904387224375829260375948304920442750157857268831027577641937349960
+0561600453741069995026478401094735925203677529242298315347820295756013844421038599646676315356655360880496025651231310731701615
+2967967299264819933654047107088552569694325550743639578846283279457367587777819171468331383302126179626852498959303153806267304
+0993137404276474214149260182488025202243237418254946278036864473980040065830274036040054866953015031416924556900973301250401325
+0611401987313671825312920644599670850377089684826838922442681491359233283306670402386279700142617583474055662080523345059224691
+5939710996631567268204735821745742750433473750474145824948890280584535509141301239485088599010310179272128880118496394992466934
+3357460688499765569727929892732936606129832020628130664357730146150594561279515636082352905831482949527411745350155774277195108
+7138561333287682465057643618887421608272303910896561253448290571853039520359195699641420904384787139962581486218527455895010235
+5098065276517497532201660511210544476729427289544804994012760004734407796257346283172974549503877915741488118551582294732680387
+9918245303994525211620190522775746453648980603544567886385199869862202445674868474533709002221515555801308081350907650459178667
+8721390287975913893819238889792260446828081274233551710328471981963516819510944667867602212793558775770710289206007250029862895
+1280952122455041043530594319244152931145497436315530258653194357643115496210565410757613267156777417895715618326341142914815577
+7155758483619829149138641241642134167637824757268284393191488835351550697663275036059641871170325362834558782380774852273848821
+9812670602301209189800121141901793479005817704022886493550881027819499284489381378125534965938777548562514868791510874667018247
+0362874203793328000664031717659796956361927785166994482222033051420000873310315385500469809294516134684467763731164514267312822
+5076794324739899424289073581881385172449093717540058394689713271226423655501988369216296397971568827556688651950460247532081671
+2211691279142831153117347297369818334578478434502829176759746633980926915557525626263924160377780019382684610945724739361356924
+9219339881449560885105533284707871200679261887421531149034514599874409542178946360778835736536874753087132328398630153344208176
+1738323078966650030040964282424869456011617229198020575179773319844636313591780039750411848469791355249483448877218482996481058
+7662725242856974627520011178425574682734942204257582618062074645522175607162830607624141450906516065750218377963070171888324843
+4118042284044277227029777215730052173836438075783336538165120621022353806541561734384066342123951846452650796265263415816226504
+9577454228253953925531431429190317095770965424733462598360193026659796995068726322946365945449373804244913417484873047389958047
+2530447003714965976379236094037411278014717964765934254550861704945379408174897820528178412885512242072953354276409893858269606
+8161920683332117194434729439905850512943519462231619259091383414069915670154194411541846032268055950920748136328515080957772524
+4455001394112823835403683958904433147118332238523201500644925421808301905477707785391327088921953707802405649821266420465223561
+6446522347006213132203935166470869874136295692811490433897687621265910913874552752126752166818595258011990560857727236113871905
+9408818174849694926607806886600067803753381428797382723099805698620415041534972953179055866017711870699147517868454045402246335
+4135626065428509052074741682443536368971147858952760160985560880547769122981012756994845114634562103177568847660082033374741355
+6629483302659977998713743227246471116209038004192175569114510152669193408163108052671223081581651955384894038833735367319970945
+2019914369819713476232512996482094786229436696697562766992595975532622307992117773104105916821954959122045124593739046172932273
+1444770368011659028126820519729159232409884803442212877208399135578736969682832974964729860145229172744181374244786183467104294
+5285602663449673777986234552062489192832103368544537902433053581936823853505740285888319749907423551259460167786803225430704894
+0644806832972865011089771228494426041526498427256197014809301589227000243312341210098122668991020924989347084902763173739593342
+8397927825150753855181618641584202156450292633924809550510911217351590362959737037094558684222129548773410325105794129798697578
+2130742130526719507540424131716191473755652175799405630787752600339151530661377691130274509280084673031861647779131553466473489
+8949445645797314751748458206320095870152672752275260151260265707878555413048057771903238190200758654160960860864191150393477626
+1150155207111417862229200794999414320488018094694431946879621916439109486610009948685634866137188097525670175207351289611083094
+3459879841467541763732336521769192414341573430800023957612803685733924880739274791648569413015334203212412056584388583105695911
+4207107909576145869607620085461426361544959409669769028641359260476393776996951928885197026584290166920423018039379739461412804
+2471437021597594937922441016847924078362096363319644062767483944790539470640965768192086646725793415577156194561524796709562342
+2281835051710898850388364318434644955789879751829726732802303436684019874264646806723409567549761608858039525219541663231620839
+2007932711287625313296243751903200023005400873291491556838807519342296983784742524733445763971687078693207166472588686547509634
+7628738900800911617227705711930133205924637233313615650647097515124961199263711780307927527262674727498690057241315682922136505
+0493387404859274797132212785618181333173806092520644500400240017059008198178246301124430115868753110589721037771703980382573162
+1169775643061410030855660308847307357939679557417322697395889694976054211267593984893969933792226845025198715121269754643254572
+1728088919686607770305974714811474045083911324960307426887087611368014116902540202262357011208475439646884185432232498389602471
+9413509858059972641349538923181108900150612516616095667778909942463828217847216087159443807284569471198894585206492715160193699
+6728843665008266563029199158801993529576549886997200057517865461162768723429256920925422142043184781462681238742660537092344889
+1931599731390297037090231505612731169969829636622229470099002019655957459951531223643763907113518395449915860761987492535032339
+5034107674301251502545019517381773020837552557746624579624919732008873147762835295630900229992866373514578020722517390727520774
+8983019600230774694685639778625463724553591351398381775880431832781553934906986888770789153951456721760712116772577734503027958
+0722579888130638672105073329597090462417149082738030373661949401575813793082783579270436569787902655097641040401368636813371427
+7854245354370422693429496181630052949425191073877308843275368739572310979470712820505147110988781661197587183674125970895995542
+9743873036934859621564820909920160132335721185173809848423866981847229831790016569684947679721801847602901060080188329396305906
+3397337816832712119749817143233767742905059889912076656163289731022283191890667300707504214144077245819520343407565716275839778
+1635431146179533618869624816029047896887367730042516939278216433734900869272992829571445669607086349418935403567352277456520703
+6762725385281999872315155129365300727718531348063401770341896591345777984146395511533572557918080490707700609701643325567678181
+4555558906784569913680220888302706502231120206554070127879841389783669163314482027219519085496782129580409038602612227824819543
+4625553964652973015688630098326028308371988997070002772661734916972323600534194087341555003249709049635157603584665553841867805
+5469615145572204179649517877754736243473051237336198742915870594247954290354530866927776592105619674425818013502199456960100742
+0688295929947456127268347042202884584629259939771429635850789571181349570944477662818026788804604769581716692572546910654441173
+1781053017263760670442837500622338443773255350157040419311002126378320391255428265011649731680948453211623587016944241093429272
+4424881884807343597741531983608658269276205760340198024603987236049280398955549067330598233254907076437393855435114528768763737
+6402747544261459973943024136936806092529416389402993987239813694282531255632557296852083229095761340348625572700195393957513287
+1528386320984169104784676953231416483588713316281109988780398093348714641247346320098277064757682809088330401558069087928359793
+4836620934876383780592087107373057072272745160875663949786761387509864704698529847777036861011698566433232612309834845364039380
+3575337583851040701388845815054721473930456788213430385395140774983959957647809720764167375524924858966015899435919948180069180
+3727628368963430480869218342563326331182798677393171005831460902561217359479597768311004931085102290184621530025879576836660947
+3475800984573188366693910563609274312878602294132115102801727644998770488363543862638723091471157432089891694987852322137790631
+5023683657353497036212732071088147337120821028934424904568945720202766911488162370473709710449329167955152043455364639983165681
+4313458074953427422966761496213154547288857367926863109897916806997328848306557928981283734566043834603735209469550380544603011
+4769534552591442528339142072463485535584209788041390319662187991947284630203143273451030277553655546597381665676996289780792291
+8029659403865541723176070298858179302484672898090770785814054293418165410123040143090326214914018331298053460618863938939353357
+2504331261837289138046426704519324433487258219679900506483638261532541113835978749947580235779347318410118894160450785891787503
+9154332931976583483472163920590162126815140207546760699499178902132160947370072538150136322051659957346811166868803166980109050
+0222142484013400331297859576897114613785020913334195683798252363342695111135735081039945217905782047137997143182303582893239120
+9813120425348259494442258981684713118897639132890990099359593568005985530954284388860261356040562648449500126432442951864251191
+9491055336614888264152467342246996843863880300943314768116172425467094897669780084992632583894436406804533915530813948074710378
+5125880262000217074108251922916601396846452955978383367381037097928649700928330600429463193168987527289334840125068384753709726
+3250963913544985283516074025079436289530032965000091704733601456641384410110473920750483277883697522865698072624602352586775278
+6909533273650494192857472271669762600062165210442469141500817398520087420757013742072500281461753556164642072928308813935348280
+4807129228896091173010215184046472764333315290810434138260279373142369497015166184160402673619706065463269358547161491925056454
+7992119117554165493880872181423830045252323577778753354174393490633929436643377607848377532573742197373252323683113537849603683
+8841806293434459100805456108210596607134914383853585818153512788887296784056237782465358856155449499271949927041469376892328564
+1632152697497520229603928059316997370226452543375632335002549957119486189260078571706186257203470953055703949967851861921520731
+5864396596718182058160283419308429964136934231008821382389697128204242562370820069167753381761875728312424003987892871207159646
+3666084774918882500462621483992172725824109862896378199142479129987559328773744933469602552905906375001745899273316469658254151
+3498338535962144862096688449703329334091149790999664223656029226119319000718124150843673811902580542556051470065598276315050434
+2588642538822153267060185463367170199110995449008021906678609426788891572594252587471982661988824671301251499893937578926745391
+9319707795744627065170409664872689583830132047201026242383522246999299133923376128562725383185342894837098008031828134646969110
+0671702811161136021518386108886822361915633677386996222331112492876474384896788653692739997207795179082317779078270838374606210
+0529680562308620614160670757652951824510508056181488035417621544956335930822186390269360882386498654576366806627786546389748223
+7121344007162987446407144751532917923911603613369296361423444081791345960568825786153422255467670330488573438324604236300940295
+7856126749900534423962976560155869500794418586760356971148877729423323229897743690930063998855496652306786264023420507384957613
+1115472217398806310578221635364703110916537667405172225846214402717552527160481181622222803507823937807179294058810167262993525
+7733396618045594337624445678237438829647882527257597412143681872681853625778555809127382419530057648275810262641644934924071181
+3613929384294435871056622853422519700112176582857461049491276578382237331260522744886532614099866550813707901946900039411643678
+2471863854966531804604197010815017888282961247506056635263741803813648407515388558830396273074055989597305977778886391310447068
+5772682018682680181055188634541777077934406094474845232952841473576584969574909042981622739932442934509311768673906919851347223
+1971820335809415226886329944736554280331033759806916931583970783266805147633904060778157532814909009520404718412464333929846412
+9304789467519446866413824868897777103238294214707967726874145548954743749977770022421296628566823077488711722686581183789601459
+4520829387352906480220193366391017100275344244933837568936172706668016811057327408759076674979685576296077953383462420493700931
+8246906431343919288012465266462141639350962646993227082304804964566869105156074039984736745415005176673660764795387467919402546
+0186162998111273052854513690953012281012706484313894676418003816742150384731546652072390520748548343581415404883693106949598503
+7407453409468893649012012693295080963235028162714227398127099455397823529445343521263605978197734068303737481555026299674237511
+1229395187707069269668822522188040767339600015117257223444650130799671208076697307072988709360546665590067811729152682754853792
+2543283984004058807502208094435749036903952553879602762556029245920852075326946498509084553554503835502118795067551626235164267
+2007797747581357604343336945727914338356814330722751353631792234077965818274628997502349441503414970786616526353391356822676384
+5194656346701670632084824377074289402109258239302810982753490912710811175011533673266509733689435108026608580234617657393376969
+9037146495591802460947583581948869619219502922722697707400434384802310554421740985009894719409552319891457897233615461251631720
+3990697080273078766162376909117528749470352764935216917028329174981312070290561402015804824976866738329336998564205666524939715
+7848352778978178394189920640395834604512765967920164240559275230242580756053219581598506048812354481467677378211973577424576951
+9532477816991813127692436491685156204938010748592475096875883131377908630365761647389532075843048673325944084338736570456096797
+6164242821944626959915759190590818947629953857895701779138738262444662644883838599728736964664029753263536337011632748825080378
+2817015241236739478928849304183816788634913242150862112550226668153792859950263630837585979285928908928017849179569989536100198
+3188299380080735588065637018955883708261980780287989654193640067585824757814983887808561472404025858752559638368589207857289458
+2148159553153805396206627740954877447246881212999958661604167091735503989349952300666940107138834649908131455364478740204253214
+5183812867943299697018327767670320460762394440257519747758147645570356514775758990004394658301628734229570022912960712413921130
+2264795742893091605616321707447640168594382931899898384410937459110317820561426704161424031904340033048159158399357351652777596
+2139572365125527551258839222311219599103367463992672950511023648604600231272790630354961828455031402437496547839035832950304233
+5563173043827945218120288721053385228256759107947287607765533263965688120561373605092351078219345874822210656978425318969319770
+8518350618323036588967937820117667974812517069373788130975907844737917546000454481446588184420492343516807727330574227463796535
+2208092079415381688598883619322045535433174373692220944523386140424053570720154062384759984606718110454232154813303857905183459
+0403764445312406400743177177292964855962834587085077838226697948324657642954983884229554291774482754430895940798928630071520949
+1218078030268093244894387180566099112644808636942463725970271185753041625812549630461585448271241111674252623627152709755765524
+4640249030477405125378434884747349008061139769305596841781606951188241867017869136729477063722445205619856063985162910427240398
+2909590245662898324814954125183873527735419113049232565629860534526664160220755933343864533662307471463902405211409478015729764
+1532024154051612895466466141175266647835257739963433595273778351297990606120134172421391748505385924656782899507982823237116066
+7625676430217706141880242765715903813773188383257526213002250997251341961521914541749167347954676286972265765550795698115431540
+3971204449523415473814450392924406717851351635913252062373246080376997499866289003353070967905385783507116089156113219681812229
+7080951492315882179871809720207741914174481310077398153033680591523295504167580131795931815413662606081970038126846874489797367
+2964040579217611595547760234190477290346436427835968877980338437548172752209833653855504469466390943293257324156532489625950388
+3972616808815375498057586682316341344883202169607183819718037286789995473261003288017415010063837288806976576286819527639032681
+1290138051725002391039102512231630818525813814320415691425261417707087230623051869853213472687397101016144678883680930245168423
+3850834662586016207855419987088023334696460550057253060411826174208076438814838201928582833181083830814307068201908029863175971
+7944749902703521228274612063687297856087416799604592533936372400167341391775276233906976252493497295192482610468181988345091916
+7011096175582468584236690812621406307216715768647084636075068364924266221366474623044001441060540006895424513815585241978347109
+9612362696533734373153334851655466254197093486211639205861389987966709302035551682330490724447416578042696870553662285651851441
+0111552534765233442760444257765948564305822466469203165903339169326584537556214779726091179725355707166736526121645211226756106
+5885039259881836616302187141071464709494663689251644989212209295897461744225634984400183422383926438027326803031066696585257111
+5396579069429715251643225942479087285188610492026082322649552644481241838275988175206718743351678720472794668564948833054357449
+8688233606386980591001497882755114729508367160997540301693192893291539036951478433163921320714186025327605130043325851253234451
+4872214673472278544834646890891722960548978190052377730643946484747055518801507106492936171927846554906068388153908514485343068
+7214840374326612339276352609419398397127314205763710059777054421447567554750695002090543962570373028396055745121721373269382936
+4524482436241914482911352925071095921316760701089039169544052169552093783128384931032814298463081577630793680822839743941613795
+4223734008339327317027315036935919017365387705335808468598641390301926191406305147914145568155445735877807426352454856646393111
+5101170944379204574558835956241764204898906557725918071785044288986731351021322301083120247570462572136590876553271594974477165
+1498954940338463049076496039744592188429182308195708965464178219513192666612550201124332096109168498851228361187923717360547190
+2838593784210615507907908324852279814008797652951109874718831612968151452611605913542110950712021617053098075818112497307624799
+9381906333865113269293243176861228537211612376105763917319466803899016867981408631123044887142147183129506705177986309824780722
+5409043531218283220619747469806558139995337403975277796517573718341286548125289716392847076083882092014379916668361163684338425
+1904893321014375227674131798347455361695847285890504332145250525132622615658888584205703776156043946440538442055020240373771823
+1351830991497076875181168528408533516757044944191964801761366476485666222599596030732870772285002472325833568217236712614883027
+7315021210616605619597435420913698876375528968662848736161937624720303296895982028335232063555260929924269983942028091369465040
+5072200871530059327653441988927547294080741487165355628851444397293608964873155978474929308924899776875776153220999350338874781
+7297806144047991652107617589673777407092234699017295323732250434070279346790076112443512292202647551871470787944370705490593514
+8338680194506251068070541345811382066184901866943035469419313397753521282182668152084983612781310002659403231835343007351253055
+6114581775690037701739519471149107309520083450078485755172388779153808947468636573364766942355736298359796132744647242525151199
+7574059840087355237287159427555431111919013708861023222908038566164641505519732443177083128309239177653941203870945389834998157
+0673474392377001399825892148070125779937209491690893896089896421739180565135864053866800087116893052683453216209088258021309774
+4693630023596081716394525302256706650097913048822663453433130852833930985337805085115332988734054335391426675730296735748012109
+1093024463171151726057935490277564245957695353097684106836395483499057575855912524860400186656839768087931489404973303617192884
+7635877951810419014091014411375539957398983529537012020519286943703105851379947162885419241335326379003488660213681674994537920
+7313912009934610962402221459721660669217906503605255214027757570091733853488694769091622366303142874602414314687218525998341547
+1566050559171006939210753283371737704974135991991141945660050193578931524036467433476181347487862613613591250793557188528520720
+8176429431061693107924500762483197651311460029641913001176379201100638867103309766025948024030323914130084770751860668764418979
+1729648696441840023063291425166270194908270401060650039064514332458826292034060316832564595611388754933869606578691497545240684
+5096948893204927421293649874213362565576773971352082850459718459918977951318599802521678656926223913450782713343578245294043312
+3086541714606171194181739777107223773075014101828171109460641650405365226657056099487143258905930679574237317845176027548390939
+7740302926757091096782313708390498469422515280866564744352174072524950077317896546008807496266670386420521998084434771204151893
+5027934064208470666653625072824590692528078583512194513874229573957257382460729248431045517338285948895199087965965424240384379
+4571860754401274665671127939865476298997613160622025616980368067727347277864838846767268485621173877779887690613158095362529635
+6944876714447267999239762443038959101083236381747476636643523496718859843462703424789350147757356429745707937022796547995361159
+1608685279655308172831370710312433300754386599666997983340912162248117716366440489547493562293368632280675661325251959965144367
+0470115155279779686716584895721905617913807392365128663764858517955975388392843450401077964641050043314321327171303982059553970
+6215103349524529478271694130462996515027440018395285605756916821272681672383831564950333676633547276622946473458222960324229716
+5752661076880540890733587009248458903926085507327954333035749203073156883894621881819872469950016600034383209674501094959670531
+1945586770541986321354980385963397070039734408942633942296911586196737659678600361467268366772660352728384921986880900512427348
+0224298460720490332231265716874929497392701347632450314627063512555464017409367105505507132766860559659364230297395631822230539
+1702023132625842749699356356536784362975613947059773629978196487288877402990298821674431326788769352305708774873068640207819256
+0837874454109632180336808361233189153201698197837194960277668995755988025271886650717010166150668262322432532297058508033324759
+3169311626099247379274799980132948823347592107280599635475818048919814215035606030291543579920124429871014029266938736200412702
+1914619565140979302991699155094170839054951976790499833713849411741065459327090513567799966465721776223514774008243762437394273
+0284830262288056137733605741424808121279641702537891966081045603173960192239888264018200262442793489277094386722616393425116590
+1173151387211465492751444105592198529015440250049757464822160661232074007786672709170841572180341360083386765961004042180282066
+2747834197332941363146926817441453515366505571978984487189489275517487274745916049268403158626553738640115381387510687487708488
+1958762131814281375452347210594453320648975262319481726099981862965271971390001963271654018154213822420613244796687794506233768
+5861590138913305751605474142329109238465204802867089486028021810232894377402829167243953763417451369079334074531476305390636648
+6931736509544684644323440543056340368361669695138186889701847677102848670844548402669049251722131793379128120867567738961962646
+6821092152578736586590175476051687813270318648206546383329391485549308897384882743702278026541948728683530021908873051239269012
+3127870261792191598343155115866595959890760429348459173942873213248004394755219777755565345896164898508858847846745938219558572
+4104690546998169355396414252792133064383123628337383872945199098541769741499506855287626343383400914652705990644014540006261236
+8792100596328961741396764802811919634888917999468524631681735602589600555328679349075778614192998476904702613310979642799638155
+6734793674993705010403616483433595873080508573310753327845752574399663353072797746592366100412052447212721125322772808600316385
+0099515723538668132596125963466202152817452490708599517233532239221132293841708379481396652887673374586403485713968074564071453
+0083805755888358130747915433250146084164753782259744459712819051842998158461581619972310157769421457011089633907439164606444507
+7652876608005273562462370933960187647117519619868786042595158425921249718553500241273244226393132978251127763667423654542879946
+4405249132813172389850479368504130884719811118887711374371841091799443512801595585892341132692059703325567321860246290919547167
+6941199045895501309914547487559727954258599982156757774973817213033640726217789962907551298312065690327505399614397188477788050
+5358645453073717607933338901589045055393757684759513577031387645637409945004898936885098068574782470685593557377991753572387018
+4706013177574137609818422036943485331576839280415982210652357962891328244924452137995064340517319656166353370990119146719861836
+6329505987385677903166233247184756000826411332850477352758018273420949926789280244169127178212529891658087198774279941207714390
+1511370436371213645604523617727839098695940567432172783593724006252095799407942743832278211803447800402891197805298593983426545
+3022464264863164058488714249339098231034997516428008392896433897781383885524218363385806736382055438093644340647396074293733782
+4501101178543767329620885826562169899606635544112652117620964836027885674519772391619599940633712271697963657935450955634525900
+6375010018855545330452050093482150077359764898798182405456683026765532905675606074372556178229924063905296358938093169081598198
+8483257277634207523851089755598501951207216079577367620523344599612671928857960638762403403726285770712060711385777082614045533
+8256451384331378443868986535492407706512110875647453641525322621598498933275339800741719049869908400644823204415096675208523961
+9398321546440720870569872262936542811668490033035472870984698676634686438176528523891161540254323161470512628073841436944062388
+7797071423711013392162710663609589623668119033549706301015274145920933018984092472146696838533855941884096071158160204252589379
+4261414209517939560365542448209082777049757262017603674203052224119028323101718025778556206926756191607192650438859403548542695
+1466289085237622991161102650836935979121797669268051582725264475273671975785294342068745493084363600896894177743687712147368123
+9181597431483593985916614200861015600827448233462428138664038851972627461175903260548893373194383862378492912625568875647273959
+9257826929421951643418775488431746425388390160227055490497812088985726596130954189607412047036836095076045019637105980229125135
+0051088814685847441269344262748461773674703937437029964258894662753422844953047676499113437643607083551852374126649110465539183
+9719703193787962011022241398606941751940065229976379345648357311141518661729448144028369831751739729767389915436519514302519528
+4754705205114290966030322546625592332320235853494013451121235653943274561055976709436804717429731588488742125670116982095506624
+7915307785043160782062481393173682663021526076353055172054644485732609943157735268019683657488875580064373381138013382280006724
+1348120551409342824081918999927191374394809490457882851229963796819461455853157081977254041113267197827298870478281259789531341
+3812065821388690082091959389908490155933727232741583927718485507099116748923648769090644447688804257458798099398350465758474495
+2937863476645119756329442458144939324030284617554341982278719802555921010666415523070911564773110585363083165465312366738827231
+9179756558387423308702990244249813252311594585173041207944901196092166608366163256489844497165091829615643175666074910233765563
+6459378049219057988171618077989915820678435345205197081776728544947416949166191536837274889454949606246062308000247423136050336
+9590694274127077084581072678020481871509177233838867384578103147792423645131300534630220077747270144036126808318115046320973761
+0633314308759908977900550446703882605141401119276147159777634200043370016079844602659915203435729306675829065339742126589258345
+1889317316284541412519941066954231638054475095114130395821846044209964998882207473650227876029465587838652109009674311273487678
+1491201614697119361909884499515016131285970573442170426537294317539659125369759905519191669796894139802704690179128614455530965
+7312991894729010255958350913145958890797364015827373553097639087944419042322472672141767845335817123220952073258598944857610720
+1824787410780276399243095677626477613009119292679764840577779945279669981000204638159164277233130499426714911295485793124165881
+3599221696151384019695918691913331345308102473844702422853474390767392532790500021180165318933884607342905862054572886894689533
+7797578535955366187957171752724494492272818965402286074464704517072955420112819202222670121573771410655986788904078893257371168
+3476992235872213742357632857624847275225481432286353014243838356580086497628026465199448029895990288276361657184717108337186384
+7666621551208709893696388991140973902647787737649797506777580191326933697405674502023865297304974748640809764705859758691017754
+6544825495307606554357924631329747091007811292348124154567821317868772060770803350068486092232254680993513246201748613742385991
+6866165375349816659160016479507285079045466715841081115993221601429358066993308321907376618487248492349626318569998572862307928
+2954124850369537534496609519161469912394832203382444510628904117251662671751490677012621979800464348066614680001698354593940135
+0193499508454379205949576005154484505543366786538069430200252986165917146991374529470556848495722371613024998552648030029385354
+6300091436093722524653066330745577837674427424963685925900231612998930766803747751089009018089480544176580489192755004987058784
+0521904612577648015929532704786690696377674858853171421019639025087849558650954768145265982042719739087464082587058116910545924
+2995811242507764873679857631100733041164546962708369112790103328792294311269786039292022283070742012101949352297665947227182231
+0598910805263795572231168128611351576632001399408367899641814748409013513401170040370795100905848171920487777572798457368620639
+5688904469919555388263250672582090539068694827337359228605791133091700320455439594271216798892203930514646320638691425342088585
+8515424974655688512862245643897078195523156507477939116050565619183311712594098054858317849757764852624936019665610738326843069
+5113156995533534391502169817952742278838176530218998980784387996273419179922080679783505603663683376521615832986618021979492127
+1086319824275441488370793880965889728722603318901376609034648244802721809098732997770252918945517263258021059460064891744542026
+1590099478966776519298307952043122519324124336024594288380180094489716784777893529727657815697554594607079223393500535902031225
+7357641282650721485620638312466056185406173433791953981763404688139736645500991900862738958018055032882772556895285743906215162
+1650489828204176805947705046005072475080530548765982426627534295084219207983407930870882583588364915870597364960371942080426209
+4961456796449042167841011430036294492463136865448894885627513655748299627165496853898722132001299392052298889154231937053221092
+9292679093929935825812492666003758036634836903177775163898869080980492856814299385978432904050294518519563887081873640579238706
+3011512315941368814678516363524198263828364895022582836616309022291899256400386653229758118495144379060943664767132561955347093
+7994582030787878507087359159314617931782658556072425334054967106060186618004693028010903789497198319676911594575116984344480865
+6353605238667338186351983657599555627480760430658384201616896420757729940462911589836581183482303716623193619087127242146945823
+5587627832512661518234488087236957525879895860979271923639746468639388295216331627000259398878042734326931204663332399636686573
+0672965511904852366825996694902980930309250905369947812120763277890579450585046143580711709629358309790006863408567461111578107
+7579999047873643551313574662014234072727914277127742448350969386406545430650595860664380236476144348769728322529154001617830780
+7768720905776990806878980911933213548469388055876623124525549575902760321680062870410042191450149173795942693780209583496274718
+7500581851674961002356261345542689400915034872242480502581980604450197467020488142845109390383270729947278076491900579496982299
+2129690101587171429651661009917402506767801016536968984813683892465052790569498753467876499730105980696506174974591421872344509
+7047018820490212289369541715584056487037206133357581281018603240803633328043751106808274944483601431153046581012102597333076902
+8327884098495349573228357110403653478827808473415101824363258200250596339218554185491862934594792362506926494486378909931564949
+1740056330174856891125669279294923651309763604203532765617783458152533228430452541997637109088581841891669514331609715059758968
+4197367157825328214419156751555885819747937310581379204615061923091469679845199014292435432070508700023932922581376409143095993
+2165125379005342133424590972755612895768392827051354709297231877589314385116008084334202246281649011825694669304551295469244979
+4509728839111272144692019658264673559690649474179262646699331625117318888277703635865926266976720285188867979085670193580891875
+7275477166128052446741208082801962510905074668975005769114065221711777393514237422266031434604625793424024653464475330291262873
+0817046411197027445752205700663441451626769878011224256767794721900542448009071309280703954949009199107668829370562168637408040
+9787763619368655981881242490879775693879040221802840519661369579710229328600940826654427779387311550329699789056384531195194998
+2723448594543172549888888596962814780076107260643457934204621584814413545214573904777806106803313154411323713368897701260407449
+8000951726014956095448794689858919573269714659606606617498924039765372767236447524498222062645212525371056330185170891625286898
+7400634580995643373473457408678165048789850829161271772842260046851336944770097590727744202976687517001530085639423877373364847
+6131960772116097152434381501203781193864171006504601138647645912125860654370952251962787439280635180850121164508129160794934976
+8194796768491845741394186667260815254416308027847649620467735109219757947751470402197659639068665099777922925932497275155739813
+5209664008657449547795035193830830788192397569777052795318568835532699855624203558168754541268446171707037486010417690857467487
+8377976554519991606329945190868959375772837211176688945495596448296939525690240337764633216663866800325009183616688088580000528
+5192787146614999641495067302066620692218333148024412938301229255333067720338121642154391246693289222550082295681213541896998006
+8136852204722481664059335120578115477689164853072624921786692464359828604653937695373728935390680120663294293493176103289690254
+1144435038869128719771735108732844672639943553994309593207501141582954078007058121278827020008994616209652065957537243296195065
+0970656298377136326223895516660489631269402730038663872646787518014244370067321464425302758563853474605729399708299081361238244
+0240779629525661769222180612134943092596901392802155389763359378856115803129803025504659400407739325825079102512268146609621569
+1920020849630289059227598433172661405103577932866917079329997842631426173495463282180424424558897910324932519322784595681717233
+1144193327801538649747431966846093543676528159861420323208804005782998653152702827377592130780075570401214786834816747288844424
+7672000694647648348909906701159130777349487715893771185782393615180543175659863092467698777377397102350383295634648499503885338
+0495630306491592179663093479474155305629241895069310776977867647781537028272341913619281785471238537339471770501056143359192572
+7308837601725546836619910084602280257935558569169920782961917685472285154488319168403367545336906857013748237755825054290532894
+9661814404701500878628706398803486793202614438164625925828662516099882010742067149392493627954571934045651513234013334682059852
+0312168977557161126723210896500911203207572745509229840888786198868413208045541779692684493190694384662556740715047630385587973
+8520266389063839477339561111091620930884162729262785462465146299021058533677470756448900131157092740484913244873616221850614852
+2366892600338849323238354679971377016007007696850190096980341739336594207986799037588279474367471064265784394163814443326245256
+4911325423638475961054407270474262985635705119625522856108931080012973303196967168739739944802380176010145279834846779349851937
+4257810389850148158544144932315012034020829622092429506782620637342284858172415547207765264086812199822149360687311593339577078
+9708659858477940738903030251204629213359548332123829955153191520032561522000846708640602917979387525987407975336034837147466054
+8086930623135121532860695594083516763569498334428501641151038532550501591735570621442476271723263173645629791905305955098548029
+2777352200022791503781001509067591047738954816120020121065054036180446105221458464420759433938919480637654297994424050557216733
+4557327979787779116307153599001198923403057470538783746410924085722270113118125208362788921890249447415394699853853075390237309
+4365884384429048241521760483369109759203884801440475321881130286288789565265074980716663859447668954490193155283240957032437631
+2400761044210689572007006009552492603834440745618264315468884643834376009957185817870038205575856137576307667033965516109840180
+9737040417279915834911486990827520959476936502177184234720809847197612305989565105760154340868284644203521456078055612096029018
+9781808678278846885397125652129297898882169803910679237997846224593685450165476495607070948013373905740079438009246883252169515
+7739852920294363425633218123401420673829295163516060432640021373043583962110762867984429100483394773437741380363822754539046324
+0883431115446791272406513984118239461183841794345923431236238292749873478934884995894017966307053473725524062094771916898837907
+6139386014396316197310075826416043562421564641768733346779156742528616231256212666391070181857228107399708720583287723130892055
+8564495834035892079724353995520557131026025067703760714350598180164418444716168502414005579666385014431317699567383147791141861
+2311406885413424305003701677451722846677377710768986204839545491722958560065098823523147478261771908820851989126482817082569115
+9602340226869859614696378992497033778548537442058541618817057710375353486743749797455027651809309416058045995383235110379798461
+9628709222162680949961060074815226201933096277151174310696525731658668144988286362519156716805236829848685383992849148064465103
+9735346812240729849346428396581006547963793149866858949294858741576251512791660305611651687839731531035722282235292660633788691
+9538042061855430905977346502656421504814621398394569363683719060626568625659708532699356988708790883640172621307887407813836364
+6305019984976325257337569429166547690694053229542307273781369534773313407694544352991644928363693848808898178142342306260087117
+1805704646504085604801764484506100460470712673185793035853367748681894021658904030806253312188697070560965442489042489792077571
+2490985236219600794455119570755743690829793064352980492197865586952595298856978623488801799239792633697972577551080842006688049
+4451839628325290929728145285465077829042998419941805433824084767085375358192064592570165051059371791323138480645291403839150350
+2979438318932849641805788421308077401361414307061802172300131888869924632094305534351210554801463479850767128364891176166829465
+8872921500436141106816138238492673770588860037153870977927285412564501357209059187194899313386454964167921543412282921398037659
+7636485131279033828460677166640282160440679145358607334279812434544494120552175807283800350790566307285400625724030248887429340
+4680751592769547019498010899871228144441828285042700998685644394131763248290312908027689367430340488843863114128754770298553903
+7371408142591796865710653973046215109255786437157352313924442478531290092820677548020730647005559727973069973416903159076053104
+0296204614919758433624657596498376245793058852298819735885655373134544548701918947319286620768915718576221199382936906689136966
+4514861015660728180490886079334753171354215683899059435960727947953401618302867137487819801076786142685334483700384896695954037
+2862199178730357056510866292501440152986864077701674864131708177930481209373944027435441136206079828523990989033623289788521958
+3232125855905003070647322986167904784829417211608519129888545490992306400854811324029764732798696566611533605039116218287211064
+3328048087467522304174357185558580322486932881453149442008314359000540253074863751401069345083176437332910631591438430165816043
+6086110405144344067589331082608930355326779125945673110136783179380891079747539440654925994890579005806127474614509336396435324
+7215091301714414443069868776064064504395207482808517829405383379414684365187710912963053526301972343897304816484149722894728342
+2436471129882505774580140273945136647748090634204279933544155848974105586771383680141377892142181597367201114241681187884944773
+2048644482475865853030326358622959819676030401734261133906361439604280224652350627125083350512410927294034793877892580606553735
+3602935472072437248748601211519488988169731855279575778400706577254567463123219123896535430970244921999769114868734160215986062
+7783657628040022836086246510234417653915945131795351860293548640058155931582229824232337815003665382949403984933860425849161499
+7472148054410673792713655531708222900140217409627089428063743914621052166172358563633841329724840401144427912925448192355476917
+0347053733535476550133949622008506766494989314867137093489295258193336447136204549399148001892481820212852414088927422900419709
+9639078047884835538046942482094804161605891002036742318046907668105442784580061293938476627159719249453272549683221805416505790
+1032786228200415283294994910054729118848671075845281886209463073179728081317785205722424406468440642562912784973899656483223098
+6968595178017412521208376863115552570593292656764798517030930445070380603195697501931025439581550142699705302804245618724490111
+5453654356413064906966652124099905267347821364144623020142756809037695527255942562866173971391249170311659304510623511853516154
+2732536262071170918681622064325048337837520111884271935643287214208402090379942906531363266640024631740298714867728868944222573
+3147285446615157276563228822132897878376378847350594831988142529113309891139340761458000809351957235529902167556281922497506368
+4354478919601617063477169153215969873898414180925342349186710519974948744199229908589593712396666250201617868945303106857533139
+6882511013607261756622150246671069745871933132400620002505947164316958006187665439907383822926483113411891198332966708317599278
+5134964407461253261959522854559873663187547708050982034442691200555341283933873911454057728258698109359806239057894517156699836
+6450666103279081547887551782344908272320062944069880747023544207556937435206656509659651679103507702121341392065845820245893429
+0369780371537429488949966165797604230927289652620569227359744404503741546226260737989821878745670653730192856868459952515531054
+3093345869807819730548713734544643718538694047498494322996726007960107180939172720629651622711868833028333458719243526925076960
+7989599203565850572942150442657633965818968052176208211383992661670496993990824695668976291478797155039216428981397014999174383
+1307119242405531123217610464790254600437026788611070015681427406612197589802556879143899518155467294982590879340815458735590885
+7771734336463859132744468610337712969586326511610847632572701236574882685603506834926412287387742247547804989759024383729486919
+5271411219228882208040644078382620627789689028134461694434130394862996168758457553833289759810275955726724366779012750280404286
+9512730467284947060387240979546511277358650894416265360099607348235188428440048072383761268322342324845297508884228837212297345
+5520192598997086640709924048681358015575115024163991652287513881247554854286841200564378110057343645081513230448973403055902132
+7020240592700662201858752560247475343913953666111892278775820432145603140381127320826667055090149454135269196723432849201394471
+5046712344141591199667738249797803701007407397593500840656021101416075518278507896267944040576213675962509419570331142339223528
+5009173314040221242742971167778009936788547416346651832329001334847054317513290947080798012432976916063888435394522306337209156
+1366848096908460688950147484431870925661107449748979391978321496249695501280906214711588783547789400280700153426360634008817145
+5032320677216082097266187853807984797656213614647275198101803139086954569491022740666386321968921335192817122277500443048900363
+5004785469025981206660221297903847696398366951138307001168655587727211921402639926973173862035209940308951165885978641411045411
+8785398824958308479147867520302086574154227898640917802025901098713415060910391722736844682709559806414137007346900318504025652
+4829177039724412998798470463159506613910620057768809973408365008034259886542242550978070824664073713620021235802691404413458167
+9261226904113620784725763761828029554734562287674270893824453948307773514334280989553881807221303459863642843519335273228474128
+3311573735232406552245381370523373424363177967581228254334269537766809380288366330679697723673023553333593300509406940840178257
+5850353980111617800710390835159343131583882096987317262767588967118575624615788759557354550955443154249258491730584290096574346
+6058742867661098727133777961247323273097355895095662383648934730004254372357455111922489913009492093823561131792526688980983778
+7068373836217667990225856363415691473206022105532884987579074277226993152918608006384495892970483440333181267244554192632887695
+0375929236714973683664267906774009903162875936131255110025871545553310661098253000439303508717945000859600253447780364023263921
+3589236909622208939924919255987333064134666511205037102476749734554331712415072770445515704120917930961110839990243914307170158
+6795584768746356073781978623124211251870230688353778395309754364333319536742360245765209901147398777468379230149142523181377411
+2729948487677410474357762288343380948554393380782338431844676175646578459942584025062978984890983296713845183696219799180782039
+8853156389861615819589926505138052323380550759364020828050387019448769426662074170464533329827565869171293278882331249180195752
+5354617268287092363055229579924827016859348547054043349609066878817933385065188678139799271936447212380584467570750380867131343
+6669574812003056132820086160683395897628895296098843871784268115803999250621428898234509785779912888254113882189729913124138323
+1094710833263258542617692112795417986473641110466966207723302828445199198995397058382901854029835381782441946019335577334721714
+7084654187809403875061887873785967514836739155665927380077234732823032340675248478794617424267309726934964316167994411232825813
+8586810770368457480021270214945101098418804122645991758117744041940927633232985858835902473466474854825024480648895385708401183
+5596898921066046808429836093228050083092077217562084369964360104846761170405526779538921555848456229448715495096371173722462344
+5660195590159993019077789825004164832246820538076625410586718868028600352830449932992980717485232030870587444549082470943172077
+0821935416600837395349048851468072663127356309332941980901438793730151587795962214031501434310617749617534269164881521735791175
+3042072934705160703532059769445721283937901499649463824595439982424043872605434635393216517511777007087089174560510963232009367
+5464155662396168936608488040261163576038165196682279135320764015816698209508887367606848299565138365679605265583581996112669276
+6753095562768549798586933346781184629087517744898743057935941129179204236737611864578907720852163937289062427955626269555922129
+5716541079272109791401178359438691238957049044014297693164836859127158377764717929820749372762244199830728156908190474636597721
+6048348633690063166546832299456572409599753235001536610146572139811087134501881675589119526672410909520126024302026020371798099
+1171674402450497762501699459068107617561003253876215131387056282446344211385618131395030296408469586922564210025675216461987907
+9312371022806876440175927558224158477356755411023006311819103124252221341547172708634888791607917037276394431911343613744399883
+0922159956723896116809200304280546821592880397796462717485456950002852867129487923589665229233372270334774238944990617682919310
+7658709241655408916654408381196074058493866541161875193933692025333882777349795393761970679827330490202099389041851596493234215
+9234545178442642967566968436599668141535683259923279950462781030512766827071494181783393026832191674347556257505316419663487762
+0041257342453564273568929735796453624713683399848511617479340816490608890963355058355974856413150349382759095918170362098854394
+9592779304960316507865578967321355607760068698329045954497816675023927602619347677723250166350520531047186145206536424990428337
+4299316161376269795506896486995922307501710625151467203920818965364151628354223037516185750241653836563366411298238504451597789
+8841671421275735676647633262528681899530392131503705721695449652045887039670882496194478043622621695748874619557992717633215233
+2073059696519439089739646800449388322820261958926389800326850308700850275001529873409140035288149114816334962577827586268363961
+2490360047432436143344657376283381577226551875079136121637392911221073093866166045906272906769849919522908370281254710635409730
+4974848754591262059988003622570276863287575164608170178580822963208162146400835022943896925242423440936618793540028102479004702
+4372126595413379264526984770633204109208673880518625238463206225086878596008443858616399507133771134539070683384873925072702058
+0639171273649854719051709551224607779261350414555233764709993649110326667200717789312129165461963429321431418833445603440663689
+7186962822361873750181210266660607397813719262382253059434948056476254707273143420389570046116876618519383113357898774377253891
+4319529017033432347952439153798524883464591210553274851928717915148566352954737293867412627976883192261494139098284868083014649
+2622939111808623590774562258070588172127827495395694013730379591966886930134915200669202327099882207686441261515920355425526638
+1200973651071533307294108492132851108586204275141332635739794068695424575790972361088170979623763207458716935295604008671317983
+1251374850775260697268191392326213755565839271682628582402356668458562455145193885654924842502488021956636839087993338831884363
+2092679910172237700017761223090447686346621171455515944807634834063707579619074178681232780539980362324148874096831135359068248
+7059799025589703414119220067452626516006331839767724497907056535882707433149950178268364082722639297792594500281095862497786970
+4542905544332920101592075397986385645511891063856851014878633174032148021231620025882083670673312205077519194573640381350698919
+1312255205389657370322617251904525722465432117955235178041221031184821368449334584954069933722375723026079372281725777733909489
+8940234530803425309074547064952811642951856360280155612932727691967562499759113316867977300723413954039644096858319695187621995
+1667713304364140592650059312268785120415368020836414159057787321290823207568631669529330852196553357371986318924246623685192637
+0422089184234642438098080557484372830069143118691288742408958852833389685002956551956492581208496774233386094905265339874099483
+1677835356907666147956557529262732608196197501168021350247232245111279150809917571509855702652690905689682229523319549019678024
+3645155615476272052329623583943381582821256380614894465459876556622453836730749021655688760168012160726745987877981868221817319
+5647755640891329597098392215119820185325320967799221680909508299218493251878104661039386657485694867555315346235424508828545406
+2249500944046395955203873004372279572553883458895334843433140571043474669708074473381457065865063499709405786900325552248426583
+1230511579171467602223112925195512272958191569060831817009891427720423564097069405239471201694564617244826682098552152177059273
+8469866721000791525531110152439789939013289745066720962189402891838096512969001059723536174778699525713458075138245336864075519
+1296905270266717168150361331577154511349585629938472384230294812334459038517468323643620870384471376627488513753063864443527971
+8484849516117452587091720711551100043539596219785764133452403530020825880462282298393651618450654255243582938022557870602084123
+1944353914349184905366261486479354722961723711488366658700425467290309892874206605011693831609609440448499484127167958439545979
+1904342525350793098590501390656028964534129323617049186915074724786886755773131382892183343708636631327982725884104881408443775
+4047731221209068512782993439144246721190758070966515666060478086425710216870076434550244885851035049595368742260028400195490338
+3375747312957348876639595293489234210411377963219380216708693519698209655124852272292375830483071612875799792380567345928238534
+5110079232697543396393866568868109799067673989898575725771625847005572590499345721422620239447760726870678880204127450730489419
+1892883230935369730591390745517921975081616548082333381141791553938700817410468926449238904528671037503779324573001732065035519
+8395077376884962568002904176016991329810132526312963614723727626088091850321489438757392596606168596638103913778878129196298132
+3938927636631738411085232552592623008752473475775738216360990000223836611551924314564820835426069886741001153829625505334993487
+1299692449183332553204542348863840181665273246414104121624684776356638436277872632132123576236177751436546351690643540205371844
+9194356489958293805818668234623245496942584158879649161401045859846964460358471563904833418667460716546730472435403875780613403
+9275256836090272445757731146730052254532930338266683064726986679677894399506235508548851649563290194895324537517696553037056936
+6401315045565945782629076626066813595555038611734944119511046358367624104666208828448443470577765348785145599426526721185590575
+0586738484454531185743029468713911469676776854865676690022624209621140076731906638884334409090253652724218159918793965233464039
+3171209020852465810305033445747086308509991604961680580404820907479024353374887015602705890939142087700418451581794807689385348
+9424311150932643701645157338987499029528852262438813754400403069738023146915551968014972578206454343730343122265559473474927849
+7742146609950233423816671939328483772283214892322537597846916524424589673152890736557038920458731659652032921748569241119859976
+6687533180189782962288035952098447575892236672807319984532899523336137857362773056256776453970744401322852572058367357860586750
+5112973080188345114036362904396465766939815911981737447433859679102909113460170044475876180448426521815838110280974934802651453
+0141366660566071877771992446357332649851216791119528638672163150044856967323023760152081614645879961910911227845879654515023475
+2214123760185353539707121031098580866690882823675580600794715047520486504684525675655152270550399135886572417008928998130462848
+9223973656232181173590003292639341133004977532862200821270596930208889426180465089396056658959981954090935260888619248916061940
+6623578698318166136431412779326115216613003933902509874343492190835346614403255698238178964137991654202739789058288364219841871
+8291158969189181550110191401002122993337707939239499805961356987899937471416091612952104089354586248344316163672726189677077009
+2569911973118347742318591298716009672334442600647034815935927622454202539592391699029450660978546827587095337413939180709898411
+0899648100113650188435064875802395140965508050973328163902047496526339571954451436627138016940395531683176282436292339394573885
+3218116539223354243511329358754444736017570099304122222814440304223163469524526595019625005310578387024223128529473465323727623
+2903847495538482030544840551895363794476928236443136637630260470246965452066473119820100467512281726986329810864283236603867046
+4226586385557184936270267709088518321173404628666811633771213904835009960571786348833009556180773685058946093743512399598902672
+8536593915600232712348175092402812063615932808932457150254760365196790780020038688785606653890320304533826035350207715944668272
+7207307332779658122899268750088169215451053148485733154400660830345046074837509653982716901490942833776007996597381089382249055
+7354364139715042807616100729619187431380023428907586266528433249618278407719620456619422594117403277614144426686677487237152240
+7463017222778211045789643242204755641148330540930800826901784405753146374489626927527265867849180494980902054821139633747003818
+5151230162674659769071431499839596583910959703956345024479063722159584629356540852497161935430481786349464090482420412307760810
+9834488101241849496636150547202745300929538510953947644624667132590235877398283748992791388091916279125999482122365178401663101
+3799117737061812716778711014651789301773605485731280987694315010080752800132070053513995645594283497896886041897544784262244652
+7787706667573783951864085352707088626343810856713494836743287556709150843482692271254078127357988781374166954894723733919964351
+3850833609175684557920955809259004150766406752693874551692602542748508158101511651908521148570349768720243116655926752800025156
+0542333256075861408967459343438031423694963841751597298639419078331767590705140401244001636510150856151990464720632445051520472
+6303430699933496407768275797041897577889994294810383735293345544688537126863233465001327982318529841153751728223029693637728347
+5397568768462052741831355049132795323985421528118062025164276988946171985642590654143451292287062379578161283874235728279748519
+4640901822963272018953105436900070403241616145463711907565248533620946580204196365483196723416387548557874992063706490486368853
+2187665586968675889547896116950223441017696539693810802819756256217188102291391477467930773393197219210849036472348714939348493
+0530870138541801269405772003173391922440292694411582576482977240988452402062182324365937231322664832700142793000599915699446377
+3232764179605713808662558293727950897506959582972158149863534091415959234408922619772945504672047855130269189456164558749700864
+7976387712997851037838832161690498586021679479533477214488890351913481087239877288703362839723676811186594991567854176580725967
+8767096970476797579593159059506720944428573124512821132135870916546309651522551842044412513318859523946351494542237948488449896
+0718064204159475781113170590472579807866358541733298234646266805452325502205676982790448617382183104529620072495546016035798369
+6656888096932816475747398102488120987337320254949271905969490909227960204913812078261626642629009104843808070570261399892364887
+7197928827518406319220242665874355187232953000643123084932578105682719648228431872207900564999025910692470162420939628457406240
+9390054304943829673541677221189814900027963471043254648597886086990795714249446234111674340418457357710907778877224567169903636
+3047190706971324195888140547475741620358462920833528017528636158028581644462796976018091635090361132164631234849610385434473088
+1299169151001233913629789222426928990506746164121889744635941525381099603593944992448532482489564134843216370953945058018816372
+8022886634541463283701288620853613352158026264893049477075544241214340204041747957155846007535087712499320675089565208063975842
+8518974453812680488184297781261482966404248280615326837256707090751389480480211355208009414536208955423929547041219391948623885
+3604467721690594055924832819820324481035373705830034807313911053016213471052470202123999030910736617997566930544442854033269439
+0783963633104292458209399376532444272248160361826344666316224873723641667255667675127680227315908535163742986352235015659049712
+4004639628899564002311837850986616952858773518487977784208052701702476955042845648511721265262737849283604073030798668836277183
+0862408653011082563803132060254754932254909982790619138767168477417959797920610077885997837256974272446346326081237570982197007
+0940886136952306043500899870090754863364443344376526643707265847999796477272121932881155662360934605500536289044543909420287159
+9325468416880604404675394196786101658805312863903480479928341990160539724867416343519113232899201923506345096672360143197907320
+7602604379899247751883206653536848520843218205588950289513511227638017895858870330990465204694386615676242643330003217066315632
+0851199846447079085502271034855714656668178101657497639831079366789502032474686387227843449343312220724903806454747746782689424
+4098848471040002241791388735422021963275960354775258076923928679254165040693087908221190070756034164623860222301010088075103056
+3055192757629057465255631284293545235726639464473675957498678493846951810733281325747646636144880693592596312740548434768830767
+6731474905682791005984276464714844713588718904361218261812425686803684106123652431919970410078795392818111582997268429659349585
+7924410389518202685905806688713577803625532077879713115752972677622209346192681858566234259911076164694414416704969551453021886
+9355683562980634479815919874568756218379958083872036318959815690363034752884522901587704723069489938561066700856799286608658620
+0543220462343036193244858851552821480362000689940188453022451557344919396300863983139599553360452940548134852258624017234867371
+1067014527356580183151961289434647684360706506035600010429135039073802230973345888131418619960777100132646812026883383699827970
+5359069383361932605007503288578185157851793814788353694181498218990573049785293883804780055838358139459377587968253742572072043
+4573719136273381835268729540845328454994954362222395612112318303745157807658681724375200294326161779060096534923740884933625708
+3514458846264455850674231783280205705825729759163794635971944702176098831501306476593168602881301267771422854514181550204581778
+2814589926430879599930014687698610766303495462811227979670379853246555977897078815634814137435467174275073493314846601851573261
+9109412328394243903990091864894855454386078755925003658916610663445020722891205775398782367407839761338086985543481077581229638
+1491723826525165284311575346657279958318121038102570973778417404071686643040506005133105712555305338320966176072017676784923629
+5488218241739200538202629320385686355121297434909655261539604247574676965715827475716615737941607238002608903015929093309168488
+6222350309549145806267049598652344478433516262239158892817022906333942210072994901250459132730572231739319182532518293889630019
+8044072077285353283240535057997955717161542654506209603492744952552847242899140500411096612225095709028876598587942929972397072
+1885954490526928165806858149219735696470308645981279734404025197278823077339850867123073835557226495747843398970587652389656636
+3636990744440216604699149114584326945110057025978680402356462092308935861145193409488632679598241716104734129398885084544095857
+6069902893386332364062130016921517943943574898468298687528180638591233629526536463888804022514538460226447545474670300837773440
+0715242925233223925302043184620521073165032928562060926764419538572558168218946544243657541925010495652673050247406203961490742
+4163377094941935791929068796922863289449570870715728363127254502097952823099544701660693419650850191571787642058768071578191335
+2362149372830570291861457450525257727016337864275693314681112878356465000993320675510813633779009823896594571255519867010367760
+9335339409871128425332395511671431500329529218909754194982323897857550540930935004728114503428724192561034251245345901549129065
+0756506273973719264925319448914314432556471353593665242663682345436151888535592338801660197397976918922142540903105362128344221
+7296939654818049488767067190718755957947538340790260392001857532393622868997477129188922872359726386124323878376837617352814907
+4078579999111217939011699307760285871218819333972182125286903838312055662520500719903656687016759241817857273468272683917688574
+8726333004719198815434960721386959090224338905967680668744954339106442434132414526246207631805974218944345895924595868424575128
+8809968439523768418749746186037611280882890683322020074536396621763557542013569567593054212148112921735580176883820120783267348
+2537069038616920940158973428724068585048795501013293376681740631186566951229973336427931288891824421015980577224523633941036996
+7974808176187279818828936860482106588007126950454089943602952411737485839990023098877207814888492767150658782003308086338815157
+1588659669715002646102364063331711646691061797936643322785359527528662208821134749050337274899095692843563066296876088924734707
+4549130202526685872258479111021810868210332005793914145311147798812593113617843971880716197778981371491177307945521311901222788
+8560297570244477829694687977784621455987068942424983136944870380427057052887779787702603030649524780263375021654142024115901877
+2048774313776039429808088171712835186320571466269472744364892701622816406146475324290364012640387008030349061922998372137187474
+1958983930518040048400877463606239970518078952389442564587925608445408847664043055091202257080066087803944336882062127350978604
+4065348283423540496042896789726757274478123900698244046915478972359449728574613924262102889566496871444268574144572205450579978
+3629438124450409423602990222911509881985430704078927765904795404045938118161221397917848075421341126252805098426191320837834521
+8085534923914835313209677375813349364458599796275600866316693139878003025545882010477316042716780306226946838431532163667037127
+9898915134568321964545103764074604849670802062543079353666823915979509779221620608508897413582424170944308180311897168957048017
+5385323115399849956058889239701492340513864492761797303099763383900112373871513361204005145800948160917012448658958645510687464
+8637322858113048873422361029279103210946558131854412009103898341572774795544194370639320402689943405658836056138282160542993169
+3301482949893831756487465487869018898293856072780727019945397657149862423574816057140762598392679733606145316506298182753363157
+1989885295563430148607778298379580655148124775805236404809749482897588166275331919278290911157248463196182871139898936725797368
+8850340804158989499571102548588275214111587736824329752538481445797164191835592201791780416442465525643066854658921528683230761
+1421812723062059588410998478367550671697961940333154251595442093624642651562126033425248558504164225223871598921143098979968917
+2477995193068866106116650832975646638319811948342255800290956070421894468168681224145709091760495793451121243995417375669474096
+3150729646482352886032550446062928871539222609285098660402450856512727724053427921573737445175821849100475781418189174380995632
+7046750620615596575236877490285020288321290904270312430965440858488622217217317102253600290127052465317624607416177498383288106
+9945695686299042380678429305385240697039293151977430358157956385467140053019250720885367675692664936064594234820657654969335744
+5571751022714308898152825948152037875574841245733361004625842517428626308101356793475497881525020804091668118665745094943275801
+8608762448666074656196662829963227928222015907465782465504699762597437156318531429585635263586424089541092855892902609967867982
+1978685830753176969518395838040278058667840236176435782603960672407003909222439483538760352906908927302768494238355233209217253
+7074071920319953536604510843365153876170171633349491568232092272150542222706006804946809770825099582766752656052960983718114235
+3280496115751440895543554193849398007467023324006497516116534251153591572725745514291959829061315518724947165745450390160259001
+0601737046591989613120616719919874653529282948250689745032606820130735453268070027901333295387220734852357272804293331117523997
+6136958737937467562116926228263651346592589988767235293060122410789132148757897567424381946719333849272080001742385628150689944
+1891595701639675010992493605507619576155702842803896050077803395482631144748035073236453571286662875633494080865014296782405059
+6994138350962374748911276067098522195781999897499082597900135054301540799702368264182765273926228557006482725202228009397664985
+7788023609935244035749201882811852725625300846793646185552122933557882704452555648205100150340311907075711931570895497802594450
+2197653103798752067286172607092220822596982226247423576487125070944191009560709583893589326623076734376750057424185701225493266
+8863132327252007877822761700057804325184406486939470443703245734365105772001424789573894937476178130538608010471355446757855177
+8174190110749058109791874932401725786307915411703003043709908238217181652029602262116068758446055873309569311805547464496642142
+2490958747068677929992898459199669839140241121204680850335549077174567238373970308977898462513690749136086901700597984427253536
+5982357462083434284507903055152940486985159078049952746161034961672224995628192794860546561549979398991180455860037140923248338
+8926976775587697462174304166383030496921336111150196335640267063653243971405939737115496867091474614902122111713955464436671112
+2328015592752422584686538755738383160041067711192111211555671470860520931401458590260603642848665758765427324349701633338120285
+3238367054704111120178059574962944110115171398341904274585267575082605150464279484097073060481753901121878225454945359042570553
+3450237761306126967240618521993384597368444622149529677366929462149782561575513795963740446321127465963106959992420775690369312
+3448814725588587245567368751607825271329254275986408132599484784341832975302652140521158378926626072460485474580935278488412601
+9150780220021887436734602033408383688852530542191765389359753381850912455739194414678686576674855611507802645590418679170889751
+4835292344245385826099978982021385208338079311915794842181613685383986799333650292340449601221579759524765161463912861431586003
+8364091375971775721571844301438463624297900164446658688640976105663184901553656708363187917609334998277021278755741801258289094
+7084708048206234641953289421943297010794421803966656094223814335341165874897678668246105857901156960186097878571917343164253048
+1580091826012825586670694920435572709977363754508123881333362672498821977048126176623956391025928031884064853593246953559407401
+1343143393297933839473552543351834063051545756389274017156011730389906161525821950360013682370064447544881706475110217230969461
+3302514538150761859786668968377489515133804300482090273478961905590177116881654275768644498073647264106408418864420104945624333
+1455642109436975199690456185370628722356663838058282076416293074142932077562024273500214654758558303856335007961702080005015078
+8063031532965823241531821249811544926127012157501395220835632529512891602224510304171587094059291180949555426978545235398053558
+6792060710713434110654251175014016166953632439786838514140951524356192499726146571336067500056531834668571621898017480292338282
+1437695510093265077864080367192602710341444418961408220405302548941539890702354912153612054318858614633735009858764482449040861
+5181414865532338468286437374705876616670683310417100729198121447458573292151625305538384979133781114543503822301014850960361423
+0442509889959385737920714766510641471461284309092021412176656794047214218226892073311469169814612693044014585717564971417728218
+2325595356223658506960436649084028083363095352384800259697237546709925440654926883086116058532378827751785516901620186132035077
+5272017869427934924377297497212161665902064352062568107159660976294283182349751217848859566575424801083760720335160297859673425
+4927647302447341405487506286250768152116103802235113601574433911840768325925117428685709060725568588745725091307806563183578704
+6009173829226300709392490503960716312095637543299322573027471284752881663572097511651811613598957587604124624018835545870558611
+9874256128717490827444943646188644499417848153072863603454092200052312279880710501340245614763095671533551439274986414901802322
+0712116664532492284027602515056442554560965687688409213710573265303359796914199163349296608736358741384041138558244053035969858
+9693983191087651982342027390681525334777714170455444776207288727295047097906322701667199571113890318007616548536163726817679168
+6706523778360875477183129443881169868743369990013775836046887154518569535610947164990958856446973388802060554267647855673512269
+5862057420569669693068391429181291253874208771601116624815603880238130385298427887023332027652265710135551985724073597417285974
+1151313997638402328677281725415458206631525714244607205307139347412188214659490398369065819541976622293080801350270699351750349
+5489131825943276548129703872359273308252153537674522058679810049913479398153870812359217912596783251244700635734540612732369203
+3810123181289945953628771451906051867522552261199661987069529884844103683969181491185606510174695973406830793843872394354042162
+3346242314263710422512316433607417431578705396179309838772547308651613774189871178285455805352015354652802479496815910335754476
+5032059944587174601615131788722847272253927881072336845872496308794095355330608135957953660775615970673613290442946086962710905
+3407385896995114869865346803277241560730078573870063366755416777507927736959074993460049742600768481558296737228998922109024099
+0049052520096863687692070927701978011226142548782375715516453178031755305702747877694502859869129537906539333534520649523091710
+0991259574063512483397592194908683392249793361680299501959035992654866098958575700878621835330177239453007223378603834381079687
+1103177507554459538813745204571902700244177530864339036101223775180048578597548931452670546251696214644617674818880606435247986
+4019388020763636749355438098141001952281422670022244785922521428313256185545192914769702955966048643204981030086298329088086717
+1549239391810219717095199987772454895177623386763902046734720379092060908409042895882464384442634362486868518995850543330943745
+5263274887172899674152253042181056688293450964020128773142784973127071891058343458622006778652971493625047746423062870250661196
+2492300927820520335243072396524887229850551524757145264574209619185242101186100663595852135831547431534587842715149723823788454
+0239821705984933412196203741296576026949577895980132509651253316722691651055934018399445089497754941402505430183658650264000569
+4454480470480799484331207273048645656468167612178274351303856622687362159020726843169180682079344623827123515453025370828135970
+6142817374030811769491227966611452974299687874240073880283247099440633899922286466254504368749938286010203764066551001971357963
+9169371099648374900400474139097217260717487967105154156622253602791903705738661081630850020115390238371457432815879031763979788
+5560591117813511863922620504148281644660212448276865905578433181502848473767100143776780656617049797235772123812344362645447507
+7125601127543091335948203843174929841142906765885076202058923049770681372235738838189576737300366872775686393117885907972185950
+3813261893105186097817193647097680347436595910522013775725325978428043833139417789267610377229028363642103442485430761044994912
+3166100516390908023193075423476442023657276364366869002050485177701831320339505415669888608102030204859429175627661908828955978
+9494583112215459385851845969134725676775320276319447511947728695272882901489693777569547667119292451041697329224102769821139225
+7691777515996491255498611230620011375291757353871825879292337748953866037150788019954259501731583992956846734646612549716437169
+4674403391449814677760084246730522440833433795684947826674440906657230316614951017230444639014782979009506122819959837960185292
+0124355369267161692186629219979251945207193338015531285271750882020294586168274943975716404048435047057151424920598922068881892
+4259039872889979839195103377532319383985569925201669042943584292754218542022884377759029683915124413393419307275904131879991019
+1735669223208908684334277224397343396336961848404316449603849894027168642444303310792840158007116435560970914275701222063897926
+4461905512399641675513869110628312166872040099906116555152852234330620387342830937229572832948858700069818699059571737043133655
+2317566091257832110561031578973018527337285656514910017567896208598685109912802746001639928928505435442403312983994465299665281
+7100315234971800925514182498331922330287575769352512401970636582041663941571732261396082519132641394516031353060487765740093218
+9334108345710950934819716799864030596011645738530063495673802842261253827926601866855793893356025796840470669373855061371630452
+9938632519142602121728449903028585427271086908360215670337654867014624403654411514574585082225609074457979619906343109374814363
+8543685485409092161128411354085800792705928451605723409112677460751012429082851977989992688721655128865875431794910678786635771
+7286092726668793850700794820169050814700948490519583438078010079869324333131287831724247406778611721612540484173599614481822185
+4574626770701467258525092815137010178678255624898097602082268698327798870150981485054197815103745515005378748184630266101601233
+6996566956298539914158437280054873330111337840249130739283399579411421525420812145476940206933841167306808654076518530796691101
+8418268977140865314494741099167445020028244920345037125932530888607409097769183652295273473400544354104335924214164055029523702
+8653179301531871439574603212631671179611383475494609355467328013854637990353997237551580336715104250041179882078593885288177498
+6757096834181706624090949791934584516326051126444323415129234296822035888300651545387936037901447054120865724936805272897353272
+3719471070090385271298581540906250911443020297189549719410313905300350268160333497598330190662838247612158675798074496367653467
+7420546839654007142424912212795950734732168508855699265941182387494625335487354878640173067010282119575715050167662820992299427
+8999971488927790060730948508800281979058687995045352068109470869864835768781397747295222955822196732634803342790733054201967597
+6576480323890189237090109618880316708942469888066595108911237671288781962755118036472198419023002661197238821372958077703913188
+0030541257153278168215715641021711922462243607936192442241352641161941478602829260934238679472069149540374325351015851641339748
+2308535064234691761213175923993413124441933619616103905759452431159366446936203305785164404138919753229165645626046227853031827
+9274311478528593074600453989280243110143811549871941292371158642466286143077576823957560727090752083042241440289345317446749500
+1173344584450748636805732688311608479601983149113524409946668094326431976475189882181347248492781101482302481266734427266149348
+6919145353409181506683417908661000530570384104910516382895650835980412723990294313264588477866084060873540703108364930450237118
+5325748279790493246685409745464007302387808804042056122442284885720787803880628218787879564860434934892913815793329423983574457
+6453232382761168189611119093517182812167138336965744983593436983776900497001902946217406040709180061277827817549237791463409689
+5084186690867471312419665514325307095801242831316185457562663155798586037028408988187703062546161289787145296742552136882463426
+8870611874224684584815641540909217473850820482485529973916085066540438294865034479488663791703681082228740535939513197426568394
+3829342886981207956995705990631766515300196466846957375041259104048073176049856454632700433183856168388096468289412653196954791
+5561500767524576355366009997865394697845244227185393733933754620619491997202491015533470742012384145261633852618565246889880329
+6777844984653507188325486982839438152297369628419739121210603276755667853986365800165693953505799574103492924940759456778294070
+2214788746856145315547663790110177531050862742765653751073730521273798413515040644084618990342819820992718598911810035213540952
+8641245540354058813605493935866324134857506571449379897541736929598327494870227097960497570120553215541706501704428439721082223
+1700972466803583171420254007427289345043866532653318330426834471075577492940413011600530531542381075895357213715112384747031546
+4123673880740060770118806009141779021375877044026069684883815887385967786493701519196377144556351001736897028481481645941513408
+2662387772790420942409426074953672031980544055539694698764834339968798663047095391766181294233657281432203121874861027827377503
+3000685337077147654086746625753896686864534986031835702363775205640514651662788785826457436508900020141827996232430281971022030
+3024908258360292259670809665500668877816383415506517420287409766113445399746700536527732408780456759980633419485517682977905050
+7609884167715679957397855272558744514159873182477148797463658401514781751802711120892880095270644173320069885204433134067923423
+0014100455158046473463596055055311019866188559065450226001282429179589867255611231640796556419411721523548855378235369309657647
+9633011209397874287442661801560684815176053929256216322999478244794557838852723961384875065741787167826618848105863793521919749
+5428219888294008773249094303237486065991730028127620139643719301859855449270217745813940272539972852306476328220561773494939103
+4521537632739898925531910531504909038824924540851609471635849282948417316063275786486909546139512668787750779344864961591530650
+0285764732059028849862258838048464137495797174589639632732738487543884739338580280553036435526582504329979148309470441850901993
+3193744331770081476790157034764887938574991726583896870321256839758584043852505285610942913104942834651377543523173599555843275
+7417116084257040522072018694176431604709041564144995596676144624737792695410277079523480490262409478745371723464489814999444924
+0087200564277539488709914626916914001557170500699327915642055990350944184767970585140183066326636283502929299531353689075738930
+9142572663076266551791245195307340496553949814370587843903642543965453293671993338189766065010527351493298615638788367806472270
+3051117521339185890745759762693550854894691691802102995243849634880012010573871449566457109934687770743470466412945533888196288
+4158491602681925772695910708467090530134341332595220736564785569416215771589193350272179369165509097131151416084829009479740145
+1103853287929082360008599627015884781258703830958532256506076724299192350494313751000293453841630584783094561339455205657099017
+6669316988454995197629701325242327637911706551201433838323166461015137492273818007712193923739461699066479249555708713191227011
+2113634008934694195638896909191311796132499125975665209093925839375449400491235035672664100786917876149509780668632265414075514
+0126792384563810279878665722622429577480527747103593555729429055584348852183674740137123973052149872227487163624179929217676754
+0429035865573402523285948804441336965668748085575713483346016033116457998360922288296258888389027618101688101669309692510329301
+4327425318090553450075452219201170395108911828576562899226660479453870050953529030012653173886753094327406771671224243820895023
+5520772008782057192477714645125967892355088889936328957302124838926954775059515639556003228522011635026617680256545865946919398
+5091701805891827972817338370300267783615596474978619035655959815481776653782092336443749908777349150397039742672328322075757599
+5790089502501043722549854203882262801131152082075103693079735744546403353282880501020065196803852275180952587214373981006637291
+9796322418193084084142426874342342820014220995329829353218013607479946651207097461896332568716316883980489998209799290426511423
+2380307550005537574650358548246683232060877572246000949898947779365886734692122861965160733025000170093436288569747823376036955
+1082935962455046112099818942036953428151667543776795511944294244788427450015296441783391903107987172541886534905100146388519657
+8380489382633120509090625034073608336127658262734309778765867742476489991527857117594934853404329609845740341120593238746572358
+0633586457978329098387174811695256037738146638558272816343120362030421967763476640034051908578551893496813666553354240880945358
+5373098216766144042601726925416970539214195693276289721208185447267076741060153916852700809475592729479267755151190925441394762
+0437558873199426030384531618231327018631366219163826316141114912440580402838580312314548478509711368795320884000345769917178052
+5639423930316613774685180001977671844817204570499797609653987640525926925309564084656003072725353558374445587925969239833796829
+1210135977251946489323174272650887900867086890978166723808871820517325894679293066521051888521481265231417131690626664853728495
+0539462898410401286175566033379657439604282033567012883413399478842279156974842259796901368805265470365140797961756617874554244
+8867613639089241484274514628778139575529407010929548231466056716290533770512410612299882134379199476168691871070113322417352240
+4833451141363445314543208606007459133355986460223413209331799936622495058516670427933156376684533870032838911569984108849259357
+4227813092685468088212208364841572112496680733745196711345105782294865361331232982776705201607924522572931046426758698077037314
+3298920484699256928312414816543062270280813072616261084031990462638788100585936907797010649601422888227353971911450080527103430
+8677297821634129486433214400771371293863980023792460946229497228182272173859417196509074761854532992353908622744248599410546426
+6781620363930103389596792660725581404654123168036180688431615736861252151699433810032668453228299140054818608750957825124796595
+8122906022184441989524946520995601380863784338127264956306250128205898953341684941467474429559908562531894365353100792345598520
+0411240004527716081891095406341655736648076045216518268298111043258024354531159970495009766409513979584877788837540685928510096
+8110610731150417715423694936324187409013994345563727775716872413402896219029394300366269945656385788061342489896665541029423618
+3755150141442065122724114186286854845339699980415816422951602029278923264626041281480497555316143381278936597056953084064028022
+9997198501283363781790158682287440631540353151583792163912187892594225150451760679251039984200332891341466144376776153588743411
+8117278660244194155818259161232321467141273951036898758016163015261776236723767428479024530348209694127274271155128147667928805
+0936167378563389999940015556970429817708525142859666613441735283201399969921725036498088504412772933143791841603758820099231969
+1224164983307664154773003073878449221074064106296765689183370554165942272977254560731754387603794592725273703193699452227243648
+0945223186347621257574665017745770814803043072264123465865881332861490934432664674134678310921895127370062396231037904388566491
+5578757540264948131008953288936928142006135647005490612913881156326258717861846071301620618495929699330750590715333343381570370
+8766152138213724166896984751062466183413369758646701425025924527217037621942282338912065834670044626031344011383552551288896568
+3053487311706357675549287442389024758844523549667853410498690516184480612259764698839374235801509026206625335813997095967736808
+0878702145089270046099454388880300081151816870001049594773880813882330822460954086402671799804568587855965385027526964053573154
+4675804956846633737319204649690805027179329770063541964923158992410097311744090492573918964775287855196910884200372242948299414
+9493162547793763389979831614732404846665474684277822658912090008789913594349007683276852208398902139951370774691434150042517692
+7345730422542157756414350209374237744157462270676494668123673800976571405254566784526649041229590418069453350314530822807850416
+1964598394787617389494252382959463826235528571672258679974212194662236832005305369294264438079751870505403383373187745093885686
+8249944446042573821740194113388700642890510755384482816288425486723007601353010761537384611960083168099219424928983664383056396
+3337126174819661239061831213486837993026986769690178323635308622147431003839607372786324521326222541843059384926020501381139876
+3550125336344588588098791695947139914704682212688259894589141433972450950443922835504195392482891358587151935390940488550833886
+7749712101826086175922145824388719830543614893730681609524662863877518177721578349626789661635402530736054829364302745002369020
+7052231140791673822400576065079175225485411488088090330405642998541294857834801823806307475957421894499261138427284899379872160
+1843292586638145520787104685467083303977045950130084986120058743550949902430669077350548793220932862849879063881005931348774482
+1487754184031131275500703273842524528318488976791651801275003631033587218395976230647938697685183895874331282612016119932243681
+9443865463893265996646234621765924400556069796282223873874118161895663217586723720163197972926787252465189277090874867985305943
+0897354453697180183636362963351299526862015366834373289147517835099724224465741319067052046603751698502499127219361448464402391
+5704747041899601180624074915530540633028597706644514489974845238123048510465569828429534100611326273262355319658327363672387706
+8316996307878784269659645906887598359322978350217418291053466278096200407791776549885681670136754711514051366460206315185892069
+4722848610616728633370187439001656108169740264355894513804107426599369076853462061213905264840303368831514494760256744683488217
+3692367810726295806823047818393633700597950772879297341267237845287738595298116096169937443486203130496785989216239853131904645
+2667811751880900529395751251780403233472004508704751605995052039171718893677809009851286227285227934697321953881347551922850785
+6909280644240056221753293916337855667825910341176418724960272141306897770589964342155201798900696411923242239316269753447770119
+0999650808847959816984860421127802079006195715319055574680057716511026426618826912583374854994252722086849395905477181959336308
+6682428165643537701794115175085151859549462586484758294772142985146427091765603916714315410145159899524436580396471513525615313
+0287601495196877948543109041275994870460190783889596253917385102642407519701386785758190101150573237633840832279432894588540853
+8953039640516871936098610139590123074456039528834700886251621001651688622097083336798736244961699802438533721144359429291546962
+9090712409265567652916908423800558494486073728012853735882650836864723820428807816418262790577395429269519877994493798687893365
+1660175388130474812877157640023025667491901812382385258466335889928876299301453437354017152844077297406456989761054934994390342
+9934657654239690864626478281461559020855371564678749001531999572350068313050489634121119934441378970500982348402296361517516343
+6359086489575862410458280767790738382982543594459454924194612177893193423779790100018577922756855011303081967830570557786235066
+9627300155446988370785806212844429529453154177930814144914555470252140016234923123986998575098139584073958387735640106379021856
+1431322355214385540867355391544675004031897330982334142717560574603867105320387323557316017902469957357722433291210791176477230
+2894506203039713875024969465668820869708991702780944843854568441944017095189870471544531770235169544173059692732034123691090895
+9985087463071783533894010510378579436608410386134175083499511116916575290748570942191993555978994826375337547024070760036740444
+6261306132531269467443124232293674590069389935930085698373191334535132795190967480627467212037239181698443751352939224782894445
+2120942222786996279924477488386308186164427794112389492451650285444010405583566731254920895180572589153915684428013418667038463
+1430800636064677716455907326084896393465425867531959255704442690767435730899236888138775592453451717734356391997983296892276722
+6245887023168571979343600695324609549057431178812999538431044619282851448174071578424122279044132430998592688952289021834131681
+9674276988668745718949139392247616305459443871778443070291211471809698194880071407948810420513382171773670397147925755783987072
+8396960072488524616931349500116793025065793132740236508100883299116095620726458675309257154864629749532773543158061852267047338
+4708002781694658659895872218532749075225884113621393683821853677375696999740077965880387656889715948194663339565410394344347289
+5555870327192777337829881158886331270254424879662205835411641384434648950116158681537009743933205450514200494453854527945997900
+7477629425593340948832945986684831020436243430891488737957650425170704516063535499519492960538931301090427592749932503236484184
+8423876423875909116240287411777889735748877901032042101830839646783823015629217546200038215020201848216827890202734808048558954
+0807456230133883710789676060781653192722644571250120561750361830812875165496905115518629620725251203869040049714454953862738741
+5303451865971911125648060457840129182131488705975454818569283523145391216818437057554152537823305765736049257100852046148635621
+1261116302127532039373528605959266607418243283938981652100937053779793268699698358833723678904084230346993115051100507293779300
+8426944066403361349421019695464969608724905091684569968020665596067769625988182192985084507208329554219894020546830342373194912
+9836620096551496246720748973842622026481410313119306152287268352751048064398407415273133860155815754408933010180348795503748753
+4609338756911699625776639967309034003047928015509904888467025680057353339055998784262880963136510735792422530687128803685177960
+3794220657491630690779260465220147420857430753103256706506076703567632175129351004805264212916552247643663829004772139169350940
+7434241221131032055118140342385838086277269231509234123959703170231052929402882172699084758826526485094213048561191825363736939
+0904036155468367437756029547852649525568053491591721559536888529587622171812488273446127650656057211625693401063929504404510727
+8594239813337093390867462989975908087174105244731466049861585875653241923202495711120654077327719056153590078128352003621088112
+6550980939146114945715655019872060022635651047970499718424015515740106255804720532248662461951505100400404921280927158680583839
+6741404050546354494349489969507458195999859785965336806692031040435145352201853821004643353403220778871762826594034649052903693
+5050161106286616149825562707832775275340760357578872487646716309800665185049903572794595588208600449320559114964177323489795050
+7988668426398349050514452498533331732900030359537800440340518464659495823291497139184592287414133272356549392805616744235453149
+9266075338762306748845630416478232159198106165396768656800162018036519950819645985549720852139273704724379986117806399232175170
+5556988932197330115132604542704979085477903108338527639954740461587257180160289420796745117217674397152069207476864049579397740
+2173348172420527062990485233356407054265180085263061116024667765176353870469789794863489543966815025332527451848905334447400043
+2653295629344700441742575198328366052220017722996829827117810780652298604720896185508927603921863120335461979927552660891307644
+0066285895594775046166427188466940243950248922228033222148293913898651489477743932715196100030572189599370661700468278120150796
+9557220581453859816276169005234368536133383160153382159372481458293494645221000658600106273797363754949138070903261376602472730
+3805492311138707905865671027330890704509145113408439234581134791375788711343962876719164349282530634198140214550594966178264550
+1436926045326544742314469119616902325996600826173849367078861191857896132772006881206929709595222480758410968732831090627983535
+1444386260983859263563013696700221044836992640755935489313754181471481261753184503838050091200730279031416065367564840157446166
+2902149047863838396186395637335864504592375088936920775765866174611877001827681253531321463980847446832448377620176627133555161
+4791558390249335499772225358752569718358080171845842601137108723166037557543519329054572216953276760772287383669070062122544693
+3653096889815826831439877436629034472435210543189243295673175535474384447647824085044069839822212271287638158109858092072312186
+0748574544351788265285261914954044165932622710335856937231283900552445994528620171010664109729214838117784033934235805145199914
+5275894527081180465946457660332530286653207667782652877623355615488795343761394166684000047525776778529177571402318083997867530
+6467109418857304686760026137696284413841248686101454431645726165291910757652786986378480149853820055715870646485922893256858093
+6676215878298696393785441082359744916852977084427450114208277030042915360587042453548139647735771416607502451093388273522788649
+7671054706470997891661682369520143839129305382788490682363534839812789784359519127806453517900921204537766515545890569275307893
+1361042207361371441527086792533736691205317414847988400835638938786015770536113548366581806919926001472840811854920801842703777
+3513103534581691803636903931367504112887620002748826537288400922168108606124444688399865918353400722960622289440592437281395265
+7889386408564819031497565924192895193912656422791697412472168255473833561450568882333025985344661645666990267705103860364236866
+4138536431654239332667925068305482627915123154662709208870044077990559363503200410357003059370208164876016094801255094919175222
+8463391696176344840026735185830036495571599978819527559041511392555529527154011417043582657075386914403021244017762572439715299
+6162318218961162791019379824579408557803275130662824155987476456514181881477682742571553987831058318649000691189597142635269772
+0762970133488857814721372272166424064692356325030921377174309564434883115428450738561984323237757935361350713032425828308741123
+4714351982559489932236335028957017819906944707422172680018267561533474486226912008423131335876195206249325093723564894293512080
+2816500946584950779938046762589915909515704971018715869504032011106342871269261795583577290967260307340084652876419981696310087
+2895004364486838513889537109545822827678603850445221912466809759993491507875666091568956682275842225830234855225383245575493552
+2650099647818037615116956954341655646634963643235750472739733468509790968870462418042203958941068786618484819431710507936599802
+7533481270625343830151159727689285867369942408696652407015806894633372367355011778476566950994358633971847804532262002525341326
+6932860309305588424128816753568417315152512711756820693574982607856846643933251360676478873401876049759834996395397442053366771
+6368418934202491624332453410763014824694322271983857287392943327020965722037743354197029665328443075456374222598320483575376742
+4282586458471797802238473382178433687724169447427314412337761093512867942490521429740324461721167516599618126259885014134320111
+6677394682606606653900300409179091142196198876169170096213616729601352901860163965806655227312385454363306654134273762118341113
+7643573234932937551595703701897895283801028602846877296702625125220327139117379468939484216431057135643790896852072143295568124
+7835389220407382114018498622358193237717282193191181508848234026347203068182480302817923964772670420825100195578203841958774014
+0034680494236515185913110737330886189937723492058708152408147979713114102686546086347368499582981596157232052021983733385897893
+9959931900795867812310134476649406402976231824404571628106712844354935633442704883886435745579659139240624317737165693276684021
+7687653483916295211948300957846886688394120859824086212655110896478780014654869246794209169764271870284569926071280986536129686
+5389201304796699165935771717834181664385244359824248801827481372360749339940576454594000410357902778074011200874064037958889186
+2726930691205319100949599707692925525547420349048657283658532712722412081334373160958039199607974848481872853703890943042973921
+7254087398978104571457211604241039805468739560240953011032729779871018385163199958508492807104550542120182914215024552352099374
+0577915788776618918085672242537299536604399259342051743390425673863630842390420280176568564228989365174973256614738413491070038
+6830892093137210682654019600696831217364160874783778871977883927322860408992703263164973180938595498029716242874574648385670449
+5774283228582139254923100205140724149936447963980034063069342493084827233283799090727386532026590721266521634433539903773672657
+8489342339836233604189107412549422519166707342446243631744337172427688799797300485425305108241084447320396355017099790987982304
+5579039086144583780301772101084268454284211524135896968194358624225126732215388025582474957280102865197930121676550220972263090
+3389908879281737422526309759732063914252217622801815648828128392852505613143446838612931228798897371072027044252222238376051988
+3571583131629499703290168358948884937302565954157189422433659984916252703476429662770576623285862465399735505261324990848316694
+9423186355018278041568884367207433805709684366572651006506138520185260823230823570755489649379382727052958581331266615555167678
+6126444225712076374139461277391085492256424369818965208777930082776462483927136117628590877335005615182912506580467844672001776
+2323186582401204627524733122349298471005163415025134564249126647383086521203590734419048262603709759435997087128843414545136629
+1421280371866708001926278928901318288694248295906455469958649830300570517830927222281187526547437638030692046413330135004977193
+4201689423423687675024635448407327285565295542200018160703811061939134316388397382336397162201256369493787936488029791585101767
+1265877778847130342563633758037018164444481581498122824054055477037485608751037801526946223069038643514687690116234164514587643
+6465410554863527094647350795029177204941109231775452235798798372912591022108733306213831496272836341289051922220644943607370174
+4555709604071919166868299016817656945294419168762671940808165674695761877170460702219178063962280901485563918842254363745508105
+0013210837712837766354170359690869396554185818181209225721015219925108353810498389109811284979505591805687297968690234266672264
+3540066879463905504617792447842885657986052603128773981944573151451301111933677250259888942146768184470087035596773903177095378
+5526250295384032490751656419926139482444274162610961490517202317645513359417017299610996672882236901128269120411948696682951298
+1147928498844392902179227619628807696892271738030552398135463750372457058220840887917423404648021366673468670510142397314290816
+2022158104950164034675577261500173802135526124382488977804744045573154829053227880877248106935421683250032295002832455111826392
+8408395848784043250462314109208469565763023368052967204488715596813441318603486322106989843882974610129619714497130039489786739
+0214994088989310972413925550111779902382656332396702390689823464515504633177056625665996413210331231059059122014949611785985118
+5638643037266704666895115401268842632588292722777701463135298698439281447394022408579092978979422708178801226855288373349007705
+8326215915178072795379523340039085009563169070517125775679474479863606678664704404360480187047960485640111421757696617713004548
+7011793090984794876958820884434550749243106407550272966012525399145703465211673094494166304978135466245182409167311669917812035
+0646616697055433264306514791141300386873739412778313053422926573847874849306566154499488632029298944379782617421929711377514401
+9297384752555069074761141370510516463922575237795983591479132397584337422724053423993525662073888857524562744276272922807488244
+1675900193060201503933483483504265157956265823054822690157216718534136770295979836197494827206847083365905242438375193125219057
+1431083489513661032602020638770515681536739853677363483613015298018233407875797334225693452983166033993589897236847768729569036
+3412842920266990322594256412420427432972591970945387529406395749977856430023496367881365081011414676715347811993981995507454759
+5814144158348481510698013052752762134884248303529348153673229587940320030719465454064415732294560941869034046035698546780721067
+3694293937312762744233869259702927434016315955447360677690945403418821029256532787548058243155743890295919743842535871205350185
+8704385056392271497806649473016369833786145282019863224686988090496033200166054190979749241314009880507707963024916288921654292
+3157093902990992972624660747840907228349704051194371097267625916545775966277296334446546102566702460108399894331979790861994643
+6211141708601791603941445199717151439636201237385208163393264036156546491266459438443028650233309419884755515206198073403412631
+7609935217879726233731421923555596716242460372189351557516117275999330506730738459524772217152788164129973955538645698104965588
+9847824808961328798019186709647321679530290047204083126132050648182784705034270305452693472108814807665149578959595630309221057
+2336424726766825888588931956562955321343032371214572623650620016457504060828907233038750693736196960807811513112341914628133531
+9997503724107344142689181995651896815056436454295876248977561163594537358114242360861284248276610577578928061231272901007371912
+2013755472268039887671228509805013770238575064767125406070391538875450803622634669600191763159687914916440803301533482646017516
+5799981996920369911160876482866900908859555470100550461338722440379485926728401393736777675182480925560316384661340355950830168
+4131746820931543634876854491169439418699998977639325418048790558796894160516876451374044889060607036066881936080985211558198717
+8071462893187814119459304307555930509471933902061826760709069595504601694208191737856286699434878770893482761009503838844594596
+7181730908337307386590819037242463777795080011670425589895801753553643404874388537396185083285326538843075531064088612600268485
+7874226918011033625880877484768842271536701038369116084490113476976040281425980324472775723714911411152630252812320962593721057
+0414263983887707664017378501754926805713789236380580564348508099662975168539697702344553508537455836440798954696577079098427990
+5498272997168152869729083312401990047724554350008563240202328869525129660589507428406050419409546123885174117080636577540661417
+2321805983098426879552953451815149973073351984882483766093075912871745174124737636496091875961776384678278562342333189413446156
+7532047930885191527458749856036064187500060909405487710845907268217223665450938676158247000950256593423837838865029236735406065
+4326287344295297838879679103933460283015103512394382866450845885799711951741393486898208614864273534333346921541450681108663424
+8567495767845161425037712088656492510273651099963049803480674659806775332933320452431001042997191274150089937218301268747409008
+1892491166044214033213915009098534855928106088594182060850901874215590307570900626843004514029616915218847005161443909006676086
+3105173474201156958194039816160955452881468075916368040511971709028208813038518932050264340243550030216756906608101248802881284
+5437478863331533890468364414134511741947560918971502005022258558696334726057777326125552089511046269814814736730962698056311073
+4951554244048858298258123156812226947705933314291630536799208713986095914743504621255604040168912151175487398095913442501527517
+1612279415688868683265625113331706654838561784474685978138326507909792993504451472859581305912676732125668231491237540161852687
+1352117401098609459260904440848555453118498774861101544577811081137171667682199549961162875051222443028292136608108908775783291
+4668566015341904293075901042719184643021339885314119600028221153413672044545251474917661767760069310540295768155060202109602728
+2520334200236839012091693839792035322503068072072460065591632021254758742371667902074341537861212278319285847598815912703706243
+3175268051143981660033747106123282192419159048635214903634052864839951778255031756400562020446144172393222917501787673701002700
+6674523291734748122422773809147614700484318146175088254981107335895144969807349660283900516719746118645468637821636061386059378
+4188188277626583767786502184322569089569789412892621297176431619545847378700138574560707680259428721989759555839556974186233480
+7390532896972001905316907714622971854007628170763072962479615247643615622571558632228493177244362089074929594584800973845536848
+9849264610200952816901406520106384682505741852721568226048835135789532787094701294801848704745256861395407908649513920150263639
+7854370986367091444291966220372693018093730764321979930716154354135718272983430773038337101141108835455952869661500155683833074
+9808115836250545782744528663456612751035343126746511715032833222650951208562936847133894670903159578406935434899681616157157677
+5449933772771897148631641377562540641640474848389783754029100557570032554566006191465792063723092795517702238425793412416470001
+2937905058909924731783049378468003437910238645835264792097079136587087350442777867813702093887200643761896159097869017005937395
+7717133729012763683884090295651337537034023162131283487583227409327777370699292346651312872193008211062413650051860746533410200
+4095695950110108518764643338298928366182339223897361738328378044503564041168430011712729973754089101835569129650304327287404972
+1174584897511466194183788253926349029362049505536254582209201338252575420290164983455933289840278231035884030712260894346134552
+7761765877961955439161913415420485543948776016504802146528406434389546215574979243086360938551004600037990661153084242444222743
+4353062554304250531566068529474211745999775668076123932253052153101156786485645664269792342453816897835171506547074839704777091
+8193385707206057241016991296332616186095885707895014417445978963635638843413167453713147741250557894417823842378892716883564383
+4414701258878541571780503656512173574547903536405524255843710113697817741762054938128322216548020454736882148058230445988304376
+8363544420911047180282206501238156287142986596377518728647856328365181602387822102287895774281073353368828111014956911375392578
+5780430022747871965685716392391425352083934583867099701698503567269032511748940082003282777645389137257025389413017452674572537
+2606024393701221307694529871431154164540614164993497271619958131424791186768644684669356636777831879397734272673335705649633002
+4789715983933276471694982923444249864558464851612286765926229253919876317314926011029164829296322542092827015562884359904206642
+4213428153587165381335521523932052241841163300973801287138253226845490672931816978773941803990440278669979647051465348624079105
+3419168581475572983260190361701934633564914249990805271700921787735379441310149748846950460105295646015883522763651311765718139
+0643017584581435034370880134992336308617187531872808223433939732921528795419567765739615646487503731718827467059811489514462708
+8240926821672036119484675230474136343520006840157742512260506574754560864426113591474981060698558545401924390339201368669580151
+2180431409945375285121040004138946753923265119496541829137171528887590486854621739462433884861201148650039065347599969036034946
+1220794484575763660002325630268586558185893116790653322219525972500497727914800636242536069684827121496593553311794674511534108
+1435781606190730034271758074654507450242292934136120417582018758847558210750517197211614624177861297537749923102696299059068262
+0472496196020370020276610485121224239313415267755759579734483426439502592786733423472402917351281201878422928096327388672118427
+5664545446808704741371688000935805171339458791507069541059893057148797349299303009996748288669321167515451714205892864440743408
+3539189653746007637884781151821846130210806166359445842675385724193537198834368015119520365512286626859121785638758771673116936
+7228747311262908816869990638505266862436414983330364594232199408818881369887998094729811275091341031498735810192826600585848478
+0205817711643909986528303579098875467050350065610591795091066174715779956393527864740830714556714738435192795203670003124014759
+9197293866434029742096641108142225947219962019182256790387923893087254917713809995074288755692595202295289706002058647970706318
+5801028709225408662416729985040929435165270531028696258985082752391299922713342941633843800570338856731347298583819618303436452
+8554584149353583626116529209271190042567689752495849141906628210792514969913837494587223513509196504949988416482688661169416704
+1402557567228850127015457900783688564010064141030969351494178978419198543363884975731636660451573493841983931009293074401767946
+3030096749835569373371333947576923588432247404291305005146406298391452901679290153566364898274791521766815033709118309495674776
+5711698251707518922789190956913393869735623141004406498318629780886567378932420667481352170410684788247915724815490088304482484
+3076891999474110399724898312925906240059216711193634437769661170118805829580169752019184852464954183024109801959695130678652316
+5549698831705307512844145517641207234201273500862193514468462342310564088815360136277681192006596458241962992029526454841238730
+6411622599480809121036108851843289420809827360922656655734346202711742438003990222191272251022816208079113097900823895134384085
+8642218596518127375568301272202091207693967578318544987425186514107159773089906580986790334784827799489119999185876094206749612
+0920817351118635692704580562112859516048707763068110821230955827967708140350064043987570026933663880446183554485511010170742288
+6208781018246003491238792622187493762169792217017386868912187285653248963115594278272915569084370195923738619149855997663765716
+2725282513427928049648973662146630492856487618068183730067763515357833597788940914019736675580475997314248706127026547890194380
+0912098065082008833983417148631289829848433926717155189805055489641556714887595710925279228500591899600062727405015074732933183
+5895616117549258380703685066950990019495929210886386708101945826998030626417636766877015647925822567530097432835311405452851781
+3061662816058323226135782103379493145683394691280827163116839270882202901941521202335712663514020076981153846416619848715503675
+3704213022599283410938645199398840870678548274677230864636710751729466573816253072905154246398964963820890925958414003660031502
+4630926004977081614276851598024033198734821505047735799361816301169717640380369512425102474864033576302498992022080746889954455
+8300690807062719013236716321873014112140959900671073008576129360776883572345888774946590273926184154530838752149268349654124927
+3447912234767016528327462063192808290048544233618790028527492173810076784214345126091690768646666027973848294720038771161886178
+5457890600658613094704911994422834789695852986406564746776631261869186614541778685993675186223192485017919263967183543307324819
+5220338990377375643418843097310570471194246573225298484773451484736001523372710934922163010657077255170019875356114982042678628
+3627624529201855124798528837400884425278033564368552915095248122583917121126951781145851039073704399808416096566055979179720996
+6138215215437842405346946457258803271828305596332127664808930703097188386621950424243497121232196129953435128118553466623324068
+5920381194124220091735356882290501723032521874921419228504863143247804084726835859796865644318358484363167764149683837216715113
+9615036434361215242420376195665243628638184799766269042140156331651635843944014951375098750172039065463946417568449326243598402
+2848169979084951950982695318867752277301100025960923376831113692149385936857810916874319944880663028251022532340529140647508871
+9496200698078244875645144567349529530108679183666387943211721642572053750534478253516851058589093730399207634528878897274151362
+2928780676487223500661310045048476864951396027388478482164226318809641027170548978608486524888062863065934362652787878241515138
+6280140376322091582258435509210383633979192424770386485640747341583226684971908322655364759264755383681296473387197771187476598
+7993834385710389281257683754961049197160221786960013125265044154150064439440391405850545737192660609079271627770663100625583357
+6072190114323511020360786591498148692349156157375850747362774972374185937176303811511475665210532862701141979885066767496308496
+6809986728266957224821129384937931767139546739620244968569547174693124128355961928311295430759387663715690541708892900136725621
+8713302194814326105418406542612287987228114780045964567511737165272440568730052294690749670110950977545749571399774020053301568
+7216372973252354647766828421771297596834262561708247359782436050128141372353679212726164448161015103612893738264244644610968102
+5490158565324437536585310937019467679460278414170537463829112562515850928229747475007728895628087831498962809803771938282971625
+7508575669851979183836777758657815365989035447083239066619058708444094473391492540134970134555418935400444033568972945852753572
+2681051665685441434594259287440247146082524888648989023037549139977692642794573123372272447282566487899476245382067369090850227
+3516664349028783594652935471979981657724225297147289075312362875423752912404004312370632615551263897637065247961679885605652690
+9466216134195188009940680229231563219004828730503835830166900891639648098483491041893870240357033427709041628218884025561211450
+4848574180102172215721912201870496816515688173491866267900855346017402326765363320124474261873980008204988494006538252079431490
+0175523216285771758146998384814407339456495403123042145864725622594607160861096627528216923235632801268714390775921555811885643
+3472489136602420352765486727018974617090254641528435634640334942425890346384541194932965110314503859645146781896767507525832148
+3797532143892746774112201800929601204074380314303366575611389855222496601937222584569281001864863917059035591510412512996095572
+6540831912166873834974788036724952907724341969947205585823842409980011722639587514582627960169448155988074691268777322159243577
+8665277823830969067856126267665294223334216725032631778088124483157924821285251588520602045895388804877588758409591955378022156
+6073508435137376529408576041907918073738449051031545977935509368280423831551346121480713109837860058648169729195905582970167345
+3067341878979134838523394919669124325563435281537910461171499830549480992384643061189946199980549578258740383418503347009079843
+6535435940186811905537955923044494920097170641355108274375772163581055863892145187878626476077935978473720854007118125956368393
+7039488100826115931812511833016243383119511518291750301509797980336012158668128482275262947277553272940357496952990711563149829
+6786417640541461059254040553435360397444650993725507452127477820766859236159070974204514281362156361495968903161994222700825800
+2231234046323964842602361033236684311038633571563965762668970125159431168316364793191351729000958068187715242930876778118365126
+0967020148060045963966458121640283348948132407097784342111426011211692372274414489985481236783110642969061229593384194970583663
+0518863000584387454760957529314643812512823643579550158516331617073251164731368407116086238782619225015253603821594850218277314
+9500480699512272865605970060364505765826990178852739273720908237913877224017867775678563171957729835114722642208632758208282247
+9138815300684460564222550599375232818221500256241474012816587003367381334232108533309664763635997507997023730828738583077664669
+8788277264997082732015978733262501251796460091814731315709354222338224334551918351172940509755714499856609104221032539934398062
+5201268981606265439495692981057225390935909458631770334121087316181673897848115792408678690299457980695904707677321358225662858
+1753894444989509786731779001286291244699622264775676367978135041545186928742736879462156569826451402964970455781449463407937916
+0502111951096040580120210611615484977765606052460541731989539917916976249725653281972573849533515652151626503088059881052346467
+3880078154575290219658231687424062098862063067654268460424536569017374872824177081255701341783967148208402475928724455704261768
+4392256036256639333393028072709593018903870460743710545351823219115495656631234924513636506499865017761998475934414247147614073
+9879823269518650692917107025520590107178762204459762006129828636469652976104262657652867426597078219790167485035259125893130526
+4491505097353181156857564911252591317148670618490859288558887139051313551147429010258650026546020137477020225229299116254389267
+6985649712270923660498384674089852650962875340575045596604964662128408959309248980968270692814095597628820086983662450615030773
+6856393844414418123694511010327503283724147879193562418774164993500731367874976787177535887228795026180482876909284579667315939
+6933319890504711538399213021011090982613851985557386817639509779738587337666166285748238443831950809951451700040304637246662798
+8972237565184004138743415214250280650420991574154677063216686873786654244381615346208802365774879184715316421935088510122029692
+6620712954831004627906209308475373401688370427674946161939930227860450185388905612087218953668667006558048824549749639289702982
+2252979368901033426647735610872049783979382409247439935969647741186385842273253355085952551816588123321471149874812539836048112
+4296535534263007024565979896369915411490254323267398694533004344505948807352166933785377686738429645888455485219163542489241753
+3740204196364178691705296568637646938043711157073683455458837069839389554673644717418013786210053159123354215579725572298341488
+9402853270709855032434056268150751702914142055269816941745088351607954708943354365301302743628246326922883750858759728646811815
+7702984283703968225748705248163911320353463996186650929366431271533557842658056577524133407573715263399635592058138266058468047
+0714364441200044139354320382443415251209148277388628504182113543224388038221246572844030594506529807381529435302712895155562998
+0439249856337395882945730885613068512496256701244515252923706394988734280606704794447812748091162906835016774939625011625452587
+8701684848748737861671752322431955447724661967607517009813604790923987516158908955881849157986515334551799664962438730731109340
+1331695486624815425190823239475277990544123745272288937823732446789801006674641059010522745250663013852871097862751638189259629
+0016943722810447477028299392663967547809929491638369830715943306970577569121839921705532284065788504261357162084070598074698898
+8301370408134947453196729774027640676030589016291539644959237246218491449189371838582480346507102754824929019477369849852385466
+2141296007314745921128534279212951822200061786556429858733058886029876384472876002241385397319110771995753216118435172891077520
+9778033995372614700099511429265411943800576787023724043391866778854759353346452408608492285235768924255415140931221126895275706
+6825951183619818611745057594180574765846145064255544523604725057011807870654883273137368630387060066151211603237021909384345606
+6330524686796934177420756525152826921339672339044318925623881985016143335928837573713885535605018904858579244102576335089585010
+6476163553560279805504121578981537068558170447489713068606370855078339092366601341950660196338341527489856914865088585338744059
+9336566578276542977779339876759708356666986167810967015943735975240831465492474205336898814725322385265950743359319117386285955
+1003736656415305664502391530550831810874960043692083942495595913831106487788016650162073804988081719551806867379947943364891966
+4573789346107222063252149996048100164143705560186510044433851243141510350751823081763496713992637129016266999061673393254758192
+0532366470306788734368951439658028825164454629260106890282620855033982533015451546843353901652120510130789111458392221784617757
+3253852880221087799999614626290882768972817659832607861376923098885595639154736935283503251479471872499871522284582447822302040
+6285682722317206257124522813577367514121775302484636697810948128394195942996079881830875566043123925277038343926112033315427349
+3775226925665315936530276286731605375257672911376828473612175726312446039948354980701402997357293119532073936998664168131452515
+9033989479402366425600648174316259705202840220576987680353222246016330572206033521947195443476632332503203414941943726000075449
+3497459952076058462828783375726894554577596495151945532419592454939988268844456907659575363299273992966202955633347460395801503
+3425070812671430759768577458384150050234482462127557226191091262303333548668785285283704391650036078067518873006221217224813250
+1772566105841430765131974198596141137685703304393653624186537427347991201369580105964338526460016536799639038488848966636423096
+6770176829068426450217510320589346020757715335312260267538371974073805419798173049507293562584393319422383700569196675270010649
+8817107380879373164458511189191184591118659927137093795839429896643513855977855984835472389317216929700259038397397174527984545
+9182176191236023496232040243155433201447895622909243154991531577802143936144665255362367572046313372242799588041424257757065202
+6776868876338528332502171518394602792217092464624165442452676081627495348032268487133922812426314590277917132179444733559137458
+2894505940700668608956696393712351416879091173479440509500831009675626499007967467374789971290965256917798968433095199887640804
+2933556414955828193417995654373126786599609721238527340939127371332396349156901995803794360944816870450892560704118441975220867
+8553706670591731040619297656286157301262507708170329674504933402137245881090232925455937213553504830839742590855235282434383116
+9795978189578883639204205303262814903090980902741535992637415797011196591002116065669674171784371634354111486560182744790314795
+4119132103638186216017314646897106719838984255536083613903341238051086509058863316947216192276628486590741349320633205188806897
+5670698885913664671019828424294908157556037863822378418679559826760134301152250392322845741422553340998938758664406467756180798
+7800330341660310724142951110753435998016854748165017611258286920601003037645494210716339815788133485140202482683448446213209716
+8180605035942700911937960726293062276511453378796626425148211321573098417580088171144007867547815289216240544844126601589466966
+7821272307041782298994133562164496850666805515425583415056198384421212580796187662587737326754702942280674718201253410570348983
+1042240816866808878998548317060777151321655529169893824595029339588028328148179827446446643616423322057981572730612868764050015
+1252481771070461052389437601673649482439048233841755345725688472923079857771939132303119904339949419801565589936559095363036112
+9690992931777916802696331919514208983516033826094247916936120742724743873182994969726283601645253015955852055017097669830871832
+5020330232719825823684760306159154637346729706124058199917604069885798242234996370123942691457916122474221663868046994104598933
+3075139912987034850456516141324884611162536977850304751997334983975217864864834605427571083113425269670859785386338318467147612
+0588929507981854517277972648054247858977149919377574480251256787460673116218337687478964763305472549592601599187647039007311159
+8091499973422866102588159323886136790375349337327388200287148626779716184548302459458465936817938524771802569873742301251650117
+7114931231277684778417144640504976098202413303636808727117937611520910337365455884518757181692362707318939628346107928380267487
+4950235887683950624565704360578955553783208046483127644086525832912071037741169842458625817412278583829306158758057435134618696
+8199425955265652644399992914133529916068954186792582922740480043066932022166380883075792995446339961281184510898029007416993672
+9600726548050421231768431078919064425306219469503912968092554459127359674333330276775477837154780938957377807571696713004700625
+7295599369136487293154800206051955319915985280570186743302107975100582206721744471004980480977594771538574498512856521123216578
+6297798457301239668561079936581574605258366525996359269984364801565322122584365843225724581654618783605926367931879918225442452
+6533005631078137948109852121400341144965267577414971222703110484819122046478368287561575133762804019638669026806894198861867537
+9875087635268237028446411260770380453643015454432015279985047995719605753073640336797720945754884595273185611911133456865738261
+1289442162696753398201423924491482730765830984320927644525084976853458311031303193411990973143614781325043459014068347046089289
+5407587059442212092113638721767282263392344800170580359252927060347500966261590384053868270413268344224069405566567860000139705
+8360711621827142923632844470555921440996634627172367848310520969393805873503222609811062308946619951688125101610027026987846081
+0944723049476073716566027637737569127176067300129222186002435041592350356420231369282460258580648007773781925508162225156920162
+8475983626059931171149310298021646566523963848825823192493400102745845807108661239544077702836139330088359628977689491846874286
+9167471361458822389556369913209606973474148790242038515231761016355472551050907573614312829544645064709238887157780557241782741
+7014298247554687536486236050770971039248187073536082362810060976896826815113357515444053263548215504897920396644014795535941249
+0560999088691723682614108804238530988595549473233071643241045493910124491974900926784898185428410219894939857122959475910314078
+0706992135879838500099998224229773341412566822617554024599579881313516475013871821845580144033844736871959630619808210884015298
+3257284534077293882786787542863570138992146936142087051892058183105267975351672517356758026095332624891123361507959805527300464
+4074440343205139647276844490970010808052229358468787479224053850708044118534407822903344480715673998402733320764968913814756460
+7541792444051749131437550370667287159419463038893712135130829128921018730253201583423068101308427818790061823168162915307740555
+1517558628903132612936551305596370414201320454890625631435775037687907085643182588609436062805330988597026150223859036793476645
+6591140085443467002438387440547002194892167702007183254656681949652141186889776360123350307460795672547510863464622633652798129
+7586611318404573147896264171755514255213812732114705872658268827371541849326158561820698871403138855140301594042187495345343587
+8296969079616469879346007981374601146907653922591351081026313152884017339179855411584129459367820354848581380738645777750515335
+8731520753126192088044684618604970364839081511006806274832524720914395021711036520236353757973882463981033460910456305044738117
+8522729809358153390546384877141395094866223397312997581315815377215593011496352023911920483284381829852239261360027871178466434
+1761342609588366253125631150586581982113849076981180786682830283076537811478367306351425774976563602440271445970009753618288192
+2190966255981782407270090701820316391321596233574351800067587131465490412933509752425381764960420707947936543904169527628499764
+9513655081411394282745221856716659032453348163674130701896927299389413958771625248039619427975826651601280801943472380714643137
+0617514295978753057337209914173385759751936634152085643157967813155609425512280471102235144051790721763863647958187237685008587
+3639355491023500583172147594486316367021278514106274611239107265098592491987675254836995000835549078267373162122839134981244694
+3032030608995234928881439477961757003027720355891764881759463215674265954842081986273329762678139617217680974433220699552082278
+1162323720318256232198753258939220028085022540772566418699150206741508982674558652349158167206478285853624098497667218452569282
+5449383863141380776369123912608347050738601579475359170938129811063143046219515664348459639566915361115334890006657006031842097
+0352577524785516785715741803748070461694324222115473415680064156677430016348738412256655844328208932407174179588633693022145069
+3240824351920886083704779764410813380504193208597077988968552959949184540967132284829781189340533621232738907229081350464536533
+9963137564898255760485048365009768861444430624328428769392562608655048396702090989488644412080235346086820241525013306324575413
+6313120896902229376551555163469139342705609183907471905448131939609829452611107992213294654747615543541094148280055017927542670
+2193326928610645174628017287211712211408683079421721839813537852939457890561997238125898536070007981217325358023811789787011723
+8243869736268481951401784440593310926754240433539070013976127357814953175386685024013642745787559590618261612069606519053423542
+0179110493828168312231149822817828204338127248358983471224771340698766448231962762617835559498180861959832229135237920163613151
+4787386815157272287656433720722356482569671165537977997843012106191355180546649834098738516604856452092754246704403258051505371
+0634701773994997694376147550495812360818423051628930021511577756465075343321034591427451854134383867627150784580620161049855432
+0766676598258381037189024267219785521248498516810290597640526034223344261052531930836169758828566004912961881921058343147697444
+6482511785125094948376527886610692241647293945078604787929517099856009510498982203730650348969745313708621728477885759515338493
+5205196085155489849560658125068733947071196666550006357643461400687947338189762369344420067691692171235090223284004207347050790
+9809626775201561107404043309301598988061425083419682730787633868247584100867048954636838021112840948572297116645919603622359907
+0822943415366943321888436141210445288839456758217953163265370657515497810970631795622846252681104767475177503937782564413276889
+0099794234571476050102251924980186262893747705880229668101192044145818046711997376029940219465691893053496893208450200931362078
+7338980161503676399103395907119988361285887220551606875942870878016149229490400212073840391368478482151725734739290023095487410
+7899326915683751786630813196982092775796371026481722729931635095642264999233728389534905015911812126591048864589797672830096696
+2751118177471534985294175817313968889734356500489672942275914873801559720503551024017816293024629330339229860581633938440765263
+2579409952433198069628120504384999886282779583918285844878077794508256550262226622072460752726666294025165627679376513073930940
+1557518549380248705140615993858146675367318700594928368305022009826106738355680320673267541599976659073767016002316705812605118
+0706655774414337358133841048392051795234166451755892548200847217249090290629891786004054678210061272314883459040459769608941760
+1894242091014594788195514987048397793320863358408872612791768967887371355399390803287124928045545098723504490408131463760999333
+3060272094521186414251733828941054176318890330197109603090531231771409739699564694060282342629340263255630493316904735659002049
+1028815907660526325417480678219858187627208188992524766305787455603486273947607751634385261335594552079352038645485771077029993
+0683468157651545576501200944305620051155390867906355388005127965874177601579306536442110166029928489048442610212141268455617318
+0988081700313980006604864032962026305268670102163784987963985127384885587927642407664223367758558519122248185218742873483956807
+8435692954315269375984976106264988536738299966701776101047442064080401887709348151446333391726616352591853741366988778921917957
+8956328839854159854532673749984321247777028190876411555620913589749860701945785300696279975495557163768982684990843868186778431
+2520325381475441756157721367873710939223796803781885424158254911912476533014496257166233162377942526340788173572154209732321202
+8180099306765466453860728219641256442389031828386563717730489464926442454808958172470108839488494541309400369186661157251374638
+0628247148382602252920534144240581556722670156430583076620252695866327968997749969112676595494827895760196984828212360640034869
+1083401588117745555669152288505435653771338944376475705488767101152826312238533625308441022273664874833693060276780849703095095
+1156085057274283778724094356821366624982478225088443694900412624860954703963723162086763699442272343649549404340286403255643105
+7910121814653271873529362722249047841930063953194714561480180469523505989148782328178679381325533730833709002539304255163521040
+1625855113537607234401449098110230513476322963277630854102799933050565678807805089239388422442620697922678611315082884292068865
+4371620713456528072846857825011777710835705836437187394614071662418465730864540826899869210260117229659041798505650538477261368
+8985576750846387981996728278040998786610281073838965731512714567426037576813755214228497693635971824751946973019990502558550741
+3401249486943615979298276104790818107736649764729969044884395409904447217117866856126816079991915988836153438356752147841144170
+4762938795985970542856369222277414531064648102624695688826552014393694646959714635482411149329964264665288374841117934547255987
+8266183745098026650707351627828760547702165330658530132998099760473617506446329738701905894912433667123567916471538563863907720
+1749733602645901685261363936495062217041689057898136406969925562689807608184144495204588063954048062251421026224871438707736424
+8548102168448428644279598842714118177587767821370906237000294038845928905112282335030976267725288843840126116450813362024012439
+5938499597145637343173003399875431713125443282016722261731991805628239317480073706051380874344456692406363674536084190692646142
+0730500561374089587897509875647211800809704761282604727960645054003482860298243507208373227297725664305984934399424216469588628
+8419154111597746163254112932894914530620901371133608712199806376981269451117389112518987662727134188058972066300128519445766440
+7937806580759161251998478953470159484262859343028238192145225348422179576900021837242945100592904945106701907680168893307572302
+7516873429370795478978284132360296301129718931677825172903818753611017830921544550227392257770205145640364461713731347634995836
+4812445494938381664839724186613091405433366166945041207304600303147241282114042034521353097954231266436563888803937496834589712
+3378087498752524611421562976032943128888258876939559646852575538636633313807640898785156463287303741217790696080003514700600687
+2916828602935343245489574829087284839505734067476926451104496434541582983914416281292812699388088495707067652976139900162078153
+1962925444708479245069456050692574860960690835458249514553536707157865617717301444683893731781098151767222498616081872995504896
+8173903682609218746993851247188524280631112843215665762250628484523471921122641923241385617676960635551184550463145418449684690
+2919933149036430836155770474842583951453613631150982113752681626101371527818957365564134323888669717562193735500885632774199608
+1609040194815030093545138643057865379099082109649230423000768558709693305039551156969735710643672277845208035827493067182565724
+6908049177553254273158603203912637795720376483171212869602699514186725461068506421013630496115516175113680573200157037543353536
+7096806396941038667344905110986317666939904573544009284947400783005195693194103701914010433669991415780015087815639572682791514
+3680756978168727352707707927350530897842094443052210887958488018513662258743146529661558086974070289076864455883890457256934114
+1990854389059420349848505548169668954938843880071111806085356892226974097003547436768393216697877346132002814225746150600875921
+4374492277982018508835930955357380285574652568017468028145914088210165891776161047538281175076369924948661559170128551211440651
+6393090046195615488795758266312386404911848462625030168594274415704463604586947949625250757933039912135660379167156550736214014
+5728243934436503311699358540925223297549609990942386098315769782770878982264993140803173130768644963918006938211060093506696811
+8242993502087208931436768299544970974899425557012952209431499521399155627662162396837380424393929443574272383673835625796387465
+2907417733054963303298412175669470571774232019901402324926626651661243360954715973085766036500273697051651414938093042950467378
+6785894337286818807967188916007632157799934091531302525882785328964971157321099749451607078727217297793573097237856806946698841
+2698558719450879861393803875387234736047009367170703129862250880475805397892793129358764218650002148641764709592993056227677164
+0081971305438865752091446464085352177755237063190907377734114566649793616356658589817576855323559323530686449621884731840150788
+1826939540243947080817186653825740075444935631469715645767626335326860305087307127848152820195439244125563274241365606473310540
+8086243883958240578268878611599696204485799969418845316458163879163274209827292559109804125366908746820981499563030997204003905
+0386391010049409963011357239704626669689746915426124197111331235480408669200583724344735150698143659880232480059746405028850204
+7070621356175994235487518719187218494861976025281218293612423462113181646903473241591007825352754630207984555163787848738511210
+5746214941035113394857005157649321493185603337720914119128667915231061424163637568324581504110784614852811094476768652380182856
+9112517888906528267503001049949573135127874375506725576149307826638851599758326023611417494647191891545342374452874064341534379
+2427813650814077661287436979575407398921688136831196702246080880472345267198382221158754713144173467705458354166291752011017130
+3427037443878854401716449891823089902160247151232344993329995686205840347612271617101573796125148445827775208799719717001561364
+6663271105359323644532079372626792834540392816461024173260479629489907065371009161907255452160867279588979514640773444750654047
+5973386387254971355387042682264494417370956942797373987206113528047687059080572493246240752693790196755839336183495531383520500
+0786113322119991260636829390212550532753074849695602064584008995135867708856455125847634381213436388672553141147016113632022246
+5315245540985412852477846866194175059739189599584743384794049685678013782286205098025299864897730658726559776885622145372207093
+2947046237055804495388214736381241294012375243250351412075115454784594240484997746146442841037234277389231586332048832314609602
+4940560326735767175083614737052886039378277408442894735731934794992054788139312451587128497131293085948245032106415584594528368
+0132772291233611554088929401128017045937329980274933241381990578374018596495898631586186020586965351932668997510872004538098971
+6387651070790112849045385204698059096706128798635300671169181792420546539133767532896269735055635232257735434930885609585584847
+9016459024097607724588041340562451108743288014737496316921528251742165151671257409207041532182399287641327587310586187223956817
+7534883738445463926481692970148340291005837757179973259685921796789142441810657257829230854362459214897426800925224271446152113
+0560193061957298132549489635518745231685759631661778699250394638322691452161479836232887573811183208096513244778566157714733211
+1547430295477490963534296984638628258877576273566145152920369666682577588376652374130208299869130148553971805471715526321961195
+6131510592032893543765491267410178707297913936975805122290905928404238596549066769665229727337467790389337961037867643489553699
+0609065177988688342181444376437189336384085173474299503743870199156371216381879438127542687917993261590322648797772549606051885
+5486486858037007564853644084702405129390388809213365108089374357918264647019430516503970264903210163964653753490047274772902330
+0461300174226405350596681300475321223682365336534045385167141718398138848125986935473489411898994178547406946367385725330213907
+1293509274626976153463652826393079169386713361776443893666230924263947932847701762953659799461100689690446626123374959253884277
+1306373580520533113454583490110255646387329350405309931889447247185635126485724261288069862689556565591921946727772549017471108
+4575946994632942954732825619796920704805541065043930109567542878956936210283544264617080903536339854736947121491562648913229061
+3705434044613436537344272909123399762720035093491390444488810776264889843570633561219106570438196072991495500597843887820183050
+9436774296203905562085230110417550251074216179370977223886873788396051869595539699599654175540263842606847704783570758848289347
+8739544541060559735321933455321086474549444477666793232318769795339438758735396350156993223591143789407202109979058296632555075
+4292457420547255026544250001229816943682894619632431862491477990869504856164569154248439119907994750443837979614731379296026483
+7759359950784829354681821925764141180511597239315053998175532245470389364554510124781233539932768390441633522487434841829277108
+6460068597420725351564334958788443977520626552046510044910725038151710003467025913052244964411427404827820741380296783360351862
+5211054158075000733081570753562084145801231533068994378093380973748015206056523195741701721944088905307131000364624646104412959
+5581089920926259625216459931700561828077094118449960988240945610479754976194870306805076133937666171790939426378434449418282506
+6039057527913534217575393813423847928955750038761332266774182283692275076570170104686335201401167177077211434292507428463611621
+0405115165537284758792010216853186661681734615099607405177733845109910013152569350731884598363743840624814198617754273927011515
+1407618016023682414983073935592618659194377480743081488662206405541839291934958759003119610099774589701968015068594030177949217
+0790315691986911016674475309797543936300728937674591920985541138152579574295860682375269717640514911824203818306809998011275060
+4382117983381412972994275528147432373242673418215434465602805780063289348278856395267652713597654578622689358031371373016193682
+4971203890127140128708179164505005602256484886747097346823610758765747601150832737555748482400760746795103492345268624660081193
+1238474101549902789927134668369786012288633703563425355984226013256465916402333622807942597885223175366854363298056733781480165
+2475056989181989715935840837103963570756393472493139600699839539995767516688497969127775142807367604482540314805881080534085920
+5110483916952128964226635567750120557932419254741576165448818621280817929369091427028028668168593266857526132988629197479499338
+7382097529770364245616319813419439630747996451787212372784898440040645194051307376865641947314145623284843530906118562837024282
+1180719306858134644273288620402473339088866088558646666749328622134176944113672979075244216767608666882416653166422367766359934
+7454692494850748528168077614552490356358640467830959916873691009192683520419187156489031520981784955116022176529954332656159900
+5703126531777606205672012335960434796458742284617167876316278828807209603472901804370309819783462306443611963348173237324352923
+7622935915352142387734818536448742013947936195902370636105913778439778154319304174619967238291501475263405722167671985219327033
+4192469391918128902822325360387297654953797790226858555687025028458729211895927349803665945095655786671449147679921097155626406
+2780677237649339975622761955036413080116980723465856549727438471457957358521359815258203894427475417964365478268462653223640340
+6384355742271287800278025268983527483432389226283229170112845354988683227778986191910815226499442938779725664362022274661446656
+8983529286956750153487719136198257278584599062333134754547317517831680020077715886321603644059583997509690986046227389994861108
+7329782796097322937140185361853575699691754834694652931632748528792770060065607908729085140248378226282625852546158156687855610
+7542858690282896923167331772353246169388345238738453225427851985834084721866947550098641275435407170332769801857389664211235898
+5799583185812386717849837795175430854770749931463501139883970148364355569591352178627597816164651268936590016366615235430971843
+1626691744466309451182517845050907803525893409042451069687831523577743242687080029262942742968372360368621788807914146915526880
+5318459023686131069631243003764992320489381131276662425282581511713606116289353391248019203404378565007089996278162834011328054
+2940914263304203321901619997487124198689066488749388375440671721678381773728920019056941032982814050260828373786697860844945937
+0935106263610485636127316359361586585062460943315331019818757835533567856247177900197592421873824025425985298148601575872003838
+7678845567273084139170475285839065925039600025616987691701666903861540800590513965950744386259900437461673353720707990879400851
+8954549187260534626790030686600472676242184422173770737899202674956746463128211733652450269429272431346452882295888511514249530
+2678743312277245350760231139022995628706226321476561623183303095250671287742041881664219630594695703026351221927214229218759706
+8754746770599874955073426285210045733061478934256278154824723752843570542480374148666553082213624470594178380618511944338556770
+1258342170448502309847524118053510267304683961421264512188294654208652383435713573419843151024833136714917076044792376946554552
+2686790894179727162588194653073820095034068415445717821765878768235572220948743946189649565838289653662296142578461681042115408
+4979975702994756010947392018214486397764251254586716632357033001934850295130508675410334819960903160411122706650159720668896818
+3588969475934951426055953320940144471459990302441248110905750552714828775127383961567862284258836730043491152173444309138622805
+0885835602018492226235865580484440117123283431801851414462459989105042310153202450298431895243159623304698553633960555968674076
+2495404637338396778354332975443524901010204103490577360377282407257576116606492214532864036869380580423420924036214250605437552
+0273823801820228766960129999040441972228765926389245168282516822705610151382079832776017382538534107323345050070717318572440468
+3719693296470114077607298610532514071278447231443437795910351532332738448270051379404482177889663554053263746637709700053641967
+9828951429348008059079973550469791268813640030847883313731919419849614743360559828672182938947231250356355114573949483277719010
+8160147790535337222916241165963603517851503563087426894556730214593005608351479878086372777584308199478067490440060949884647159
+2948684894394971841029364986618911826288588400559264365297543464936912860908849309130216792677280193265598685884468366012698447
+3139146768567604514882268160880542261286448423327913447026774946542138981930662613526814753066924945383435581070740645979592320
+2648770517875200683345474598491811627153093170689853703611806314466352414707945002443742160480066256003350127740349411901099140
+3308592816806695381210143529051488111319581220479904092647583948868369653515446635908476209492392955841254295107008775348098134
+9546057832057661112548846778480873064251831646186943320977718022174333455691510572548784701482794043711785251965805930805124302
+9797598220825240487337675580868560618123083511865310119111306172185132317065154479238514833175902325985968356007574306322665172
+6169700545459665615556940263207457415925074513750097043236324790451429771342105725243301487094857682554118664272164353388631072
+2065773265591123476370674843120027879502951065822173174917589895449890375502164860452910893685397468281488262706240927914630538
+1707471421521563472417257512298478800552951214730430454446551411959701879859928077389843110236600965268158074916952323108191254
+2504020366275453319690764881376901720307904782764373433647976640867427413961893744590272111954111461916745192557787193817126040
+1588579151481338108756894573873934357158704669830936720767495898488860812251579113152660788061419535504615986627104261122375990
+7331623622011754370645778091243569467777379728540842719407347993337611435365175147413009114962875879124181378102542276566594108
+7484609326756980072187285780841286543812762762534587441056462410575222582806689121646585229111979073490526305371963936438467919
+5706586317647554978296224372749817614542161459685489294484897802898801747536653246958762657311576344225567199024088879682797895
+7982416710167868709570332702438980645861985176457876981357976675349506324625350574864591977896798566893422693217353865223434242
+4612810517637816971256206727690640808547458195070320671241318078156152911173576755031013652809873321281227880993755057868636257
+5869566853914426396407700744200965755799089377206196772845889331869496057116760154715122075783787728423594874902542137832225559
+9589225721722482637458883619679136109478999500918895037360018469933679740571642521146059558547268528193088694289457407297389417
+8114608149302113225536168603740452239048816211285413122470267658232185443153634579198429078537401989102386028340268733889611123
+1658771744647637356624539664960206812688702241127922503053926273465214516451739790546967335354319444825617690989800359892589856
+0053465651697302095039711511050038742810220818349852842019182724663703883278427036626489847521335203092583455303768771456368837
+9461783935995459315552854731516681231226811974225458662840484653357703794689886592991537310946084831023202899386375997693481512
+4533585921481186000403378289480817856084298244494770175994273545179036968044114231324393781909984894250047249639320078105176941
+0088337423065130496692628858394850230047403024636567775158827661121094757863694577077324592397639708861018849419374525563390572
+9433907825695888321692655143225283986904641901823924591220365135713855259383744336203797993519930945597887702113356326830645826
+6988446116797840398450853279454162958768243775646820798515687585868046231740714350466068297160555230698894793181661331483900976
+3228255598385373641636782196372646263654896275851591790742732186929071139789500558984105284755563028281035328678092579289714000
+4681011094010579149015425103883784622081638214345888273901960768244903621448040859732301956914911242855175944393888342553563087
+2560980412018398873410432462155957943116348971819529996430919042949095207925589612393187400930103605496273814170584912659092382
+9069469616610979589154787060025562176784632650316733720274832314981371020706161084351225782272365506817110974959084699634535788
+6765587755549143676480283034752182178980320308874937062805295265849032617917049285075020134633510431916668093086266525800515736
+1987129393090049213521579473208927794007157494973792406906256045288699283419276005662236119067885571670938877198469481410429981
+3722619269607651225319072582934109199126677644296125933160645018724047938190291886105626593185859522559253131444513872231301882
+3878903450400959596968323921819162239731394330071230682797573061816799122019281619186466630116704421984435128057686311537024574
+2171772674581440679441147914828465322671796713303729214917204516452594596558898159147461291026535836576291138961274078954494387
+1278996875658664588862768319875101010284199226028473900312140448349990579106956212227946883352757991736474264479730037979113425
+8251737524782800721142346398693390112514424073577724343296177123905498209033583895128953063498814237667366732979745537429555278
+0896743149526940034664390783553213882383502205749882093466354195761918368893140199641725113693740413564898871253806941096124190
+7796854830589872123486600630498401268330698814798157768931103798808711643064916232366065296644778046047073412187780619253278677
+6500537503531609708551372800808683958268146390074367413801774325497534682441389495398023074938743544207866592122064463211672009
+8374007659269318743410884141200642883663626493756879447578129358932170292700541285549708569643545027306452528039696051958912164
+5461313220523803049639223578843432913631643532704665479011316367050573380692644563882130994146341345324086855525040200238888685
+8089200828994642111859047971321583377842360402699515255215765930754030446170133309029861283548123601950771958367816928039501979
+4921861981592932540366839797291842409375656173168252866766746284441002285941098783812692417408647250610811303546299712956961745
+9167799975366484899208629064327399424255199740686280222254809555146344897012896217389558240697588684347940576269967072665683864
+9259388885200851860744997606520800745929512006692275733677005833780389985037437438896650034386964970221299725643606029624930990
+1923555984126235140744073661251739569863134027553494228555366490941034788475845541690058986834251129830243447779754071605873640
+8546321296959618681680784347875855095908171158196021873844044080735403609307093046577378976184646301996038465275795577308210631
+0292841602799520083981301964025702228115813520124006499666068950846030422607104364257191751077960220252620197225981403964787782
+1502322992487049171872430148257934075524270686852895414785698734102981748355080650539194240735935759095611779799454232906920170
+7645673745116807956634247517521534891766878215315481669195796109233157590171328181080639943010458633508897705148841450600988472
+5372622766288568973430030404326811200585106334044292931194542876927622884286129265334479806408440904927200146880239590676743160
+9737852886366125426992930022076166695307759649277919719824038921587655496096287480936269368326605698820270793854355939980396762
+3180790631743853089037422811844405317287386545411386410379668362987107109358079426452748318127402761332147799830440163526016129
+9051792458167155549317710812956107571797762247756516089487421498534083002847984096816239076561386593955153876706013822381927681
+4173095560231171732875361485159122658902814416236442472154640300288401422165407659115651941434514022078384640403200843998671972
+5966470556331046673745430553457883526280940892044422560744252802816860579980940340917982940500224988618235941234788610789509168
+0789375239650015659257828854233372959702664651151444414363942452653680312005125741160555543069598467797693116222658921071003474
+8906623899466461239060702070337224569185523906567051838309830757794131815206179504935357263945463042333252081048931892858013514
+2565946185596833054040544913117114680329109501977878093743966290348734278988799428312347727405020457211698124070822545220367599
+7887639027440626642608258462581197685627001806341140783071773706310063459682140433859377089948217599328491885205500920242752765
+9105042785087589492163764806502467978793005126850254340679666786999523605304678430709511644540488408967072195820451312364898977
+4806602335002501148210169758225301946374240051070758860058332659173580299590222924023022260764063882929324416573334085874519685
+8860484115578005776711551777005731510087855975894724843956874006078066036507250577776451260714027733005242056180700853839120022
+9972510062716845450929888769682540876602068670550887529330503339523242901354677312818632650357341649500497585776441604969459550
+2623606137079639076047135393717143616094073824102105929404170935516181957666178130675618698894069752882863773580174806425770058
+4036671892720176871088682314351824213287902597131301780764439176800136663620269901795969751693427552587437595932156820043424392
+0677294124292240149296066696637747776445858679559483174535961774585189431151122220911414705647847144029722579499169874681984001
+3515611659295600392682520429928899147250410034409210806506732173247308027181439461299331344368884698174936563300497600474483708
+0063773420552619484426050490136425686777123343387056930411442496315945289353053161802745807953399447036489317450479861853401831
+1025437802898670603956439520711493780674154126180902484921242469929281393551385642769157018539956452797615106532069322627218483
+8759796578568398063968102679425317647163292357375418469803494058822777510870684874739268000355169575539187937262850844553141671
+0520130761108166376660600783005143635657232142524978468353606381401953088627097253750920455395288123559132491257402067683088919
+2890887289996966535342242107315365601206035014159576380219737883962373302977227719789793402712556663655879816814402801231940391
+7075049290134330330911964129274745947329781151686133509827045508476840011833420977165532815261601339404747681713954176358695787
+4190862513692697255977164180664759574127822507052658315853043337010650269787647027656260221445450941719360532423677717036461514
+6908155746961875390092893184110336543104604423996158420042649680420697682015958655453176718660496277341803127921088518280061343
+8331309328194407889735199978235437818800306669005429636917360222653217191676841870581785131998034245906906399415366961802496511
+4025301862689940996141896458524993405457637230423945068131717803505952316603722440206101338781745994056920279938566008667957974
+8407156560172061727221211500538117499687747789630891734019549331980906693172176957439813668311313041124185359330130579817813671
+7466416959132373028000515440426004927338552129675365950832267054293724597329240325990928091976976797329108528262309484406803795
+7029882344252063506996455416881601769204928489785629548747090770306190718064516950313796925310576174715934481881905681054628070
+6880642279419324327941511209000580929409891074059158709439715032933825582097408872913695012908119133558817540571147731630417054
+0450976304961807996926719984418185237945644387146277128118939816965978556618267349869880710186417738649005061794411263100794703
+7430304052534898545934660709004803179571319216041424124846029027406133093839979267839656729246840664461817790155804024698154985
+7645544772776077953527747512204638297554270388027111651502874795299134795410937797070656228161921719694817879801901345933313665
+1313410076049663998827811921356048583498283359569530324863158193199961087225704771561935232487625934010979224924950123845221938
+5542450907649094312430747916423053695607417672358828335758664117685424978394617325307248658166202146920547925646776725087468720
+8125710483678181819120321493187443931435742819361342552711290450551262872707443639793745995943576289709507020621251828473114770
+5808995455056792083922234742431742082106369821885564948694790039533752228468465967393391425326441602867483086230714643155046641
+2407915004627569028579526596926110527896052886334582385573230907225818330304996992697006735418150830862621130034997989250568103
+4747836691209220024929494385208567863244371223110054782899030754719240501536232821233744154670656379727685527957774155672319475
+9632183735133215405359145903218054467186662532650851575633645907886287911612022173510068469813052313582577723168904869118582615
+1758443894147315526858202229285381300192667883978558926059924490571584269631902778078169815289434853467255533171050775547788250
+6827379725903576619807972215479471705793002981926808670091729392075163455575073588508765374074600361763199064144608650998814612
+1139348883195112842120618191199370895634072657781661691958053236883789482321308598352679539450892103726749423679416567117182472
+5628380449503846780627597266237186381426941668768981275727365655268389180764025467621494196092237996217033830813378898293373834
+6249982118767143075646051931844250281862161753132641089322013640269043322260625061753846454820580624883961230554153956989845603
+1506389246361534372134008198497771836659467625678409854914006570144648661265229365915719554541771143877999578976720337073985818
+7005263179523699177762675340194056182817188450058666203568903779623473238455975919469726862072009578002483873154457672262756142
+2974648493466373909300392298493641388947991203930909247567333382267233769728042131150238686456747730553128288781731025800074389
+5103801198075821222369482103926218823537252278659224466101143285542928579893855240568803378461857010249847636234366813910593321
+8255444368358914408018189587539831385866661807993390145935560791507824844153502737089683973595182396850151415917641412882278385
+6994623624086457510788033568938511176649748143257081559534249807952079088004873263643117220080770572410226081636499222544341556
+5868861827549149829709753995576140261303291609060728919357591890769431437067208298630183272025511291993873213366101172628545169
+3536668590020988868465523872067378130539719812107645831862475320339405404292929655894962610265222780223832442563481658864747632
+3855559579815655284020206856324714890689773172461142431850331038157366681406979208119201701019291754639995462477549126425391350
+8450291792039621077539436402960450989801386738795258875543765926494042577259109968714035988972694939518009619956412673656801521
+9433075795122748111293126771649210779744396506362417079033687912993766618349565561906099136133480366162159291355560623721579187
+3378797875509332216281558051343681937584540368139917115626876588840206579792879445323063696609803160334574023091211019696117960
+8286659856511129135392256673984667705469454940089344874655311260297659378259031305125448870028720171028350742267966605006358033
+1559883131888908511800248016547342952257309383028102249271256078844439208862517563884780187208616611438790446776997799461384713
+9213000700276768725565441947730287329227888200262127732583001595805481558214719061412862292967561082950848644790833398460564723
+1237463356367627789252505343790157426584837476951882453112990120548575795054118752744721410491509448371890573822392145256573546
+0705282244277315586839396249472907788988824858086668101214804950902161992883203183045693099700874860748969961552066568180233875
+3649804362910298143091615106831740058421008356128934335979284102172120855125136327683861035088765145754792315464262726624806783
+9434730144784579817482674138286237679514020123482574946846405367389289759453442305761634017866345369865209680919734485563877769
+7735810389258589718835809442124950108708303704945904199371845065484839372522859566124912994258804441548671551838820818437896075
+7383779025406555287701082383561184897642996999173556341153509465466385364878232088945280693653997350128318569872380406482923450
+0873625836034957145587001580511059464110231294763738687292419746897783167632026738408026265866915946594910670670203196220111099
+7591072259741426420367322902499121885937012842290323842004604562106110626665272233088406003591488022718144482545987747891823870
+9175117307974364573779518417573849521480439605413624062061689756346227400155445091604379572899069013192269044493766848399848392
+5240204070345240378009455038862456326732346785249576960346569277468135720674493354585769115025511723751059422380004118585409709
+3349173998694448270286501817135410477702569648480525937208264068896413487832339295364105296137401893118290448960552591536754124
+2721855377073042117183109540215181252714104113649070283807754222580162122302324470826848007123339852921541117150545915474905734
+4442237467667117475961916917266329385273400917266015718314637687934575915917583933649989627896013912399205012102463085560527584
+4091026285900629392132231811067909337191049861336953793421590084466340471776345574531068461460044327698926685026108185944785273
+5202568174541673346987530914965105932805689677456919213224331168071054852507039901870720345655716025476685968559834858758422493
+0614858796890361150654138608860068135509273139791153876597516417474596470901950497034522305572817639212080825359999795816120790
+4690019462662785935463711750437540580321430169890806355137538513325878535253326703788253684313085653375194280379587086774403636
+1192297531414960747356858854539457018921020998476941206542822005080405209643807598603349026957600933047420780702135587594220420
+6385879114957936148095665992720513226197859511089355764654052901972661068207137358088876405026746758171573905075146612191621724
+7225256074560068850195651541217829216290435321680622077492940113765770295891334808874940394348277026794361425754981697514840551
+6579386119350941004072171940171520374772062901476128261790580552298150743389764668933362002827319670377285437400224631386514541
+8225060930462866114265671430768226751533399557663700459188510439035058277166158167696828360029527807376628848000272330091576713
+0060985472860653127812993949032906458731116791182858234879179245998734711417931089452148679024170798661176089885161196837664106
+3722805008939449259124307009136610112592018063781886320098372656598331954054355261215122816645348365251690431718100984807641151
+7671563753475866652087409998956658850991352510305691362750704516857124752942784347614592502287785972007339688267613862027066735
+1058283061155393934892259910225706182663785747481861117691921311446649045132526185682558542054377226003665649454406375422089246
+9732227956822666337303879201449758438032098745926653063569926833474234804332766368153105341066282800778041496886005184241210550
+3671076559003594556531982936604847786145732585941552091406028722895252734130685947197552543811727116647815405252804851390263345
+6932108260738047486627928786730592183240725916073436786293871274003576099287405402166418657664483313714856186223383473022466647
+3109816045417430083537878210451471667742535838802468841651352736464574926057073048472886864367560530408263557356129708697457730
+5131047990674797494394562345612521219564146779615283892037401029449518064490250135341621616256327661631926681344727899774392825
+9793560539429965156147946048811944830887554283992612919784433839525971829092056423046384752108153956186882584119526879128063725
+4848894438740997315189560856906795393017681147097928684567412396811955257068230623390617279746246419592475583485164533349133972
+9247196347885177565475533963701634576057917406510305607776085697222055528129649096213092034549229625900854393776713393006598014
+0895574299458423626122169092017122327940337399418681543962293182652716019527292869659349372977261887962838657423721599638764034
+8069818312801265892359056947805299813404068292205524125399036272188934298155723014962611157660369164361085013693243392717540968
+1746313469892957608005716135870516847580996237870651257913684437466577959076954626426758903637186057505535214913540381448786350
+0826130380070802481888865468100577235559992056039751752075537240976306665243883422413804381659448597324700429367218879041686316
+8783969310605138136810926575209117557352903553802462523920408350875226887462880478648547408932195087998226093346126517623953622
+3655963588132204550439064715232312197339282921758181601943083078440247650220106399066615678880555199248431536315260442825292972
+2898418712339146920156618115849473564647025888554958680753487875973131958912468912448106432964749351366422577093050105438712807
+1852498129286540733225557917645869957332090278845330056842464816843083325044360873406582227952116884337704935341689726805650922
+3976284069253193914079828201683985526108157492968673193265258027640406409120387997580216531505549000204500196895696438933985023
+7344227386409800578949975082890327124630045606308364332447462178940410322375677488036092734345158152279018751575711953710675611
+1365860719506143953539467521806358327791893587420884033512557356449628421974197081525171097681451739962654458105945042338824044
+7339951041651291336434788317295707347631976285149811926440821662705811682404836418364754712250487175296474328282212659994274238
+0212161973979980092408896174977830808566631947896643996545492647236993898876722578200269918604906863319277003087190525085408577
+4872695328272197013637039406318385585335721591609046713028487734545081008963689929406578869624586103965589484238888590831714070
+3093781382852235095749474972285903266360882836791963595009076006750220113661602476802687021999748113402446232401462878936110934
+6435034693320558902105688910308538965196623309949466683973971294957981775446228096356658904951613108961843850602970532678592796
+9900412913465232057825708257994535036127184304885007026505543104350741668197223958911527343764741682299736861152999772201279599
+0514985184283479308437214277006973884479296109534451984897036545588323471166529442587769709637302971344236763633165248653048272
+2548677505362732783025625571327094753804197898599649990120724885114160782630110803234921618274764179324553264262464188071111602
+1490102219572319216164107062405778780633273426833137366869390517112371874174117264586848123441331500645236212846316718716883477
+6374557134532066647778099833443353940716636987739316642710720220881882944339283639205849477871629369917099561362221287484469397
+5537933700604880504714026554029166587597577826204845542181354963551493735767539318268321221914383282788245529093887530478824907
+4539736948571324006868573970323898689460869616752573795437663232396854974783326373421982301397494963660135114656842200560632231
+5417628879269942844019831356484605118567348015685889718110291011794547506306795984565230200245047127434730978214554859175571386
+5244295129306313578981901753289283565322938724988065200258490956019375699629296714989839545066652554067148655850643910689520282
+2971836240187409511885225271973597558472371014435493899110877817281998758924278138897958733963027723716372919312791817550414257
+3718036377547310037822620295119160273747183347935451508155041258644862468137971759991204189248362267356043409939280563151645203
+2059403653814048643066476915696010105560937121353588493219472721117585709084500577027269061641086537899045745026346755806963182
+4321247098580397470005864122314116779988792921164422171095663365610591552259489098505982208555327107941284015766148898178511334
+4129075760977557106793231123557041651779523250483585239932004312719534628408382643294636229121610127684366632908893383504173184
+2529072874533404417364878145806482135038499775952105421793815591456627903830117948809720387389717200574623969207051170720940841
+8319746694698707336604137199806790228573013581807699678418425604568242103303802544153333753105945256725487631110225791990763711
+3880160358558853965367146276153313624158725831047412244380280879089394407413109649993209520904697096729360273647396579418687376
+2091906829462709596208568404663223009844823381264480008433097662223468678702122339891481765380241818468489069582210313140199504
+7634167069455911451763369770809802453049016134384625283172635485682336911180471943157282346432504400241673963332048163371168819
+6945528084709716553738011980160563280642542751055915815221655609127228922438332498633425574184424076324567457335614537707491118
+6855985221224698806898182154405013337026345633363958698774698699505064139860586968819626692305575161911369355200549282693239574
+9661995161189339321012455875057211575581587182476156883528607442238967236926672903199283225630412167629967841892682077069456544
+5556977126081270383421853880021926196747677623279360503448724398127284807443362608046943892392030345708092629807650879718315338
+2008556770184273576766805643194174770708191017610672185545130733621276522353464775534219302741371801405182864900478774809576537
+3865082900785088869003731961311138273432940384506242628178208362272250891137755623037615929981020628600026015312604846649871045
+1810271541153370013506194385701474067688519311563701121092950023460871685900667973434789085894353689769155959515852286976707125
+9220855281244525680311255117572398240118776083069705246489217127641378521494501271090294888487837045515780398860147999941580644
+7341485956164711767365322167960284966203049807458284565556017984048646824943506319395879136232290301571995491168074801397213067
+5371405547126368328180403806382396944697802094247261778722922120527093199887586224288144259646007747572032786762234373440343768
+9641998676406552363362334096338343938226513712459780071504106769464358782102176567281764333076640338559714360625098972864983029
+5780224793125175832096440772460219675603258721147649221639684097269727175225573293185628479999177881598175668238919939024400140
+5871315749737173437146622211284749783435729572078139529891438562616324259909214610231102730312223921245301659630109254504380334
+6697637358599635782137313649853967748604644159075078379860391872979880640358744386814475406235163749464766557762029498100317344
+9260432917913444420430985635427292687992391436924828756222785655924726309271829922076362876173530631675597755661167920958784469
+8008272163146127952220122593079694523591964786341879588418492633364085713190449203278430539536800444410958318893570820694596913
+5865771428552651226808077349460469511350507824410126508014924137043903316541107301501243645730254790431504727160432598689746741
+0797866504326277547835398517451743711623314102885283925539211029404096358855485908679412360891989483761400122402649553985042303
+6315338269917337190802305575034003552890761126872174385267928282692687307003769845400327640284655468895977857113820663582843212
+5883143761391732179613778683464000760776952507578651405618216504779945736760856433526347237980076786027307666785673805176780505
+2608019170724255979187609288672429113478903050968752935506997075853793110328285209939065370268834945095553185289660445134585271
+5934178091636548622002305410563118241322636012045119794891759960583808782939464117247149044590174301040963274743429124451974081
+9822212841254646950102433569804383682318140936706127266382165162763534213426673482380144302560262856995513292329891211427952322
+4939074943058922639133209628604240951813644498408022254626546671648111368884617471264005460319454857408802054462873323814596304
+3567851550694955955743156890344607975932611999373517821856035756405925438219730313496771878294219292907299376903706456079314724
+4355891716120089571168867921156570013309057339164893294310027619061553640293850173132141828093723591781265620877693908024633891
+3432150765823697928455051347308237232788126878764759364421680111689906395962403729413891780224106047993476140159348719814489238
+0234684991575714928121012708547654894568292786765465546202194583822334911755447378931758555122045328265456840620648627956740582
+6213762564459648735386518381734716590458385722741140951208497160837103126054522292981022939593107580769282971517719856277138950
+9795430658880195944561326976463238641719113418421451290008508454179670774519228875316092692131997401436104108663905564902246214
+9652373982485787988119955149332007099514930250170109206849474570844779657182243727422415156736246473756296181666403081597210612
+6363221919442807657179269261813196315614323943076172547080772762082497876523976444410926957078802241443845971487934887307740781
+8442538716705496485993660458983193034639571775952652456130115624584796446966906201307091498198760859970990751619599499849168922
+7540755071266549940783200519568012630337075342163311989445430751720634069245959298519839175642543857453232073106471321794307960
+1699245059009156264426959609151370644710641713396754020166970217700932248280718651485571836633670709702375632170998942628345680
+0816396190588432801059693946646313280382672711087244012208759747817406868034578850546787526313820913242493648577159472787123381
+0759322746357530465987827894614798343895157467747058744481984104257507440485290934854164189380366013210043776529824930881371048
+6385658080000822018084506735695449199723297410443658699992360702264595362859622022028092450523165950738306668328519968101921178
+9290969633149036611961423129438616262578501454017560337962795366936304454531175225394994520495848281893733418969823834849646325
+4866905011511861701376543806753349151579844197278285044705460570867283644779510401658626041128258372474841328027560368075591684
+4097340967374048459759351247293757377219970623863320131555594933368226711740987383236414710324945367020743532195606500683770435
+8777289231702354648686196142357855572861820397757772835817870476148855333166772599103631182225390962911857675993162562793056451
+1643701292272316612682496492137369576459996136135417810378930005125534965897227946840522877611416279622753205256995171831362038
+0366738891350724663780781742018384952618867530073606447030185424566647732433327301660674858875240792034393577096349757765316310
+8289591408206074373434407333542355057011414872348953466323958988208406535831896578204946085981588003478321397316316325936083627
+9704718565559121039339280928457498417206123777131839564784077774260566019404908403357317188872113841441577298919813210986548633
+9293886303171570837540716535349361584600602170148405662530496205079833641395026663688854207586823003823193883976384903470625532
+1727675041270249998973772127828169098733155135266069947499638944765750528948036161984830730668217006998355034769138526948886812
+0092789759212121413625842309085282315688319684507180858726957280563112424218015623004324904038907228951254860936129174811193610
+7248502251808372373101361237612617365642190393287142805878594705588056326330546884029678052177636399750149538893582015648656691
+3367150919108114535725714981888781359653934702237037159199343298241562681613327166427987327289684634196866794561168570101129576
+3376393226054192039386172081865991731275655717454440752850294664224843539838937920883445641690602345087514795742186569107517414
+3623971382393048718491241619316545941650237621831224965329865224908967972818626887372855949653336237529478398264567160685068577
+4052813893095863733367924664141451148648087387776942749014403408537141959668060633169208644494300366994545481397333067992909358
+0667669402093903159518564734675653958529086910570255872008713355774046040785518290333034404789497402572158389475386895486868259
+7468963766629011848413788837165962853506507117471181320045844652746289086413801588758664510368868946415159144280007188633881726
+7244685543653493127669292847190750279258471265994953355225441242455255911176450067019362851931161106818923851255323971731656588
+5234890473800747514454607303289634698091529945347698407177688996229422965619449293992367330399443066079751703944482713291326343
+6459044264277571164204689989304404957960666476059760392612837445978755062781098058819661144475485054149528425812865761888665230
+4335062014272927898970122302854052906295227383275313276798239957308395793035503825814636802802824167294443473540831595897555019
+7272548964073946058176039524239703608785612474858328053422538963447385787828187985994849316214926394617015487472147004996421715
+5996250931763812814551030631847429127490485716717613966608339966170653265360723312151608339298980087240888475983661731432872181
+2297536852364764322872184823063403907099469015512172454623275616030363118664676670421610327708607480232788374190290021972622793
+6341746181410744070773088966325798253704849845010112635545932402181743821794042899160348845322610793015131752714444557452077603
+0974929188283489944704823132680006629007254931129889666199080416689925517182595848963795936091170595822025233402048475030835352
+6345563891720858751435127759306670956633219054037703933137927110019397801896389210768937954353107771885376564624836527498565777
+7406605189056950050564580620487220225704555865872099535962165458171814654057503675391062376917680202395298499820248250031013118
+9646002186451042668001138188414741520592517338749162144757726571293411846579111672780359450504540363461450479439757376293399965
+5620887367929571798109873216776069586763980872092222280624201174614361433514239488022226011723867237579885237366697226018636145
+7658816676965243906096876039909445364177324988679848256414790985301032302828151276736018655718069421805321528401722943260148087
+3504531887253350368429518151187892137924735559724530027941664978322897818820489478004391185810494126054267658700325358193119630
+6476950573687760010199531144942136546086284325150545828401223666989902218958065517474495615521528611225439578736181496123291235
+8141273699960775743878136458997315091877968088833966155435545803714212437024032432947661397098373986850161208575249088483734667
+7526564869781879172205819920641629162261070844597301726270751056013595355206013946667713217060767795442616244184317275433955181
+6807778755059399042252363801724898729347456888637350665052001794960468288523356956423878794195125458046129085019792922364372832
+9606605635909164393346308754559022246397895156754911940817409436883533684563312856180585298884265000503280045621922703129043223
+1353282688124152832117904166784884443448057703427122162928095824570260033806131301099883014390489674198929314751517488130229287
+3941712694041861559776002423763440625536805158907454771393762216105225325673929237051966211204216493810015246774275044495594616
+3694132772158289887311123798026659094603586436166517150338257882694213224057803554027693325965893134619716724281180373864668897
+0965421930380580362871564338408316626579345707567981028006568747619015807088576948951469852219385041334895298633260796214042764
+4365061209195177145333592267894941789748549729388820653503884365772532158665492262305741107905299439181875779535940222413616201
+7002692668339856374514202085788525299569973429859432424389034479629705876996023622182434169328690891870930429505413389490533136
+4295933444463189433951574721728951160043627069745406122977006157620687110134601604174649175489421916452229565760756130297102064
+1960368933597422050626608328849588309269037647433491188814133197810733941601294848194060829957660144812059760171213031036827489
+5163673581923411040228773859014781426438397455478270422462230943695383387244412044104565525899545629313341781559828594738866880
+9340062964014870509227099698887936675774112546104074153547361150335199188541340855227153532746778775047019132401967059701871242
+3486224254115155530038741441994666898680466167832566881940775772365423817200581937154559007068187829334117784945473428671685916
+6007443619236946702946484250753989318115938165448366527641686620981129998037010871500824063178061129082786722904909804168031283
+5077049104333703032159256335893142225775472800145797927383645074150506549583979834771372332786212436563421519736302401896553214
+9328253090460566002578048864828230612968529907510194421722878024618561333479693530779323192843841998003032594026649617397117033
+6902940885468724446328665796554679901999854957523032465138455983570952184108442966984143957137952183112915545991326476857170678
+1147940566264959316051371696041947904637481710293264721589819021588178200143221071704512368347198312678908673679523259812561827
+1664627873674389755627490418493705966611982979380988314739579220409030725477944088566536789756067951060713524593551031845158984
+3598081566704365022254984411009080907751257030857437625615151390400729972784657938585703465777027605245686537246903748184890274
+3743523412032108137414706768919475408652123860125336712812291505493576913938367683595349130153523703056997225766687176144402340
+0831940301479210349558229457276992358900461281585291044594812536347699257011182959431429011534075284989504481274394019519138849
+5294182590907051056305209676408046536522421503936187377406071503791132907536141109384530248717758304915645762984125835020638228
+2925263782209751558565689180869492270244285946019041108330056058905348740666223484108200048676063426609063511425234359377856803
+5066811579460770402822516077692569897555102184861090248580603480179709451447581598869819018321983813091599472628576647298283510
+6074763977940235151776420120127969582510026900568916108091774893522283047922950769687105424389690185426520673414305707753060144
+1829809239775426957360751626081187328513913192137296926783947378382044283754109795780048763911203026361961183033933012273700578
+6256148707335785289325167505290076615535370263567053348838880542975561767345020465640090418173271179915907484593965695502745441
+2416400711412329501943051474827325196149637971289654356289167838113336024091716837472756809029018726324544210527893716549434408
+2077670900805210878733285491095692143052856294682669529394939361462198474814099442765549871744436963471806447226559851872954947
+9082929602325709346337243734095265641562540772131425161193766826203999287761238275537747088073534676484013517045928815906520421
+5721840157618684926859754448303249283214882375060250302441861554867804071849460117284782240184817225436567120551507130457965054
+3640323862784940017360312940091490694469989530945043763136591022334344797040629558445856236949010602808244365211211804494530091
+6701192226260174575156745632984043284760428280836716963199179332091776863302070789290228857289693019520852953529236479717683160
+7117865720410815041230240613271283107726446255341876904224653305719269008887983911844926604802435682901331270611392890319564523
+6692783449614566649026808017316150504276465383033625466313163064737973819404507236614011588134611220037079763294452798973884759
+0914820111491787540225084826895277018554164459289529667607470230351077932208310255555375301186238522549530796497320559115264320
+5836662613656654780353360816866098001238641884282152191319830259179620144977780872729828947449487560906147944637380292807461055
+6561572680280173994959056296932010485999239763428796091258639640337313710982242786240160248574519338042692530967139936885572234
+2825509566854748807330632140109077953768464116764873006974740017020211637781546586566316927017884251448954820201170637677959988
+0832497323156260043765386414739221132824464852853436205409279663532624738981652928962852787063322728977472723705113895939816648
+3887836720640005567311856937351200913471468555895780989932698604802967755682558413334239668009044766569135994431992317817193615
+9488541867758126379374062288207207762501971013768400508156207999323493728384215408284344930017408986904527951285518045057193770
+1193456086093196883061110691053041347131507623254475732487481683124957212918787096719880296652189465479161772651216902388161935
+9023602670135872848924155417498176225830627494225163432154996996459879170929691453342113731711303819248475466023815067381174572
+2080493294756115922317931111866355542145263306791051695700043555158422272380979294286809277064163627702612725392431921737967789
+5506584820111354803017904304944193794950330337626863953844116710622843699200721933361001889997152111163384731679702997569228667
+4453953407265344555661480951607569587119336749659238396970668832430048807500071385571032957421002113212240607304287845329689873
+9400568404300352678168177542306869394633571699501805048687025644577243527012594817839631515308187464636399822139186673563109194
+0383996386779379889997394025888104236940479474160100383602505977089098334042031033748699121508022116963448387393566265472288965
+0847531693445140037287515174964594859379085364324835476807557964238229721804605800683718605401718393447954937423707976551995646
+8901279644569224520056558762822223149315014455057454435980383798016264269841766056870811144787284148299586773970705052525539895
+0256120889703056267161520334600912740468642740690884187820554569479971860126461193414499951106260376564440623032634236822171234
+9700910582776001785061958742334821043319568168457980526939228569330951842352229610659307009566518307187068255993195333178816924
+8084009439471986482548298108494644279210299285939700414080731141355145274821687079465639330167799278714667429384500519830074150
+7502762255088959326392982513450122047410180131292434743496089993750128169949631240918611287380175422097126458912263961350683605
+9825024574318602570230904976205086057242856859840660113304499069379218541308171998260227484149937812807157987838492362751492073
+5236013621279011602439272005713397632062733928777510296548649421999353087528124960783236699168282936749555076309059950538448044
+6316174264399599155501461815935271957641181470379962431535756895151732821144407472754664303419949275610161730902538833181412620
+4057262138394989003315257406621046570918156102356055537411042166653273066886196141130782850554134831168704085162214611295749827
+1728494807516097505065593608124398864640297391491113562997206711322054216710834884111534067711304959653237337706486015754839628
+5402941401919360128506367871554679221289967323748328989926516006333132440966780154068277893259475878724270654107817685397502294
+5331749302510962305291613004333202326722920832094875206002590142911609625146433305314091631233538797653208605364527924132244946
+6532771118816432093996083328883576769019322364788699903259151365484388584381218032915424365355589731770063912720956702509258388
+3882789530639893098899335537330679624810372563783381211488557543067129370526059579061942074775015254040779746533167078485769900
+3805020437690986060459807837031266916198079638277454221416718947378635541609908151334933790442634344916435987118766221380030868
+1492873283652410067454455812350782971829174602968575413579966330593167559586103530053302924740897504468176712345572924410751989
+1402681422012394852214397745855323854981769611609240399129690457712558487768725787104039715649959552365787249656873757201153712
+7034615208236270834171130441362610841044504351389336191409989539270321328989800821619371048375553928712514470949748975085093770
+4290878195796201049040671016672715493368576254144716365945552067883559930088219118750514982822693100430367769784775351909372687
+4911033872681823931983855759969195568792322301570737362071175550474999508803728901587248248809147697357896852570255543589500900
+1706971004869558605860088419347382200967993695904618287963224847080176675951145483137675636512072408162582506993137174472960694
+5573663486380813348973168761749599259962367833751791115712074445847171992391927789752756447549332777671869328971664763925290830
+3549115232652328982096333522858191070453865857146234126898896140406643330756492575988127393599824952457257137615690188707592890
+1525981890012719417710592274397314151142262744434946961995671692595224961001445969622314797497698000523423663899015096913051877
+5058249696800337974138653960205886721218275906496709288754537792787671454609339328245451684579097878838116584542322616579053187
+8462720851869420776547815997374420654356793047547706068426425982466357700923014078111329124212863212450480733486009748682342594
+8687099289779458763026259506520765785275805315714163404563447144528065795533004752634001703743154416316364697795177031670571395
+7862389886797621228571167458335190181377137309906389411269247283889070732381228453233824760431622453252798014077600435024553202
+9884611862481302466807813924732912660462964877829202613446787892509006450191623119538981968974508042576824347741032177030382425
+3275371888164672951716608075300420614160898739974183834737152799222716640347298255880801705875381815950138367820787575063612645
+9756093031018363423853254508819810837905492342390007409090686184553436757595124339753724654015162734521998021981012802729263275
+3427616385168365599989752741868814273183927471411894804297652680678085002922251517971806076560284843234235639397961184180625624
+1126099034992853577542894567722591646934072315106827450408752081909824273574814734547622072209980280969251694858199479989346866
+8324744163428589301098203537736106384602289116499145216551769186060030444438336222899526023763743834415207190662514180019708518
+9860319477002084962218177584666884101089885263708103715532250072465740590415811526551340778700948662719303811079801949032990730
+9442895797928578191430950680716135775881506952099465712614129706777971670822951940768332168877767587109595551931372470789023062
+9676406861977772053008009279919036888396717196766804819265649832410502497794545528956267262992497398344695416980354321065043902
+3430450368036376703613028439245508507778168871582511449294099014869582746432398446542812126358198966694091267937409209466063739
+3928978146389085853115437005111689057451518521401216175319263947818787743509560003599577334399518674836615112723186476720359894
+4447676769726440097553180938842032872197723469668279942479093598413513198335476789357764400869873866217837103053672831807359964
+9438439139166494727711797686854076602382501450775000543946895474100528401256910882752544466058353451178988269998012104071279388
+6796506900519353467866660536525382267232333410870940350598284296015115345501330091034294987205096937204489666809908368374224287
+2156069024262468587697645236488193119228612123037868983120993219205723939445417381491095019098927648926035392978843470867760614
+7821524721406495642677263766762922840188657758664683038649201210659149304382137313140079079190066786903508941027377579459577045
+2846438208088991099137843881611431007996513901288343001595074297103385844197112994321057890476648269334831505632974358825733750
+1231729513446989718094794150861322831069880594276720936717092445853573977523050237490193119260788535329095088882720971495287598
+6552792304258966749461747651069123750999083956204720301600561922121624443601785058830034234673249878353748610370038504030736047
+4350618220429461920496227812205841572163867546971596032105207072905191109123570652010474485250661135080242831754570708916683989
+3648963905128198988374985403745574043149005801382728738825016196793544318399117519577715497903566248991289200713376389062963733
+9079224255192675318799042558252967439629275533715026478752109034505102371733784051667760885774671501306079109448761994271014212
+1512159183483513720286072997122368280567403105173759926916954869853277451339001028186617037332009159449259382498277868408842981
+5560323178755830694146107056035341050323807669577457330458808700666012312546070466530820114714620579338594279601664840585122075
+1503852393417110615057020185323349829356846940778480270527833679702648854699330937650632301666517518142397830288536621388668145
+3710500442232649775196536006291799614616427004022039024161898799546077671371127704078583325133930080437162856065176543455363091
+9667028302235222877392627005222715604718844825560371250888081705125248380997161235203510947690674677658525524540413177350345055
+1651124581699981562124791312861972388295643691956825406823017359302629847041679857625842731954319702741028762561310737659882575
+7234973146912955319568057648697281752581304980681832088301794847222733894976160526360976917273669474157112988773823160903919773
+7236452528456462658486826400719408745377253190375111579049732814880300278553197889206203166333133501206064778109147665779882391
+7682375338032730875672864027350071637472437979382544031201751667224513438710165103834022186623616196654886225240056588996350179
+0853897451837131243025169955161135908558413022976148659863288496875873894764829106676107357256982339087954980489000376844916919
+8360603574420141848805577433559168689130304284043047944444385048148193572183817853604188280975779635124804366554607129505815592
+5620546941760373757081442569363535705009166704002199788324439031196454334794954999272772623824166956059123197810751221134756232
+8439866566091270892187388961159863817415914847036125600694319372852752155914048990490541073567566380258061226260248539927574844
+3029318850407273236073024405659942071591211229297986931569472429177060698779317028894343293006454758184946754805713329630249820
+2687678405796666588388227397973494711846620655765600330508932225839545844068520955016865194693435829894249625192750034081363961
+0826642719445444861688478619229100303043863369218122546764063288271554588608667295145429271395132923307142550915748046259216532
+0468573883399305338589054269280928735368128284996899601120318736730996079626128417354949909634397399033464297120851931573621836
+3410567460401768661525344506338831729399382001213762232285178082217011433200810491330007874531405259479829710109345021089321397
+4652171379208756546308171186440327278368902304830062446989533198226580273246735128676055302820200408293662986737676930578153746
+2150739333645551554065559172680067798805779396460259578671413082802669062176930977818789038399646027209326563780688854879437364
+5947149323195596075203471654735880096964253215673415065855952449622950653788545812330777657299303345667765138612882163698466977
+2308935140239438613941108953213493640813697893782475635075053824082277617694735156671731366529539638010664196515846143425205110
+8579861845970706058547725114635120976593327222009873742050798971923964666256857891243866172081317410728590091574945331275284201
+6824605749924142731964725200957618055202505975317938345133949930752079669713432776367891693447902213677009365812998801001720273
+9233059182009261025428591058709759978362385968915457411652886788541048883340218037203772730667179361924214082717915090369829831
+2313518106392278036401430877932921941234750269539064717318812526416633477902124303231275087598527988161235948020286385526463743
+3838476810771838510370563675061364260967203242139687527568417240328961372800287193798489828795160993501686735937478711295496291
+1519858055532723186083206022574209495517859134830555261865370844903580200999194798031588523243896559267197627522165919682799739
+9373974604821907639636032716761671130085088834596447375314712571767917652624045445822422980937123575808022402072804691330745798
+1179538903767384713618264919378659303577920743409425206952169277638505227558099310711226481165660388253070855325241107221381882
+1789290788643749161623308260296145948321831584631161915478987224126348775962249568727630631570400533850489485693171250304745466
+6433974998050768158826396562741859990471614366251286876757878787725794466582791436968613297526831824776182286993388108679611273
+6110623308937612049537824555231489221014173246666865428966654501963681680683054782880195354576356714786682961340119163196471017
+7065396261977852039518801715732959486507529242741135438482938793950709913003256496248997903954928882444470989824659787821204683
+9252764834270969572461432198412629509667322770306467304657216423067070489844755342237360066917220335677138645076622463524222641
+2863822477918798068216749348395676325852006154849615936810666235080045937062299799315963185719888255745874252084645488043646414
+7004033498629565919058730350299817723186869899372617107591275993421694639356397475575742082851089041949288607800654160534708316
+4190299271083535674187523239133194914262331993315335908926599556351517813335151871562105201268635100775530492262605262924734429
+9412474523205479108160235037378746252342301320435142535429384588026050874475919119800213524490595720796240406073642925771858154
+2913084106745765525951041794109785827673640207212541754087108553407118981892598453634040675583256537303820724542193091642590800
+6534476025728340988278166932729090239881218889572681282009000341783806869952125287383734393447529192404697677486779298438469322
+2829214412991708861478313576349293840205174852775802339069812401323737815710652651384534932732051408295532745074816386764349267
+7099631393624915897100017625766879968866232677413779562258136847735611193368355358377164844416154018729080207420593111993431521
+9679117084184583456113996444214687961259734088670459741393316532022602071869803421115792325270648228861169427886111180946003583
+9793622141632553469977231970499144123659775068372909299552862631976151882730222347477076919808461706462627308819362671717147651
+8286017842303147776294340423265613507963077365773181170674484922475010476392279295555883161702991597407378465228254838715678283
+7139981166981912432328248939664037584747665029041762831645786266577343138070260044935844528507385472563673503510303215480074901
+6952789894317576895242795097137355300336216988450939924501915977563360873810170551299455217264567889345472118057178061331257728
+1694193485067381935776175208128377412895577843695434073687471815717642677045054952476930977756497488385115713913555764776948263
+2231234433522295956531798985522781927112508008839457523109337600193193052076325806292222155384767900607744680674492935529295805
+7875818939048046279625548208487559794494231792862975497567734812838016356460114239167085114060525364762528245992233228644094327
+5021327908105698731349894818836329218148701613108177279681910593746940136925470307141167410364253643713010143547929247739518061
+9070977175221547245640857484222877237472955055880739878012461158071643167060432840330043982130511367475881160956788509827952621
+3413847694252380420294340031416724229995257917239755969134460592475590887547733435481300484633477930736275363875263891668995643
+6581430213176248276716948697514387283511867935196454364984608140452221982505162813367283133818168866214263555481101556955727420
+0078360325719735185976311476426092189177189796469613813653608015870137963763116020948507804890688620493269983909621885486957143
+5618073667256477516793467657312199638612399475873899685969826531992817695372605952175192740133201709617218497592077143464993595
+9686528263740598514413702973825670801929614448327903726180967797157579946183718568106283503561970266617924646393019216381949796
+7239480687825534075396618625255444191589146664116441837547061247242846107878949219756732241373337771333630723471570758001480280
+2126415066562760335451168640052256439621013367706107505889219639609857343988288214828754545448713238798703235273922756046005812
+0281498418252644767093639973704165385252675952065796869316299823450944375075913221341612192647317518382010547568017829174497579
+1057968057525848488438423398887379257534282986505898261044295544509349907137424691109525427205047296410961152317113953498675027
+8037990675600906293845109738467043233236225877257801109348395466430705164075214123065322814006154190811607337254708305938085250
+7210750787555252394437778367913891376849871377061775971887348544361550409572803722815881181222850658661431069707417398802536368
+3948215469610248733031315237243553696794016591253408216711885250561262516305255457076505242344244633141474145222490778655694723
+6617637025342831507631846476937783337058482960397621355078541340935495458638237325584632545957068938913331687735591931648307374
+8523372206558862816505119548118888594916440410353297374883874035661877591624592793870237386066600870369847319996357899821848884
+2706665246531670922861049993051412169291896643639078882262700663889473964251112689202969447822598990637782956377227324903867608
+4848299459820567898610921948177867341511272056149848749209193175952272681698383112955078617288403697439760095671946801857673079
+1356542472568516852079785586485413072353853487441642185000260635680413178133480855130718255056119475830508178140915142512386038
+6695877448601376560251771173382757011161242171039619918232438391997384640483554361477105518555170292200647684746099630559477876
+3728050473071484393708670159181207753885192509059591605951929761162380613874243004953769191772521075466929499282741107419333117
+7606734018487546777450475520310398974869459655169606480072758933265326533542081878074199816338268783853568241202511239916973258
+1633835831994903654810299535109070687398984404650301845605445387393310102422388713024846802629758902868815270339924811537344859
+8928571046801342106880818013492293682607259787490363620233716285093685649713330924728743681650501355104561967670012038426873625
+9125730098479474089046067867529096250921613432172766348896492595710398358975815806788579245423344223729093128465048555061302778
+3282236766431701005576011421891586267683372954054171332350103840612998244535378427127331925639537865313201470923709392166490250
+0060953065190643840375181038485605085116833098863859869877736596835368776079089936760138916464834786551291455693169964704950417
+7199761056487159527818318808980388404160177710661891595418127883387542011797165555082211982772990941128288012248134317959535274
+3151702008500412396300814816932022272142827209737059555958537947102106965289850740478085447869942031637107833939492398930644696
+5466978918720768258413199259613003866496795654264247159666752558539556973496507886748391341566752558990139978324598436936793928
+7875629494705039695595741518975797423129800053333398650746169290789301147238968164288511049704954808998463415048261417058627843
+3675014761845381637345570687526385375856012330298649384510964329070850231207976330807099687112778366295062201878036276787748707
+4186642715813159153197640948334883431130155154184492235081536887094317988019087470651733545171824399201735161775652002448517265
+4661100517204949080442753518341612732523752379970048081237708561434446413436675964518402865361477156495973338379138615279891674
+3104047228288563492721376497746751756302186258285396146017997376211045579689813619459200950120798719227167890408329425880640799
+8361120737152440781721610389840480574105404073477545436637229579684528270718993412816918987324414005130598864358095704485655816
+2635022304411690520549036888248912012839104866750669849182202670549996591599148236127250813538958602763034624939004690945598644
+7161693686069093177957527866565203934639363610988615731752113714098234889877144865056494208717095238090181742851725619039913679
+7926731919437873880030756176008264549114452715998481120029937345677673326677605995613852123446385084312717926880869469763207023
+2138495852046091769881664603146562927499752742224823433380060312750362684368906102817542844818392822621059272739767561472497448
+3487585927757204836571198808541456058695288628326581580540815649602826692062251298954681717253220499784757374087955966951533070
+4467286406109149470022526422047665420981641926169730080064026643952810388751979407214952628713107539097869076094466606508205808
+0329251645328585224993793572099403208481085245076448698022757086335438075955415420248533451214205820043135499362946801092902796
+0976117055234786919615481110380099853162437989837673156044051970682580784609511428623279845514623277521398030431160849037450740
+8697358783561542570626868871304762629606530282055602229180460161462702998318108546783149370269213126706148977779508293460733304
+5685401232626893164468498498310349947377219975132662081047738432680920912627837266028376099158214591714411685177672935669560017
+1991014855525662209159171891334726717439346791115150429082237201563017187579488089876803702248258879215762021955798945536843228
+3358779497231258973228903279307787602968091467986183211284685640196892409994105852728310998830904989480714242762651865855421586
+5348281152141939663360571564939207399533427205490276937846050282692131755481373457167966144301656498283646918663467663563230116
+0442219576879355438661813222738756969322895770177941048443578213219939881424295242319200710244313116242014329915750902609753298
+6880215129386746871145799105266743824027120004725079746962555401718867449525806260178086747751584880447035314395435465651034570
+5590819486053989106201536213480377379276227468376756122798396628016810991489235173054754920663273388709967201645610835786499004
+9939124283008389379680409146709896607754411605235108861950292912142332714272148567105156028757875660670111321491114463297009230
+2097548826892083113543893580713808393001576983724545670281722041343097928800752617116438879952016563025042978404320211936405203
+6082731184886898638758782020161455765775544117220425974704422223842521161418889571069655363278462600259872240060382048674290190
+2889620681353481574769346958935531281292735580442822115141047535414968598234054161580569343948696497621906027825367798221210232
+0975609392326975398368477771498401808897612300017559800926232766502316691201583773217274029458304062931758320244725915302928993
+2656060793106179140097207671393073878144623719159743370358884637219392258120064605880204498430784571518779561821815030688040645
+5261532754299991261842655852754335348627643855237017342819255089240352732014055394202970458645445920979909498339363437891353307
+2437642062562451324051185886722830951326647012880268770841964036842838215823451274151497274115272960818748924818830295293023164
+6427726746699539771500247174272715628837777269348318525014112099038948379809971189523179740600410427829712055609005231760641337
+2123549160662241455227582001148252334968910254759170985955722387116765936697038502260200822286774138322324033501219326909463806
+0821193700130194457116090490985590394866182284594574006494500813138155877966705322490599457628280712279954157952750704655060385
+3280391474844631197279842080980749627555722515522776772617462578270115902754706089142103829738218939451926197117850790818482759
+1294311329582945102206118794968530880988413255047180804846373165792608079444603588122636074961065406623564621335429415769062656
+8977139076449153307860216027207885939587708357239425724499000050811065643249463642868728678159848609219920477201880783130814232
+6033248813331250043643381559597258568598550852601730339407737331740193572873459479638405202147132462334764720678461849283231967
+5244706826495860145056785602766589976181173320167438082817365766859974115630195914700440671364272919565408159761417527099133015
+5244648245024168084347025892989203801674105350823195087890804798433093162301085522657402786073312465657131861678950736152896502
+7020998265858326008838932594312667517103689364315007929663379806725932670838335332530002316590322181497959301133051038639381171
+3173858772156448895864459261457987925785493055610741437909826143835126197998316368571824712159171580331713288750535891179500215
+2461289349520625956975133669730507522155477555105599302736241191876700580974296813158063100071375109901417730679844357856593047
+7673877787687493268983420698315905381260558449663590054448103444553449366277579160597491777336624754840213430260072450113764481
+2114017564926717940676432504294232477129802350412122813350795229854770687737407776153546967564248142801354985562159014016660409
+7639567903574424627121988012936196690968952173335045547572877439937623104537739475753166073603089257419976655666993295754279243
+5512010810515840583007802011584440810442039388430026796415104195890917308156926213851922793907826473532250186114497099571038088
+1090443322487112398586196562777035714693242567109619766467418285811180453954969091778067062185341924208029182725946749209676264
+9663462321929487207790152045012463956298339314526151434668136673612071349597053270833334450801647517402244793354108502290993012
+7465047517200443480317342789716535487720038254767800382013521445375492608318405493546080410946096145404154482214436078102318897
+3241343339884810074493047134584332154632775327907375423171218727031001503885369275032870180181698599353279959939076928392091092
+3566208126745756363429701058439360596278930537654250601183842796400352091131220495755538686838579076983412474092980588063067246
+4135280622573899686743659033428766204732217042537180031329938266218979406566474637509065330050474399644477629470645922989131608
+7243489726801527985565622807882110752891684081535249425920277363697188485817835521822988850811873532635201983418016593214492469
+8143017528502801938786431108109170005870927726570176129291655180782741998755590156671788445329312481442984040900285747284336895
+5565100360014106030272353666080827357535103165363399802552515662750922553611500390854921288593734087100792149327574407938377815
+4240318921296779247997230590857031671134516419731819431863267883435154179769593315054293181367248263035923946261410558920492931
+3065344926131172598974832603770803242453631170305261893085619634353617662701712503317939637731383890741691116709803904180847998
+9640635307154881695674450558215122808610162087865073261126743708282066313632270460083280371892143332906784831299555537946109939
+0645039315913940793949968013785570770789031780794104310782057130859521600859343415595288573910289771410236190253921849657190998
+2817116940059523621717397073394274259776453515913607417038665482821641102656240840561075406926383495205691566077252073640483438
+6876828215210014803339974347992473188369840859181281062746399956666218336920552262054357048613213862945863515439475503711072752
+1206178405392180823761458212656703549891855527651389518191357531805984535259972031066177734136716154598488260571189715523538978
+4990265766954047391630449528696946350646833442858182431131915610086870866589089866607870181211091256487223226710174280311854030
+6161821498017905298626518871081902325899313379230902725132275803649959728622670760552023317532682229232464170889758455581169141
+2416184842590677978922625659052895162548385411298782741233394356631320019382233371212037232115448059660819419247622831630454503
+8975030577721689746153882576268854827896373568358085985637110827886139292888578025729952622899410488518168089967179203288999038
+0077221628423351964468120440528719933928163566191359047160562478933063353123985611799118577768774930246047770557959247998776831
+1721135782157358288734205102478591394569267133297228431858377971925993589071779657700502192679741782178657102555324869244446359
+7869917278483084269980405860197759252589350638010408763257025389708116328761797581159680452123249311643134587279719495772936617
+8130672462738712860454774853313086658312258840823449860002088944658955778609509469061098214154416089413962879973327200377762688
+8704019840879290058261002736123709853095591291334597972059260229183193853550672628813904508834589255323455601476677738648315934
+3234707347670711573887321944356094703845291499731243740116195333742959154260950396149564697796845304852992191344817095433298019
+4556001053283765367945967785584518418747873282740299536406596053579536242035383267115157980628785476579854884310834210027387315
+3952399660098012461635956108592408478331533765191761940733106633178973207757390760027945616808844645166556348572120907508405281
+9620717181599113391181876705169833156639227504083941308593882555592005786644351550764764616222603704206370090556397818828816448
+1082150428965180471148236660642979232846204673076692680655912004876027643170213363695294926023526278443457817518033465638673749
+5350172689969152071949149368789531895369178652578561324968877842847433493285130074155790255799028895045897756190837543509860775
+8482306198938020753154634340975595193686061652677880586337892305604321362120530299145893988789835870281018804163394448979511499
+7488870885383052769468046156937025798795341295237597526911841052145121608390932943180983640617731865473642038426653712735002335
+9011612227214170561522052833657180847394409367216727282193072678838450183604374539578667642858779645471672950276478435834423943
+0042627888400396166577808028511674909710254329416152368725303977021338640330576476481308582201268866056584880471857573435293178
+9268879578435020158729300163317051184609265956929202720052876516659404370185319984314639348524347471621091689443144604058655054
+5852357719309697687694316961668030847489545691322959818739069805501234210837740692288860145679956618287254425865421435945272722
+7947183003454715593442541393266684657719476151125892217474788448864376694397034056195614730803146207684810002655419508268188406
+0212392708824827732017576889397138488570370042723523923833128481673477500325568912519958461261978143669880070457987816169424188
+1965090700335288348865794109082688653306331467742286624350702924857750689705564771477934006408695884251431946386364556639034176
+6475202723487206164676214732339055881658522754087991356304799053722702797567004357975452415295767243300651018833595864642447417
+4933751846153559955643592816488612142322342560545913045826692544542626150928640726729092043333739064265750508139974673275834713
+2427576527067163076789990338481516933446902541780767233056948866977560689363984682741766823172377515643032993191346658956321461
+7240324801931427740710853207105854320415521035336023346171992089619399728628105888007254180361185035803733126321368733856723085
+1503702321045090573654976317248889826950138261936742489712456263150062608622387827772363799121813242734818379753299053724286228
+5076095412377646585652542244868299631686826272014334350505998081702990345584728215380800687580035780236658004071510394469994071
+9933250676927268802066614172669848689165401909644815070604643321993975291059605403370117318954869373816750869659405704139511279
+1490487519262534395623800813247168885091994099496258142463552140723866858712657283749576144012562970919330051773400199590563572
+8265606609996094143464919138293434901647769730550988047626306005465014764814728223656959001378552960458572921902571777313119856
+0301901698751025073371353819870024706444286250847057963018585025053110220589734085318599463450687736352183212884401020231957087
+4456959908526601850236631528599915374848039675582388183944917813443948321814362879113998039695208714072018715891598727749400184
+7983572039054110543265312946188122716587941443406593149730482849110607363599698686119685785597056173835119438876589991354302327
+0157777305454082280716591110467065838967277498987788761274920512893356487762316080383017175970582934458813655903151031833258038
+6820568297362586686149767416323236376371752928724979488399337093603770184434877480032885947231535650930077949030676059598788698
+8108972963805156390445400882624903314064494634772981427763122632358977184343156109534055951999238879890515883719506599847044143
+5178486334616508289086769240536520705517396788807705586482419714104331671474772634945045486037353039747544411584344166691513962
+8343543694892040940224135766807400138072678909751563547074645700842179499138145819361180694589974178543789544801347334713872045
+9708545131525935820756667264787954116125739691093797584888706242100925330533736446977764101332858478855148268301440155677807429
+8363906279880507853775707450188819239306527160717217937065519073363784713378967477694756526571005707114651691767780955073859818
+5651083308096512159550753176200623584419958971162109603579598590262428369134046173758247656339396228143231420340091898293104843
+4302402395996304257050404831355580727247848379655438560342120245630874884033522016540414633929586663157231554069390318916865498
+2822530065271711681487170629161962249557718383135273443686990757846857063424817696146359531243469019949939521304535035359286967
+4074330918579124906980668220696463605660380759667033381676449310911291881680221895239419422515427861193964219305035700436309668
+3698935243696912496491762756802269973014707849066246048122302860046406677238810686973357352423777172732249145383686882436002629
+2170964033471347644711273905006241361125626168342597916481066003694402986372839549149179850327741026797871619199281396638967050
+3740578777458341247832731137954141104761544067127564384269992513879476807275980026551471675919580563967451050762083496336212971
+7234069436162575416758566662736313504628826119312240011212647893254386199394411434394192850902621006968244175625150393585420756
+0819505443586556219267270131584242241933754418772049304646166400049758424842433111724173775260453475529050201556290830854251309
+8694504279853225298817987700209881068598742151871017058490633074185456825579641586256200310473031416146096103034054724162968499
+1678422417003132262043356103744836118876129032014712571839148276942048121918851516621273265839886300177612597618998212159348375
+2526979362189085413641977979132635792430656327264789820332281372901762624494315668746921549021511066663733746233883697857770994
+0998995661761657851385372991367035240872501467476816162857262794643509591735415040438155899974797001865973911239317650890930815
+0189734426599237495702149267240934080052773268635893422129378135841786547348314154856133018855495625125449892981908291205858083
+1077322089308800545276469380562276682750368988122928137210856581036772006900205486477908581832538965073059726766472615915649559
+7595664231420716081656297104542741477179939201745233207227457362234020070465865805626851389405073254933773440235630530654929440
+4561326689796974026193323140357607026602878702428514108628434286473624453127013395116455824218643518830181373377505009554553648
+5175104916514700448781338224183451234036582197678358641053766734457042147404203339056493172875783393464733980674769043154128903
+9625053130166787806916253108452498110678784874573415439254136465274322837153616892957540974054903367967131773174510386204520192
+4708907023698793329968287054491892003035884220479471761449794976142360667172403302792534515419470234070842851218805657152102504
+5165815294615880424810698811972894519218327570376404414484865603951627216319921021460205245622341179697179353800333764741713858
+3375832459808523959735342163302977206974789134934574309888193442489681770595931407566150654834927560855722717629843449379732533
+0696873250701946777504053721122628669489758761941472800177248115996803185013999823071443413470671100299081264402635064626229095
+8025269049201568533557667082941257090329107268081485134499591411578665111542402290969079825247733361568938034890137999482482426
+8413571137578802277713985161717245739847221863546744280234586017009016274669615970285654793200770322063367655004275873714400764
+0799707402410991916198286689965775278824664119744877317308731118045964149958722032731308079677323234905411311426216785693702443
+4397846375057495792019955808977919911307473873070308655227892822037825751568866737076516050806909779275729314309462325310751161
+5878515311252357335941687228452716020488777361851148660668041257248641752627888839374533734775241618706657533250097255962909759
+7924103963089477116974416014956752830485444377913838660792557425488769129517146048639663168698011387132583363962130759916380103
+8854627858331158799334753893263279859800213644437374816465531701511843970386899153300191498875238863924442400115037208900760391
+6931077305054934679510399257137017692212293765671016977117885559987800112104522229358688690556795828786584220491722127422607686
+1161689224772384204986305992766453244735906304538266466175104130240871760142886069723737054629941552777930420547825827115890782
+1184882323411827620265622192040661772065557335415769691870166844416649885380327832148533301202237904520864333379649271453239928
+2427936123038564183450762355240415926776086706660362490151633725587501086167861442974904906015877742003232322938651897499721504
+7575735828907721001810713381085000197583517056663976862531026160720187808215284714716227545242555746984605470134836970810868686
+7690274030579086519662066594780770842382679015250578750543674207604336237491570959207826549369435808803521562398005006071237827
+1591235570232351829740515082573934645171861807176059621044839781347865804129548447089911918892970375115928184446756254541226685
+2615960213766977626603096139489045595459731295282305420627566186367919926990597793979775395219871115824222384407322704217828184
+7269890378837649922156673232477845852726935996940584696490442582150880559450498906939124023442999694271016368614887466665480687
+2492299648986452580995323839604907135499552296977074591849011346778726414701224990442027943081442825619102646860492552917507521
+1791849743502515995886083914654782544108637930226038487802556564179211481768559160141129157276978288393204371047755590042629364
+2476979194376897909780308753936290021359131405027064825271771828980164040364357335094434041723555965477129434483174161190644661
+8416023154844136801169958073248822091441560069684654659045233353502161929981208692256561137140555110119558013208216615513472071
+8088260724856516409808086622373800856820389920242427841076949364650960501816473316120878023138924750918248626057879988336142195
+8686116426096280530843620941389111299655341997827197141570086674404151699053951971920289530070752071000490045958486626799786432
+6549357623845124371617655875408646869879278421775346320373177073222854384021377119568271293703313232299103659136776571632693838
+6591886804108118051730248844194375009874244915537509136047158661056246282742880964703031154340229700891206754898355101039366979
+7268446901106376070498745112524561027602391892725887518917435705098580461006376837385629028194839014124169131891549609455012171
+2285131899533028794555938374512548939747904214953588004250694538667660139983891321230034509152717542342156366790660293952707870
+7433656872059365457021513060668191880971221287545847083471271690608548455879533083319220177538857519457319889888751900959653068
+9242848205306926609548172769597825608518368367889673409305233019839916718283755877093610440755381268416027885226989117854626319
+8543014996495123544046729990961256012932771211075541381188839964005105738775284593953696325073738652709607173130510895811417458
+1100281056074250163495442070917233405800039282178047058927490789657980634481405379098411400723381012395226453993698124096414583
+1497707784106353163476884094382224594079935684207379351580860836917141337699813295106036949622008098195962892923132082743352822
+0227639803444432864090266134712772762851750164363159986164200332551145986599690734005702172852457747000704439537884708919681464
+3297805927942628853699179019515733067501114704121488080361171310117107236329567894778609250864163044875868270159183178936230020
+5632160100910553597455671868785895773407892040726468337688933116567628214043646404787040937392191211462332257825317687874338725
+2296104873433207092085115555734422123208784998029195153841807872132818719198275132977492788603520666575735728468601968901331765
+8507664661851267844375807200747151263758160914796423476220162799279781135476440706809418288627923653896822426541736985486808537
+8804577755163112469882477676592666556395113447285604375941404675578061757730014398552781158003833295830499727417346600077947853
+5831914326747916706642066586312780276779650520761789440673709492335505292573240738337240722730985752273930258542997960743098240
+0068020053146252182779250786628431011150801984991349353593228652822215156799328870412166924618702218796377703357100331644399678
+8109188902158713215146842638263856459757440491023323555585167449490157093903282451159411558188534514053282926080246371635200972
+1083689238510925211444565358062724034393858074119865447872227462830480815166007221130324188970568012551002420122076677588668537
+8348566408824119448641450955381151117598257925347235252204110951120532544649854733446808547885490496232547849386772180981787081
+4560676276145414580213909440734926632475864478909927595616312861612204269485671554044668485757818928586611911258131650112268582
+6442754729881254198230970045300311192828701003356370115227215491493010569367089158620723231028014912810350816540331381099940995
+2865041663295338237509904105995789610569727200605222728767332785967873952215814407401152907766797309671425581760149058652925760
+4017820912206849712695013871311183547029336150750415340954915312119753021914893470116876327839429907255892388374033828544982922
+6915440546354439943941953788638484102813214756761743923515532313884486004173505190595536349294404018810183152351908266279594331
+2928244470990795144278024903861617956853603900951440210459677120550845092043556188794480813102688176816346489991301120405759270
+1186435866287315352826686449165308561598819563912734578580650689933009781657638259105653726859937343022833693021987646952723005
+8712542566252718904406054272317438859093977264257379132707981296910101101713844533871886378161442772031073848272459192591830784
+1058110999534770164492882010801967465978671453250245066874219221865094533085057504007502380425647847612715483754244102708112443
+1742666667868535721098914454487184166505673192687612783065836658057498575235907333228055857705494275550823062941047285844371213
+4854496575428807093051119901176270909165842784911651361479733219811770760153017103816762799215219103460967340988812865617828044
+1917561105792307812885764646858740340976693913696981626941718101122829669609931847477816007131803415395929587982744622533841587
+9667546614449025826471505952967761841638682554759010436234535597997076544716136876213634826200883843816631177929989595634824997
+9075236896089146108414434690485647098336762127620316996183949539422311636347004018452729032082455756224021955521110115243171929
+7022352504520236787549133408418756692328586206498166126138700604093881377702931259764322041155662852059678496015745189492835117
+7091800587591451755394603236816915477651467511713772374848670866752841854518597403280700140135675063538245814642015579501650431
+3475133641567131461159293976535068676192194831897897611380261311134218099223461446586431446131415308645022873899564559364425282
+3789965382702942084656483383865958903699057640653956948168423022124988840895696969117651267238844593486453639829783832289036588
+1651772364049655351227109534629863148340655489696054950189023140607819232747963074764923819690470465024081626771998338862194589
+8535421442026745607190566634422441543153174467912420591988970152959270609189415618141521453452531554132027545470737271909694248
+4266576066028018898848004953928316732798903447774832407967130237423961865629656870579836679541833228863492849112635373253768730
+9318620813778397458907750295204099889575365028367626038475757355404525059311775107234951920852829456542067713455662881377001712
+9660563316063581065664074432670545816492979485719464785114250983280531864483884025594604925138921571079067953012249664289286107
+4733006686229685087965270923863015490601420365854224908680910247314401508516820945614321593880289181386292705522860502467700146
+9595467875394655716250868523623848001720836247002935008259127820208612390799061964695134992188932480652490964335096936081240148
+1812489955447149372964288932685703059456499125726325849419752698359991222537673326627718506868098338620828381688669635638529284
+2277365318750471576552640984213353147488350298228497735938404810800516562727031985237579073707417430708173600319624539956749453
+8558865515990107426689500711926656694092773040192992037548490908808858324669008603563963750417300374317505710614289622964156217
+2457409596680804630516887336784028949728779145781319560216200606134423822190318186800036885710141555957030479473061434184735920
+9100569805069607595713477651532945125488629510591455102444809609662844669593112401315706794492448332303051585825039449951564890
+2934068975480357331702373570405176114572488785747724819226534222897314789801301206100799457068445592290174980265109976510186964
+6974436264361115896790352170073260547419486352304459996628335808264941225228110927615548124284539746249063361590443246656233810
+2022987197590236256417410387584617910709314684989417286318087666015073752226802244527631727840148104686143554769788772100971964
+3931314203567669848668014170818609543271827823841957939988437792149776879965413983671414699512124596470803895106449229017252962
+1646897058572253319802460817369397398067528887800488520057974357980724071070615260303277654527720835652573050782049698374251316
+0612949136289175984348022991134845911118529208723293255584972808307452158666230105816460375784187988904522880654792018341929152
+6230320383294577758148209875436786980246088588555018398742402423700033755813061790265512976391765915810238317924960933176044915
+6724326703636717615730930803229989144709304487765743249773045992631205387565818549594275877262188712201760168274734486308418567
+9793449160017973876181891146468573134118620184336387033315592292444997748610681437980592831049932965491128002640896459624743912
+4292773888056347657265747923515456543197563688072118373801968694939175467616839381912904118459023550508906592936405878500629369
+0726575398511990054804247570050536297610421442312874646372000460857738421341575986454091454129764640046210072544927787587872609
+6223497359073574286258812426783136238045789247117981734256875260415121593723556039489844073919163685845325053278772517808357882
+4805353931456319684552807410713836603840908704132137938671395582768618313934438378980539779778185823334069713366782891327854771
+6127074671224214243978383308821083055917752075116334068237357481944923919216084154202678626979129283869929664457025576182992309
+9095642603811777857467738034071749226163187428061948529437320054852470403172207781014210493833697169288095448800181203251014035
+4736481344099852996408105951657679269262847981157582390462101509329835494113215114942443801348682136828613264161536188227115466
+4003055863718708771225642500990071025833297545571403747979992978828908605722348616364122656556369792934466258936918430294297508
+0884716108700884651920742851823456839844922966806960079344733214332219603718719129110850475334654765668025057309956984350345154
+4885236271502923816983822161323233481126598003985902081480145736364185121032980985643061033399360057443356862260970037248156868
+9095109506937315402103438551736664529148909771957666146775454439817301965157339466426336556934667643823128218330998524081566484
+9554172468178139926024925040064147501158211448170728837042601105476806693933691272219558658718966118313273471191896511638062325
+9954369358233682690458005171274421730241048095790588467590844502525588085948164312745806267036443692262270244497152879755376313
+8540761990884030057918282213961331175575293790886064372121411245265558611444044299259702033859938015653338871057063134186390567
+2937295853774855369815055903708691070046531641376115545763368983982874877046797588826386810643172084809422213611867667864377575
+7456129086242673800167308357557286842740029636829456648911252509981444991813390655015368895052836323823418477931875989888413494
+7619903401290202996353920197163165845104216512134977822317453208086977782938058360962563863616931222677006031494617743246676098
+8619837607929254793532399964916863199570819754247459608169557658376643077622610923724449371091028101105519894212018425361113161
+0198232737234871539712619394554173033293046636313472444724663228704935678432306609229598127499957898688691002287353410535746129
+9160344825935915883479808009630827527538308033068458669327511758149831271072074138691690968888119139014429832927001663077896093
+6075520157463461341098226057137016444093714810741234441217965271334334440753561468859945005901907007749818800609799068435785758
+0546092246435123497159753904346692263278071121042508101131684892541656872975812647089730436015791483195690674123772749878087282
+6758449872382291050831212201949792798424861556134983601310627614120558124555112900385099751123167702480059628861813816928572678
+2294380967592455168636104873737766456888729486890507823276579714836828251933669783531511408873018452811541618386657467835047578
+9771964953738092240932562360117185595020635073758269035209960005817272212266420970453644822258523689081214708732161974226486482
+2078896042427351080221479050978223463317038184395717248909464597626365437809427793625231151897894098417132582150723722131356816
+2733651127665461066112679225653017158187022844835577848138599970119201959393371465576981148627618500453766449113619920556794832
+3098796406035170187586479893078215549068777188615428168013041309627717475700524281634638706348659216956344427373631234955931788
+8266607652077744997152631910857696622624195835857414262086680438204284388121731692389911117940177851680318293050972437430080491
+5263662912508589659968304863826115756592152285582835871560573052117732379831943224939230850768149596127803763098910581308889239
+1399259544384714811458348148272122374447108528351486026748375991519038080289258112233626298579932128994892803010854830711867003
+0120562601270662181088525907457246972630366755109340652778459673777734310903812432648671068725042051752322546900077059823883777
+1071975377081858251465844724729282629412278512504579575631776161691808267150394386844729953211628319505799528227342615586982667
+5142190253907427483211782117002935160362621628506088192922092212154140185826659904555543974037176549370222198088358512119912742
+7709122677369521964052899819214134971313049580616225982506654419124826044743127724976092244678406630989264402052401911579629855
+5241083294500875288635504487164898666527862404520007162909767182104068330196614730977680503144106835763690135404371824827295654
+6210246422372066059297630639990103921525353988425004032130811899385175353438423745075299078297982811812894692845392714907314914
+6639687154171290857100923298064297354897427312066201467165805288117452112109293854180789331988821851079333157010919824197308857
+2725453575267288288994357675260613771455378866560128031996095809604727908410382843600101001039972876558637948184365207490031492
+3022829447684501701771651529957077694566855215179433255048106574130176149607854191690519660804326926806696105896923466573489014
+2276500150756721393101309310240889850130747890241895231090329328679796493201088708899083812272168509412763541079565359287160502
+0441480433094880222135017379174984153891031352882663477623197838966247123264644246447696041370087767283894667315757217159981846
+6600209627389381111032923919248323966625789375205223637463959729585017236548352912218466643214096190786355523902607233701011308
+0879209770503108176937425508560832114089876275039410069927508813642206128497418765988069857902212785710790868994707145334746457
+1573213691519886100372421851125709104684878670999887084420803400476797705625591520633797149282934213606570900108998582064311163
+8676807063736715112005822408555267407647050728641117839753641320386536310057649950460984214505375532528456592558681408856748600
+0458633214841398749014431880145127111888700604235741500367092065118505389545560189317863466505700948103428117858933891140917600
+5132202176401630576193346962510769965520088034746560321030328807272795203005246723655044384670879356197070618995577734499503916
+6506939563329550580672846170456665825955418030610189100857896112174782009029170826779986506077333681379230762539236049071683000
+6370393487113254502942284063528147627172601717639450424195980075047464787096908959060881173708540962987133431304917906118868338
+9267746888420071021500735075663336736361717345091433424161991124952838871022030399503645263408791327784786086730026429717318657
+1672147391408891002327479016767689503494648768717682253138108661180075426978036916352251329255918145397491166698770599594009604
+1973656522713866421729264353952482643307862403936073686775977710379738331755646451684387173747099995521827339722863619385237499
+5408235756969453434913224193378329404979503566466468217232986076880098924660185616188785089771941834979789440134998311199906069
+2232778818840350786605080110308895419763433233707234872571290509162878857914634432096414764357358087088039057924071148091731175
+6015400792410124384152213047000568844879712268022351230585299428537516602169557527154990684330404034064121063393300034030430905
+2306055374539312465651241264233074065955242079361211680462145344554747450796349210759636113482252702608031612245403353997125476
+3803253691034432130798363413192595243576410393487613462409388440991106589264853952016023685661448176427389232941666704057678369
+8628747721532797463638681268551173019525973277356279608142072485533442125834239673920151827309537064739870526314899247429664781
+9025827660968538606553886333865132013576294269585884802265251611104643759277860774328243246331432389944537967831541391858902940
+1930816587488360252688732499160213070813273038333861895643529140656993608246150830322861238139209540926180077253222099793719072
+8959519042048720068153629627140256241685908963439182993973204720950662335620899080859042503691987552467007737450276337233761755
+6288965328635383011799009079228464765004787324704548708119617161002013632986577780042057914052383556753286042031709306907755664
+9921350932285357024268612614215975988614776231803905241441720250462994526451363159473639866331342141233807338499617054943944238
+0578049360816576019800945237402222592171684814088734743903979539564400529178521960883785173251341874550331866956766247772470369
+6083904254700701911630159329372053705191987684688500636724033475465777760911461588784110437867357713431148790643538763108521995
+0296263770538400456769346062348737783795801732870097577376952964730500440617573963135158364912865598645263299913463769215039071
+9483488255991073328145731534454837990839423394416473517085030613349147333787972449423197209621559003595529788900553100012406747
+6566884594766054381929553636693829055015384572992260492476307544253448277903698366356427152189807274375674035466963843196695551
+6323074679661834194813723642658721376145252523971723277400835325217197190050897668239821693181091121061162219401288326146881306
+1808318984353930429816050257400279035517547964016766257303295002919848213345027516727642354899576468006486504355233740324100211
+0373421583654094261005790222006220690243740321608605292144463259644370384862300052723119124037021639917903672109294422220446746
+0968367458627898019517765631253210766036998155063276402536135475040822567588712196840514962484791203840216962030611173316284918
+6730753402413401318179055308056338575836289967262947906669540139949663260817034924092055901733213326920487904492973772740252118
+6813399504142772729322264698007839309738863435169195740088479397131114450638902610593694986422730992468798340242051077542153965
+9094257292692469011371694239749935666279240094911204646416349941755315640280190692332906803301138668428433338486284139761451437
+4927696735702519573953727266824755919361553550569177388087634691983381789617481807188380885676894329271297374663349552211867549
+6214976348118306656535007501010457882239285954427884872811741042673638154912694956412208130004776408704809831151781445974935728
+0120629582751291565009219505554682954747176012178127728953108970378564330824283571745236870527703343674549433801104649142185888
+3235814158776446629647585300745371840827518705724793256416163401064594247074494980560274282618040988687418212805930332830675213
+9481691238337366800610093527436128723725108303743340453678113695806808341554588638276662497395500403037304969340369996972707032
+4082676737625354210464419813293767706297361241754982481007296169725698649583516782177058747437891980516222464440989464874961596
+6461961406394849542189779035893533584829634128015156718397540384299215958366542622049511074988966488475073248255117221338638960
+0142933164629079463406544918744481398396204306933357431841214352733485790844296470933212820449310522157583393441447538375216436
+3436698506912676403242337919492000906428711269510381173399936468041047249569064777837314598565623718618433285256806067639636763
+8460415932660725184337524946121929924205499042071794021186039050613143778222559008526610557979170270365704047948250328090311884
+8815703597819948360630939744751577068004694199231149936335126538352407733636909351409964233765563167198074923729461436493523959
+0713926842635856417640343723268323797389202591360887205782568996458244122502082280450763638212538223700620622044815212320168684
+9492871418408066338755969200124883796242190267635257673723366249954282292979482645457308347074754036142876356477739278675875440
+2183538168589813954235091042917215997797441009968993171615399263341109892414323128649997905799043937988646881424204624530006049
+7733957096488341212048475007904035717627062565794383079540365496869348281433928986222996400495215587152772750589584231009322321
+6967167721546910451512704467642578730007590171739084668065616508498732163764275594573615283985791091469103384452900988352107000
+6807413612465354023458660940481659053886101973060578770973513038430471528121342377174140575232152423951725002933862875035962993
+5491625968951170241792359320698419197951622254963187269169519754789130928703155856710378168285319433421425146672702276206900357
+6582314544521282948303668171056488977803778991914594073284490075274341682398796202525053587573368003492350674264590216915743030
+0229180917308822559423399370500197589688253700875858499871606888817412759424516191276640847554118760685723541416666202243509736
+9274208984682823732942979222927492539292245964003720945726994325795924579380001664666341956208236538074900737136200088724900215
+5814292572624892701632682972030886871485930705868231267185916589385811869703139406294452824977282139608709779376891002163708313
+4033763100173660376690182575379995726083861081926510802579785312647154456013703372795547129639766049095465742696104516613357933
+2568315805640894925038031436747677782703800879694535494046794349191040639680313707242709239136167699797774023104845097743799234
+6763080953224487156488442945555613963349180931811315907436001825754710792409694328952798340996992622252003347436512459358128857
+3954533989335010638156841066648473526011867397359480295694595402042037502438174479721797977373598413288286342098814213128179837
+2396433612158432510452891115965816912823381888049756989510546093247222344511226918341455435352327199403241839439420506108676964
+0795850610161143815844607948060775881656537958435083754755508315612517655376939244238451149176008256028242905067513932423707050
+3517402986146524008574508829340726577308717530546869694363472906429850377209335971237767032862995433224020904386089476753728648
+7922151222682324169544546785791039508552110735905147311483313421452486749631056709157326288104257728264776617306059521303067262
+9433265821676424821718658733270406951796862690935463256100330389699577509374904038151899940074906081844482171701461900939078601
+6186077218855804555456232441080881439587655776678203701080218698681846807414980313213113823373021577317623820418853903404980853
+2057729858963790488672801591735476430626710017313638370400064539747700089967564851982820372204387613607305955240060602392589527
+0383881550897793438940267029950019121382581949345028853214775595378737481122241954444306274659828618843592228475107234699152687
+5284798962706326315885441962112759776606317588723708150855167126722288961236786090248841992912344949773249220873179712041971922
+9678187960541674562218790198419395947752158216709587927827286969325482868753908887434457039802709422399284864987575179916747347
+5327838914777072714692085263368643404584146218804037383216974773265161119155906542869845216416813947477024304569196702936579095
+6268003933265575972147374394617649572960257762413423428779104569461013465964897200866208582709538990234194911357542427621601938
+8074876525846270711334089333528645517621667077382560706349198812216415510664481057225472908752257947691952856523071940619013694
+8017368030459649790293701927587307177007662644838805113977690349437913275410750363651007980050566471766249753077608880102272532
+1982797159364965178888531580373430260986522031868350608333752657707407931000254944024943348168140524874484514493735113742249981
+6288538584949755098193652659249807271937205648283720864311553381239244146100739200355642491916783137202534161705603274089556521
+9354739749045138253043275273268328367815186805183694069007675806235940663397422177024952828447038786641822001541524569479714913
+7698528117160783953905420058390896481011235446749390616223922774275291430828661119528466868454607218473820114505896776059375354
+1619019266174818706077047840193129831420498197596777970098691437675408999864116292704117680089265101055969410774137278714249866
+3704870678985840970113166302795462489950063082099943547515245655672648446079824717316402600594084559028770660910436751665528235
+4429408197253611572221699160867353954702111945889329273311821911416970564822252007768702453855504730931208682912670990901446785
+5056501125351085290367349611566587022633517744283896529455313187439470673480194626772000636195743336806541403680260332379718964
+4062991551971333412504544251310884322830607074386974123640580284992839293238984564989258127209764459890435786526862148574118080
+2625522665812777011614768650094518338934467618573508691312860257788451631146950375887371627144471854275002143114396671788841878
+2226696461215179698643658067033045890658991544538880319431666117259518073995053382607108900045909290904771038098705696699068324
+6726532088338857549906950143621062126429461929145317128221035122460444306074528944822699784500814789341052158726046904507897034
+6793037164285887325166583356411787362893236497739544799385622176244058491240539097656877256235845151279052346581850041111149908
+4093573044381701004333825958081420923185855648955716595548583153752167241574306747073123301312447687906770815027018933422227596
+6707271839374572454938209957923490292030537274459728356418336773458317286912917431092307541994164910938497543069009665010432516
+7241600538166073336929364870095691302789706058064621204209320909673557421090888354529446748882788614331747011940455844576764284
+7137143302702161225320499515565654830535431434870632910006167776519433451398361978770695152191140156154509207190258738746324525
+7177837461622149136708945368215880972643302158259696018853584758017706472295497707280871705217770629770641478542481671610250773
+5554013978114456033660343221358867604345109625580200393288313536168463029481940254044728394046188030569648323861618169629477000
+8748988786120543881188413407361779739580428614335192009085939766971185616502526635854198592751325209395171686208426924544564152
+6617729010736669611153048037379873649289970538055287963581277014784710903080627770559078145423490012308690390159447385760636617
+1396112919025930755072794022535421762089970913319020087082933809741223660404657644541118861471741622430838236195432385726159361
+7249197652757615950334012535738132798576509936889286629270864681020298782574659494783085110319815705595177485744225974776618676
+4858557343521566530159783491610288461205535017137620369901510860776505101408698469561089138749268742702921025433191359814405089
+1405508073047405874902803040100792069570430571449445778558936794822787960786336616853548170322337310425822658832018643837559079
+7255075818431908394615699437073631405701119134607024097267578921840611418622682373870814723883284591259922905738590072345115516
+4240694967339735201081972989105259182809574142617805837465112261091318429255228721568810181664317538777929819157212160575829023
+2748237669200464565992816533713130419647283186413179673011963172187269272224647869974262327569585442612854368077691269344188871
+1222760335817459965853292578856201576938118519312855304508610105281112231513426234814422228921425942855517206703964421120719762
+5224765636718330925202872259803187360837016560225525039097597027027310508724003400835919326880989701929146674585353105826375662
+4608686356759945389820261327877835956104857982859971343770150256738677287345081654437248462809898624047205228119203349515135144
+6762635128848980939500701402251709503914581106728361156687648893186497005364492516596632908393739083848785619442884628144162198
+9408219837678921746467927680318487696309519621970987584546154535257273988915610716263345779849862915767049642549659017655936977
+2878461866210176159858735856155729710212544372367962529421415383498942572742627275020994117127943578105501057737118382232121164
+6202970140395425040275648643808519609153095822076099220917958127812733404125781257612941188098229102786208245263355552763155862
+3412899983063072356219645639174430993848691176774827540248823520470123385464397586328853608924297363157128484769714643392030260
+7516335187749776239975100738544129195651952155894618035351972235899711941435830137791970183095848641340212385537760526454996975
+9326117473414458915105300842976184452176417489508025383214692364884363250764059076859137855740438113389750789393201920849913143
+8213713819060950631004232834986002902474872793703875917119551478078092258435100422531909399249521481966638648761188280089875780
+4759150755939784604117474362263502288999681621525995527689733138120086197663894427404346527959682389904515329738583325486736756
+9325978425209872464237977527958499931962722888446298443732493719892549369851302316811008601401750818556435135705126450083049922
+6347121675883203194927076244218929133933870815129366063255106247006180593262999464959953693728515646161688550961478583928288648
+1770297585530292141472219789662846895032928913171250259285237148388628954759446094661658933173846573153793706711301693991850474
+0792606603197595851399011444059807607822829889531316870539398964731417122727677982590799094547174678976545309066723508642538395
+7542251187115005568283732133757451228935803355815247833157647444961116649664568241618566131440468159056245333148920222556848970
+1686590915600101341570938724862037843381611006851337958368672209742162426192678307570447318588843817286911928534762475716887889
+5985898442600265569905129276649109155018541224177922670883691334985077196371351903258301592600475229763499481236752268688794381
+9908334038229937596478744640386393429233365920050089472460888907538665294038594595567391991275514366380037563916695381509760722
+6697176988394487279550132960940875716670256744139528862226095599316038741474608986574869723524996958686407456560239747388319182
+5272345146409276991368562911742268892736319679968918454777104809692672080906197146972033144703725807051487037561295160467451538
+3361581138752178146561886363234614574825214993383047665369152075131490893168140965966229773832573946751662445845244243875117807
+8497747825333018837277204487016088859935993376161231128402571833027091271675038762646104326773996163504827534262519513030402352
+2850247104178367791237021165640248127529302018809122924281078393572312164207913339929888292707995450264033189457174311609184073
+8924909933371581642458243436549195910810805622486372258791244747556044533591204446068293714215938334798650520367000310196349472
+4508128384366452869820524778886955415968833938807781198993008689473057745756213279992800316467476453813822465284911857999907387
+2023953430847273884483235864052375615320236609720705596526699723117087569499174093607783752368506950667179330339328300764225536
+2114055767363508202672868934173997107264743852817603394956504753530153541861401139621693806395357957937922300502759889840467545
+0621018093521434841220357944235687355230152336239627344725027296978480489999738827553268628247847786834042126152054295485896741
+1728177905254640772617413047936979080771772313470023078251325162582234445493894126314939244900306139362255151328277418578396047
+1792422884816727055970087290849551106652457784152258102530082023142369893647618177451355631227247379577671860849853688299849551
+1175037347149672092098074310747361251964753674884333700769847744830036555394374700856740987145924794681060765600644641697283847
+9174589667717240975144336198616364140632445180996668524271118863864525314244946497799850056518633949293612226613509484575056441
+3024489420602308444377762407441001512681502589345978196662197798484057230208048085644756143263157845710447555275495197040972213
+5990095737215350840694710792788564049039561363466293476205766559255673678361573392948770517450420686662337759686497763541080151
+5536095650185550909008740808818202276021308469567387829730017248451381382214473271435330569988489076831395673641296020100168963
+8691489605876605176450990544960425812802030262532258796192840475047025803288315858498575542856190938582743335067317105863072855
+8766959566097551451268355313989562707945501704157509911384107284566676448181401117485715830603954518469086610851712800284373857
+2622452939630203014872224939693671859800249164641618680985148159351811785234412541320836473437263872332827932949209391274805175
+6798235720998149184680985250493187047397164050502295623889415695762080775856311836882958794525078302171514915009308220188324579
+7404140736104785086437030648484406734008243907361526117865122472043884228991384547907143497695706699559582484787176857952820522
+8804256451428134606481551907263647977538193140987930551038510575189609463453621867637464848455610801693723759700181203650436839
+2454914648531519297448584075603475998203868332048006750382533505496359960760723675619846780966293281981298326598027774066580197
+7995861529357273876737015678397822856184868318896981667361295506177063218216975663372922918478316465965515092121524544927046347
+7075516111646427841984461388320881450094372462158722036978724530408790912720869813138049436688811195541657354372228803333585071
+6429445107361977048898774220057765467210817429170612447918756002833100352538329968035564836996813252177717820091122268457886430
+7174078917945962391527335388096356842601813618444449251961003226992399982772853124625379285502923443657958530018722098893816397
+4966136548214340660067711135963960273659031432856630667889996071606345454141323196469871177597395097849304859547230071866679596
+3726141431238995322616590363658851982624885785492321657227849247981548495242247508727680411775990290110420891478204977360853532
+1644317907061571688813615690182418379232646792079005297020445585096706983621152261491067330546246215457831060764875633375743540
+0260037498619368766791619780583839981870124397870392302778118229013764892065306663721631976910781105530817819103416467777655922
+1257160865985307861172892171513923812618825522832093610372208245587343312911128848417617475098350804052464802003464019493811163
+3766028847159301257741274325560482246090419451830573366629957679849625493927009484554531296839025641820596875488169323390321224
+8232388226007759579919663974563407506786051531271638328419810743863932368666194478382016978871056258046863096095307264426924960
+4549834654287891305590680957281622094960361243150054432811463994295196664383435297694301203486327605844830810715344529812950660
+5753311902123482227347291010505867923405362170620911512612976729652957268599586765352146177919457594239032123428411979879139233
+1756522666058959488542110121660842887596621268641851969762507171503624064440144225359791257651455405971257235743672383114242117
+3669744927951794530124706132421697781115421405857509254735757547057701496218013526040546290811670945415111481766033696065077908
+3743986898663416455838782244658330408591406810811925113737418608085893951934341548820971030074613077943621026895167359064570606
+9471978412930979202834282673808363212715221979769900548835760002508328425519756934140019511728229374555172954389643589129389588
+9455543651731906114795743817911783078297338344457513508249293073101170733009370971042675747320086133963697038647918247059612888
+8987238012717473365026512535048463787033301244418231940438539856074603360903070483058902057658066015083363248256775852399567354
+3364502373064620236820638615612559600453180311037005397530277541350185917242503038852432559174885033399595723295543954546558084
+9899331087165498351833150053347482195081440704956752507876144131532942935103436324218551370249739155812929164520262875021494783
+6908904643032400627041773579937621950623563067061899745276566450404645141582156514162192031414915906603166745603027411059622640
+6495757281070400862553880509625330137059949973388167457480215447233006890221821337932185784669081820552176614865399261551583475
+5214987707999082292941559306056717820096495439266384956685554643672988468125971218644583921446293636673793845912080991022068721
+9098075542650837679681095355197850211686123726685262897042587789900344672369748441583193738857149324437982999889236683375639656
+3454737499177458611505297150687929879276146562076664745364918792408073476880967147036390541767431864129948395331642282070602239
+6878237499611110425456520778926623547629857959652095556385934261653929146175223058776396057712180642186976052559776640567287939
+9117825842497962507655739795549675536045986355442960959176637564697703951624943028930326642942379066897205661256857648338706258
+5607249824040048715831055763915681630425710558796489860046207669351392908027930067134903067626066854044057840603625024212216072
+6132093035960157469992103741008683953459144927130308314821395510817197195888871912314613073270790771658400690547770532514734857
+2289766523163076031024159344583085122839051296194651927355671209701571188590931542840886950235609126079848243347538568462648984
+5766639281060869652151900461538022230554309323803322083408453315192390160247383316259588161796028371801133887539960085255308323
+9483650441565836194775795637439945189737766569777908677905305601319160962603730861873961369931413625520373523170442339205096446
+6397277751314562067770288602692729550017088466152598972362685935373861021657565974015373030623318967239986491125515528075018887
+5402601339014610197678055292860126657475597634829577844878918241260173909075027791997352414032212153167271561905364752619385786
+8491863948995147633786778542070447298998068007279647829967199136460489001972567744945790789456373114064713748773853626265799228
+2370209092117301003097542080527068882722669167429990641325299940901538545419032212913930826834352316812337709858765794889107909
+1398631884718147949515763634548480975677014453715972288924837802795200463595978496786857308537512388719226166051585776739717368
+6941189534316796817726911487247546420252712714875639017653467949442416805399033991555627055669486555645886651826109264153186819
+4940516166674720818220542130511334825103331157208156275492549414655335399338455554953498955587141484886410449146234826660024826
+6659792948006838082450272697160209259339168888357685416533244048793279607628259013570705943914832132649302220555803191155769678
+3450607770354143996892622745433805449122734203977711922327068576407370897444833149206827486642681899060356549533970828759001934
+5727275520263633514968976110225542746359061074870472786303946464842833869445090010825025879958856002949152638295200941043841906
+1327175710840731608371208629917959139504834096615996636184118498113010168900528468440699292352911245996048410672241669829930509
+5804872329617982647538232786144744032881485213965459136524837612293635959247462464117508493059931748287964717902656930987863246
+4277723315738568098484054986328302182182023008609946701266751039890388797338292226205365731416488922689962862442504898912370823
+0169167783207015850910326779335592201489472916428336283983741331168324385837589731443211700684040249551018329769335204931232483
+5298537282274168905097783252545295159931996045324669229561719918373117774516092756810950028198012718738992851067743291059615923
+9444851345487696935698137109913963152214976022384665735269814043959675847649595558507091607437770303094115672250928216923641250
+2149472592686716079768844857346451000286201002122320769034758020998927559101579776094371380910427183625784710226757782544230415
+0647876642293735785152692483992423954470320088754545909378609961100700126777198798362991474951795873563734734785888619665299138
+5849838488444430649533263787538811331357728938722568950445006777515651519234515285808516388251516110101450462227962034131202241
+7276104739525907372419126181186384546119321638501786879645354354875497667502927550069197442007577146458961731206493061524033007
+9422217503140335187736221742892478886207544102369268483447607791356773560830807813772377547585429918129160635826252418480968692
+4951724274446263780114357613049442315030582695389596800003586264063614032462365896162651936067640252887621519671734335954108739
+7454566191860852039559843736923834077952568697550937244831873949705841445761551247253789687164216518186201016215799884228535871
+8439893371971012000885553951535059948361302183174942319645796198457357286423328894929588756597087846522596101434099524110623679
+2208231333330844864465745363677908966068876448934931718761801046807820975248234034617078513450119384012451530340905431793537946
+2305572597375584599916270867173159433891169944691281508143382202813205881528811308590035206333627177252785229699333403132814188
+6581817307307772248849032636830370028521484024024459152842727518740380359881146898101434552487760886134249651169919754088451088
+9972253499037895070298514770518285390402914258598519025675691003304065496834156654347189749182550625905099172508363395356804877
+5758008808025624632351941198979018660594929305107322792450818499652772086629264781844489198081813129733546688788720899531192457
+2745675328488913480621264293304705435951452309540398654081411328496424730516137398740590505211615977997709945823736263422098774
+4319217301030265407335508264753089155109074707762624338354639950177679811707826932551029618948153019495825747590381756914645981
+9125342547489286004121333337059776054538539726153714180036823804029952720452919240063140345998373975940156807239544138619226508
+7242675874264000704878339896544038336920890771642735504973073959953113142490324395737352393349120127057115852252907686376626747
+3473321596354209308933007945651010752129252885281924230373167976919072240297072208573755175225599946410500654362886750707794528
+5727589543974524706691693259117706864773673979587751324354353742658357813584415514973239116989629743388388478173856874552697761
+1142418605095869987288446285147568178401344806595851658792922110020211362874700057924021743582095514290749364426026381491938886
+7017216586801442390706943294273005287782115442259090512088524168970016375416554459606914186390125156135455842825317699271637907
+0211233315441242280840462166926685973850749956345775689925242698347596240183158491250150173733543845430700552741593194555804750
+1797724078344241125893042060239537330994558786922162379383591805537659608535521283089375039292199790021670953442916099772863332
+6130652679697033488878720295305832453720948952785209088953761883766005724826476556165454243473790630572440696210857988190704713
+4744821686581324503785124383460438165434233854467259677279955943920755162775872557500679297287992727542016808831027373389642811
+8818850180176632238377551894120301699425047464434209428644888921239546400810384063448594908229208386662084553428371435016786566
+2565402723149127183692936818466510584042955514361987237908845951130503356391102529543147109435545190864583265738886354448729716
+2555888389438655691918145095510314610669012618591908132566801282747594112804817710376968735883323783155393749243633468461076212
+4037970808854790499072817736929400553034907676890898900783090149602127450205466513482819048073679969106848951996174948205730701
+0816030875372524859030697931442206128673990318458281042368684773151576092499288971063578724086458233384930941299441451767263066
+1664521612180858396451529620088930659358500352782541669595817923485051339758066634536721977274523994998146473981701939017205602
+2524104027099484717563367769361246592695182470261402965977193164101572566284710942794698915634141627566609476347965721168530986
+4359025426573155220274777012266852482447049345363636421786714781355224872652596955092178684933842367455487342490049229104686636
+1405127824749409497462184480237538519293466992317964479311951604897323056429690265101169427550747026874617333157171121236924703
+6018076627013550295381656119236991061160617457180144979226462876301063552180250667955529552359828561142316939674528337208856344
+4374830018868998904944977293261195517662546966324518234611103690143089662138017933662034152841911712239931096922875112835748433
+0236447221655510600424621887641222992324877860049632049076965940501963553949996895966286320389211270787434721126820780971624253
+1124118658886218410732481795333541469161905682578320893049989427979158879370075562912903672274463984603712619157580009287344826
+1490073439715132975375184719480763004789606934374075237219980119217402660147346676094869754304392997432951402325274930204871342
+7507088153751893726167389642050254715794421419546083151335746591084804700733010001661585164038391983336305667211157845088930512
+9454605864819889656904342091511833717539963300409957365660591244004512939427858955522107791635547956216918186634105330346773979
+0658593516322846162016300446203238142166026181710436615937557978420890524597354295972144917810824199008158678995080211427722929
+8980589661160288330719076634082892363742482807739228207426629330991685667550752678607146578792931470069849286956087928508404855
+0981420843325337105199162550260043516249035154228170027681913983488364730292863723816365277728171439162179656110789246164875870
+7235989772218476249654125554327002628917857770756363184283174214585030441232386973067535578285982100385381595377232095167172355
+8531968481709055316167180990447601481938541581517577911736493317452245372585792259012856477270057051421673563226983021870172320
+3966519268023261060863087111821082801296148611252172465597370204173800451852480272015584093876590792853690848377385063421097933
+4667059194375637666825712724740535719642601441210189891690016272378550854485280624499553958549215837331920055819015130335235748
+5180652276625067336617174370015460185337302241346649852510792894228685353669611675801310899772318114006268028233834332313504023
+1941303813100529733477333374209673305915978659212933725574700988773740701325826021523545062039757705261878074707241548966802269
+2746067443336418197240323253838643666106109625323987238695096142699993722607024221029583744572542375113816178166737688431737737
+1790082381839115387609873262982695752275538347088304949304931589485737690198187441832377091589179048950816796427590616885843542
+5552689266955858826481326722121453449315123458065490624658389457610909531278210069460670951157478754958271396713130819467585412
+8161144774814776141255994752061769287038765060690866140571952344698969957192475271081186838639007943816699743960034503332953194
+8789192141356424274503562578603345033063547574284980009602843989229909463071658256259561315235167835094522110712803401150014304
+2269120125327746733199585385420581800688978135760399189023545691870920243025811096318243711254873352522759304218250492540601301
+3220660009367443347579325094663071621014417170436158246461857082697811419327408184450532404128001876815109034413458694764955526
+4236810019612678173215181621403086283786465950563987195979676317579127299901400746488219293603220797858502005948349760508971512
+0842456999754267165377711495312735495780613161991580964945616998690779002045181519007002606802172925174094502143404195978695837
+4416749583760585438101952975396064089728080431113199590836008764153005621794368480547875309689843049490843783015113705286745691
+0795274682904383996694242263473123412015847505963674606830368047427506205910859669522416907398900276339485220277009294111636658
+0726660439712285671104280059752886748116228091939311944983809111670167487220776456879193368274819545300958924106260054971842623
+8150764216086897115298219326429987785009191738597276238467913392040684511353140756968540557235239878544391001829270153861846092
+4383222134341106409110971398373626248863354871646454326385144812872101996077996725153807549596115873770116755372384144360289549
+8170673501302124114120744895395545744756695363267571023745570418014263093634951684729982428233593809293841917967048459961199699
+9763136038244743451806991825890314924556837135102471133555361059824564665398157293669951119702184740695499289874076409711970682
+1422421956968116348857989939957276677533229421063047970708284154758036180433546990214632661390471026182712000805513222171655488
+0790454789270387069048408785812014404576158995323548751958890039523932351478622587142638056133836919868045535455845844392024399
+6828229983228262659292226957969701095193296498963956591476120614340834793473477949399153199148731691820887892496627505449096093
+8624492093374718033878604413583151815223479591147786368391299257097621796393142945746725700896309907581595691253852161958930992
+7107729406703783687280485106218574382700030054257355689626925093581880354626104182184797971451190514868852721286584413091561305
+8741987234103316893377380144344514006198840745678799814654988835056150781397439910157073114301452768509065135515533734967678598
+2735043292667576626222020726140529203825880750760734206750175908534901067729659839678099054130592189468939769616706044680647240
+2763006819383647925527431911808115681683993973822624367816274873450252222984650251537326892288304742295886859351709349425297650
+7134753100395351301348083365117683812003850761712390745630056031799089854945233811860729771699517948808663082113548033370410055
+2156718353193091760663949540389192861228968135157606923907872289234299014121301709409557692508414639141148641363055713300497167
+9323046502608972228620000366263176485575290223984881067717695579312796433503231136630486297616245185739116228913473000321724069
+3402413948021099348085449161508115950805641814124236561124067595528674925736958070838477983849773356429271615279624883406948406
+2586362309829746055325863292755259087415528960697154410026073785183365372343620398551768197389974234910915413966255239135166137
+6948141006945340339297784658800718813009858499271702100629421441689482806248257882748211373263608811093415305500022007093455945
+0842258683716404942736428616895358695656655266518974938995151040768012671515151979466768515865903424648012383400333040320383895
+5049269512019956300105561497239010604854186206683961343893764070138734690927147819767835829400814779254514025647466904224213470
+9569948375696342652641662102284605174592869950745185014008552719701570802715911338264166097617707320465336842190177333964575034
+9428680684767284183633020532362541285325879314896297017757679938122092115670160403478099811406505218708402491047782860144041267
+2048668363875460097326211666406188941409324970507852534507916458181293600129195542233794471499710031501087442970014489278431811
+3405993437193068750979763065800204417948705854493241428660974718747020128492308645680153785966021095932035295060527677641892559
+2814589083509652662902787080397228682431174828014560598681492336798258054680671382857806718386021239491601389601875295478518945
+5986699496572944083337074930929834075993621216590713141225309670719782429561351058677320246208472110574056384475102009208825158
+3701143845992716374497567663523592738178836225177899343548036997338523733500001300643656167477000925420983129066143726434092701
+7423291379038754262185514882391794604313384501082737513845672893062736061561920457702887522180551612186897189287428790772663945
+8038882462960387008399150903931548842040303337569963977574310341965170156166264463639669524288945874943197641758694114087360524
+6755427287648373311476510042437767363082433235534497669444705172475485394287772438817148371693824101932257743465051113814804574
+3302584529244780057393036854445554623243089576362550605055694156880682183315829897197741778897975736012282052319045886108088033
+8087176493289867561968800923375092924482419715512093174473694625106772042668885277666098646361898523510402733964872800445131037
+8320007995921770348498605128869111626930267035943426816435809551556518111290098800524644244409358410267473862764842446130048523
+1436098828025610017328979458386153232076446194265248731690143382189291992244935737904603822794261840119592775301158595671929956
+1859896675014716704798696047818739852245706249557223427847334266658566082156593745460337399765187932861285602937611319183698837
+8695387218535720582564065835479455701900416698839376472323627804365945785468346621682197696163783828936362978547295808542269445
+8279752484506847142094417985544033613129823835703913986703044915444548737906032583690923865665220094573089105884291792454719678
+1316169725449877686068579181522410565098719766530274437681078973112896904796812316498589687674134438686508004774642199962324204
+4690063619499878869524791692206588255254568407388459022366711747832387099104508881401463078787110967721065394141648606132537550
+1451429470869671002057789223158518659342906175930490990163086609677315590447420960904216338864582531646704745882645257996753003
+3594769224483393076962577578336775804994360716705648101110515582304099946203974654110102114903083901640907564773113403226112614
+7842811390980512417623967516307862595714647209118659868698680060437058188686064362842966029195804418885454481156401460457680810
+1353730331240432284758809177395482784888827256712163440645440749728289433010840369051942073911490213001477219496896397735829211
+4601945158211709423733169616586120219445506544455684681994448828365740758425856347182450418912396580393258871768216932273389644
+7546606883962070377792485250777570864737360035965255716590780907370097846008363755114568550428189781279182714576817370377989913
+5909871699164748481388103916215854782263584875652627145927520783000462057342075067627629231607264735052014948668522278967261465
+7789853062938105623444363261994088544665616630390123445507860288440231593034911635167838522597643333127458708364830418263896184
+1286144438352596484065325500754944308173042437315362632781599996019422261591416810474894175619846059414717720198222378370653571
+6971462477582470633206125394932199429053380382783796898399516803651438673139498531736021776634684941580638746309619120992683170
+8629432822993724963855361987882118654589234693568266212440633573606219295689682039033133123609808063033145394447533709295411896
+0281594967652261579794466637274919984182923757681634332365968310833409307348568763974412665592870158544818035335013012421932763
+7655826860692715418764005666669293766929001138134358352328235302135813053504743107776878655717896623753934484760219931500298692
+9290168663678775972562133999711785783179036668870829240738642007250789936063529444287722257668245891843786516368999364205453698
+1388094089899362163718773572230079214466119375080348978705038480095898940916060131319234067470176587422484787467679366538347868
+8017293664803927630769729168954945146012294840940686008911896485848777037133106837925465110245874730110174759001141830380040038
+0120439722450454617928179479243857705288134086458602893871161972846537382451740227055242495699985657918659780373398590814158015
+9185549346791665800883510913273745072991047690371888044204398878541170797025220849684634548447569944177523688037116487344544844
+3983330147768673814424552255794031561316294164196820680509267685360230979960997521617397764375675161021883986966830273621436840
+5559819786199323213875219658620019627595340113429135282821726501703289978583492131096279542835050405087347140325687712807079487
+9787946090092230362250195573096660493646419587912974580035697132589473417918325240116393969464922906025196729087774385693764553
+9860355320714920060965670358032280168554148297437945180860387882403591842300282814921233640661490871801402207762626482522032047
+3097025361491117451005377278198487212237099544908247111077372764356886263791448989161160949762415522639831639294698581458345985
+7119461403366321455704765813404706513096376229662175435103856904757065360840168635845572631764671801632765978886309611217770123
+2355725108730791813146700353437818727398062989969964100944171032459233591148110740093249920429111285758187817891195538479372333
+7717147589069034365041184332554553609756818941590171329038369697464604453126540943732615622700321916184110353125350100127752260
+5400719243883713007355805618610788516934976237500923767706894033322172234355015854525038569883308926393709084041999484656996753
+1283666031444516796129629651038339271512674202354596553588525167158551065999313761923723647718179391480101442800341777895133996
+0753973775383179955400385390016380992296547654995782315767306424246762945687075752145691419815405005932537449947304486849576643
+2979180958396224767297581462043320034127704743702992357878029772922817116999851784773690688789215232089766369127969016032601856
+3851573261415488209314332793330099314068046066211719044146103127781354079770099732602779302176734228288014045681315375260376275
+5613084622744138175415292879907528314309988380989805830104342547726499059288400078772029464667932988421246953056079406071204771
+4586730576036740853854978952480253788859203002939257757392716256983049436420156853771221502897572109716517239674204969203181474
+0982119350191052441755943123327258611832950316806139591389360751863567226397368531779203766930988225110737707276225086269268083
+1166609927459152345242074308503846915870742513191815496448329154263550697382001973332037653901875197894977220232463712982961473
+8742250538546251559619529217497793362557849446641056066254726761640756859174902719692841027963345440941200289292587371677456563
+1787473730619074666648808301286212846168364513813858291223488226257956569272198811926719725754005926219281926579718279777830444
+9964885779070155802556863992597887379404305287991864566420006473195804170299129414259096081893003248613986369776375193541122827
+8679261717535638702784929128089835277682571491318590535314932208130153018789998592505582846756436233025096155853923159667457622
+0064101062279216730164192200983393569735835140706754353527254528463606619322108164129797836707319607352924077829068257856221565
+4098966914598730293864163204728437998349124344700052324246741119119244973881766239805489297351925527481613098094358252765642656
+3256631812453399632987567720287450907847236484423613740997675264597104916297183865029408528402827703543717537820987540612308827
+9763193844988062420108359297687488837148328286540087218373263127565810612066788312087172343604520200144217517124505185828378183
+0839169941798971803467138716750724876136916222233258526467257984594030393990037357389464526262272705365500201964650768865692587
+6552250604997641261294087071350242489522328429130222914193744223497369981001341679952214443941383946458063259049876349424028513
+2213974436158368636025109248174911312580051245505113315795959437260475388392500593400331863318219524296806654096778830779216940
+4878685599516319690797457606707664358483790224825508827231099632903629838432588023623129489722939201221165328880348763488094404
+4425772854689128756512183299147748549960529805463272504802739617344094375960651486501133996216955411590283887952698362709773340
+3400068591062085249345178361745959828363146278918068111168494145377017234716441154409189698261322125169944980545699464089750536
+8846865398199885991570109728269877331973845988335052515573008133676441111176443077214835337189028637762538757833593083011292020
+5146028640720658045073881058022137119722140728994381646856170548927402303281330627742305686994941764560406751703346767750713886
+7209258975092391507951817856714755923161856176501059139093203502102911025009832983122251947751287786516716014787221574638939756
+4031047248735708744857275535082996528246946792080390060989384866585501142477546435169883331570932498501313613151748523824910672
+5636536308963660510951867259797466984603129916969819578084787382312187680895777499152465628258228314680156051454804934741689251
+0512085879302345402847429395015269085320583560263939898103230391420972595529857458723736782481282792113866713373594735837816637
+7989131244460061235927200538684991689192443600011394251966967305334141431951393722271395226793607939272662478632186079903315157
+4105861225129127048237596511466748710669457275423951266966241892139141936555720690437418563605034436351637331842274069357984239
+7714780490538701008702866992517751463558344819912101444037343071198346617249265664311758101747127784897043351442589412949637554
+0794058900554049165331519254294841158439399536633260010261808293322453935679510287405960977887161196498223064393352481611148599
+1300801876528225731545729262391681879452425698425569733040068970789105907778300649408653356394071182530765139660697696280006682
+9500403460028711452841481826687628011337250118712797471026118134978473459279189369396543791538899643830373887355243212938105191
+0873118171200026341001915337132116843336126642682077009436271005094613931653248785836179383736770204896797782028704969977499350
+0015763840495758341501065058600781266869591393444306380925176998016954972799133300711081355008885083487358653288976991291458433
+1182038281534129680784410839850542254891681906855217404657576532842299794168911463577129652659153953666202320168343676218151354
+4489515205537483086890747806185147028159038841561163491305751443503026033718219551299657596422184541173585136713789948319572208
+5427049518844513938239013971033113865769356316346953363872557559769111015332419532829697997722648255367995610629118024243751562
+2407474388820183495631279695253839995841338363502759887550630065930650395810552864219034911688436057782562693639597408091177372
+6597246835826333390472023469934087393575305915386587464255626374910540525559513620612895257369286541372428722814356277369790926
+0540482329932732167361734686964636330198342028336626252732092257904785101659859937597352536082164206650257784256989122547150860
+6958569549047812907458129176134743095874743438183862052347741885494624143736509130890665487847350948675120079666371405006768737
+8780431675373547960195603385932928721012510177772630104840609721475744144915357267790854338213160647630650329373129575638594956
+9496521524390891252020171500116808958864975665633521384560269916937417268750283135245520953900937858745308291830904258244389317
+0015367958131832930196538448945414897381505579147872992058659675192664335486653438990141847260783598099119731774723267313420147
+7668586967951300028516829535113315808229408687973080784960696295388250987543953394689424360452251573606982659417899250410280988
+0855610169950498351316129660470090096789046559977941298373823170600445713232790694833343261118257499105417238723309775430866295
+2330553865870284141777533356762036585595078938692432368606760459748846645365953536258322870084801797022785593339163737467833147
+6997226216417469287126591633487052682393389785830401431520389186301156111690874765557617527284900760279233718743071166517225051
+9560345000426728260399841368953209835209100487337639538936954570820031680886090876109665021023200759147113373797389077298422122
+8175155068276335352679806117326566700814346009488428499581701401590558929437455938924635624938224553855781741120788865291783407
+2295536946679503673362429092591476438921243024065802176610048872694278802256805275897901963915809617356852239830206442834187860
+1980560976965565165140981488552352620248220002599581191144636050647934285203553865821505084561426414945738261567792216102403148
+1151908591260497769379834919810177114427370448525005415075150280396616811812913926897078347185577604045023394052213732465977204
+5152624009308747654657296667409633669797187558140762249677298229159695566185953786763883703575683368256625993695568514289670471
+5898396239237604417219674285036697981388707533386023577734556605753254850219222927862511398982564982295186931657039590148578018
+5932796785525089331274908323688642021701636412080489905006446995970747450915290182470813258134915840332610387871533886024451368
+8138194206803987511384906150527820013265474338857553899093509868964543274546783521373587071739152356855552276377502435950664343
+6671221923018976396144288089085545597962326938710922261699996323322275457923099268605292778087753199123847741515682942101433343
+0553836973054122354894964985734607674790792609106461042226839499946875666977767744836458472114784382708675816804952000351499560
+2364997010884637465860014885474868656892220025469289156670808481103243684995557245150848863996066555128792257705475749161690025
+4110649532154387762250909130921439734079690118528643911754202049214907597563788601359791270067268169269560624171237553348861595
+5940616224028249469894892261151683448506705471885912971357007128279832881479611563158245452847817654715394431167451576558923691
+2701950548115303007534807474569747157173002064876638265966317419898895957065042960548048125830083650783906003217529190210069108
+9448438509033254495362865744281724512323137198768884725254104680523096628653622761003126111128301647813853623032837646549389708
+8800961571279179907403520239170262557803310568213744508717356574441764473623277516011904000012404016704294869157929203333991614
+5621867976685621217499877201966531190154493625522363719922688125680349437187226891224242675375445798588375405091275415995993660
+6776602064451444697704536229609651834393352676778641614610712731028707328894803760218379598569050464723477953936124087430950917
+8609350069628812265374110081821823052163446196500492527833170210965201939797385205224718774402651526872691305286672629217382035
+8488697066441224751559631066164022076293716903983024132971083317225244640782734589625800094058649006568726351629980984900472989
+5845746441409288197669763941632849306888745439411555999404218596367981143977695990224865577494042079971012624349908586273448094
+3944731944003065116712174476397673714373918870846441482703374457072218866041336694655582361341131880499845103050687313792470342
+7857292237476195260600973001695477364449307421802939526518179464787823934178232688755800049682688090660718430541383983270572304
+0611341821464316878794523833266573224644012837504558841156871904475125652999503438286924058574554384509785291956022252381864357
+0405626679943651292212678664558286589975871490755359605369624889948784641951887207653741241486219388021477385980747033128784838
+0349563685997861866328510113314436119201124870929479544327167409917885140426561670911266619220856732660355093308773694213795936
+3842271417777258599324767675283259950186722960735488702869088413460362934496727774403713216022454808579752649987147082209915211
+7262086846799716572297263071380322488276591389406786696601706848938742607301811413241169596156442149745813064652698654676224030
+5774876540806221409456713575924968982273367206175097023050483195829231424480633395579433434537883182331511499750784779245974304
+6819745509357317439429415625378554567362388569070215909977624507836378437106698876357999443207523376055325643289588788312580731
+7833148656904363694334569121139758945904938915660261426660062808527488257575416983895078937523942074734502850315306918181450849
+0874641305830980547277712020017148651915548171250649493853510014278214375521776229277631115079740388430042785920214556466053488
+8302249778400205215684880334891997915871809162392886542987069548288428411471154533517912205528047987025944754683578880543791606
+0358320982227642668267885208147099122293592290139450664586369209811129197752858004803010616081626472750567559363814707696436535
+0313506752837594147209139665385131531998918025147449755897149885365821721038971422038604629058413601987368885444084132780675032
+8698373618661979252204221364880007737028947769589369624595251994724054095272484618585409406539000761630748495654887039290015310
+0800818173175869261167775704612174999230343952148568401102639665953327107535357309312915124706207238389207300777172747117401698
+0640073150863859675544943154734483059715378564796905159762945298307365280446171698542814284025032267504158534248530901828343035
+0873201504993233632733239057534034773053022444340692497950449652566396669145334447109018793398061041589027430348848568737315985
+0702523531880691374404054678759180464956226260133696133658291458560416403819468440250477647013266610552428012647058409477074911
+2679888054788444461424298005407130238905755507645631966764120317200939342102226493489457200513433158963725232826211305616759400
+6659241756332251314783750854468182797311328498121933543014291040088680657858265588241030117849346100683667795040402222839296842
+8277427249362157833641670896337597700968219737912856460330555628526942419632625557211562429343845027815601523792180592076379859
+9754404607631948362062894438912954500557072195072644550642458309860663622333701157823267362150209715197912528880882392701349340
+9392967484360182578733939528902161701930343748675665636284278981486199253820383071398887821347218338053979003089742707812914379
+2904235361284953393462862403685101898073830804299574939556200135991635904384199077467177409693740584708928799458835571980205648
+8121614185438088992376830836290018683875444583668400234525664787649173577729566744205001928280399848363250846307170382670891227
+1379156561645180509829419293369128655964653490776933715927876086576622995107120980971557236204092369803081979966524323872401105
+8210634652239640140303181717302977441319086010060056823202877048062527278336721358234059108992008083109338742139836036323492605
+7384031376893772770300054085703713950658765604751229388016547464754511995220292088356538057488534591958960218276518555883565725
+4074775956662864334941163174462487475635543748972688834049926463696503634025310758502751556398690346342648412837461668031647927
+6365750302288055740676475554487791055706610049861824646116595120976061102018119073494765991803213702717674747175954421813209939
+8009331937511328151001411154015547213063838109162601512214845406533014265983012161008264010599651427488015290161524354573353234
+6470978945561557225050621564665550894387519941185513668617316911095236397590508616848692919250154411755818493336504839734750031
+3525111855377922515708294426372763399105358667430235504503228627410198905334837234851992023849271193012460177555030458178964902
+2832205291216922852095126506355099210740893308816704635379794133382523761361826241501772732710458333973916837834880210080414250
+9084082447350749526849475397900892283815818083030975632291741303292925823304366055091504295072069505478412237935230243114270458
+8733240614953524515745727759843129756538792646920469274157284227528661937418719037781765126256474601006075476554791323844619684
+1035243868690685092085007530104395247063420667025726455865466535541087734271159372906562129287612463548495628710375386966180600
+5440542501876451157868698528285357586655663503645304099842630588650168915815059917415278238955617758631802903768822104984447821
+2018849475721498910886528030895133588236820109040257215930892013189827568406433756483461049360024443491773721292902184969255790
+8822875627013591731684908728396697952056849491038175568000507526035874582989907019189676297477355884544173196568562596540184740
+6207027832469439408465681825635058880584562540284002435337574271598044807397129809411607354965616450909115426381853724556891033
+7221658030059861817521753782741366902139395897501991336285575875528980544038829626149666345302799699624831576475243396464744984
+1649540253799052538081391692469181324705607910980425515252483873483980593877409055481936471747872491282539042199279780879543216
+4236145733824367590860331474571745015558798839670826761096891349398910243527132904379844441054007921880393265550231971508677926
+9325201276405157061556423958329163005949768823959483768715570931105074676418085399720398268434277889429566019457186074673651582
+1556755082109554008455021604947841187746491317217027281220528571996910808491743715098726471698066342041982149950618417860098084
+9612051527440619756444098523237719085720236857461176953239899550769256325996619384467815272576473677824512425753715748473823644
+3293706412332532029368150574309147409666660955800738909802362577371939197344269404239579009973609254902956047445459161013030585
+3889810572293351817285095560307955387570122899356894847953368306309169743185951491528192204482516204225431961214922057114411745
+2466537795850541088028557343809549480793529110899163252329393397207265339963882361084755962562912216879860134066671514387618346
+7860354854395803331508980945959835169783983572284248855654573657487835485311040917221652836888254950796354469715116733559514443
+9649687850645361629683896013084952406507914922578933911589068814423571506614639956792270631464418346423540206296752844238915237
+6020288012912630828121914201273847417936995938147436941121877369382021368921214557882494996867880498498027992143690818597132057
+7464732232055318247290946075477625177092427701352448918522702341636498386700884661390140882325113012278493389309349523351396213
+9696483275515491260944768055252019253491922403588385357522280969636691193420388846988546363998678336385777443993831313531774583
+6282522032399446565965739736752150396232120722412203505719106262036358824681398508892551567229346012725815333843066908465157756
+9407628149379572734413508114861082667244920525693627019900560538557779908157912341364139167913811711711544677292025506854245811
+3464634373606321375959043076084467134891991975403488809906777158185809859079955799214529934428440394715803296141747865907907489
+9423993889790762040142434803114305323935291193328498665927373291227929076575533913306444776443880643225751481031179680675214923
+3368470912062297700011980465345274304044785588310672874869214201316579834207228249128013243107286248089143869069547088156308777
+1414590222708121116814503748513196371955339806257298864789960510451079590735116383580469454857965360874314128844784304143454069
+8766678394720390254448078037404671513243310605018703312189431738938607517130277658972087080448195787216475306011123823302381254
+3391550184839202307004590614178501644771630600861096494601392733266531850599404613838770697571965897048614790913072319558856284
+7803230787138777594218452988887094396749088370117209351285801556001096168575241228759515079363186428923678980339871398190852582
+4019696628533985636279505759337532628472390302841917324608852947709111244515112700445738982371253756187679740389512024539739520
+4770847899134941839230668652175028834007538603739876886601634289336067458758592877494727624461743546957277223347887135182085175
+9704365765485920770156655545282270424007413902597806432869012806155483311798101235310454409760720811406614955012826140011450968
+0313480515097495573412839063893028999786645804567919951099814820194282264604422806064547777371073192487100289094441987847150568
+1657543112009039941765308947835121413396501421019711136903259340105124014460634621836811024214292779775980478293474663062122820
+9705767650372955367904858685510440746508331239334572782478185604370866609254504064506288513924921428844442806366648997093161941
+3489214963851233247024856358669087681654387218345765317192165484089902190489810844772030255183904855574220071570304690043795231
+2065091959221855386411960322245401320421129454685844655947550889456851989959823948526569728196088066488438899595441765150072821
+4429114819428348855107669954324003559235452502739679008927728613312163086830142833511895866448006257958165946765071157730382695
+9882679827690443780755577550740154748999710142655073573245474660654485200341800425388615819101330831466686148830980748666684090
+7163405135812565179670235235614927720441373285793867065291904861238349709700184831060873375476942470039510660809272264903320798
+4462917767939061046448018044214701368685457860623889616757211734619696932095108903120448131130054208365085745531785639497736359
+8218165839330532616994196742532527473553555966673141549749982047712150106818828620285541917373915693522694719282613944281399835
+8674485087809037160526520795860814268331241546826667372648249043039257847644579120849321232434718628926179993145231262359579173
+6402705380929919120941181769537062173912605142768108201761013755197467816367902585985810911153925853453654100594647121313245913
+0666872833826033632401371436548685693080139022484100159022033636174658329127466366162032910540421919446428986161784748017789598
+4723199613767942411247930612753447325541505390129994382585659648148388692327147276519250190560063905452973361339890280400124358
+6913416888336681958297148217827338479648390575317941960750631878321348332412104016113215430987661026879407929196484877377640061
+8494663204235300224243052398541725825482919073092074355975063032796596426605495082752541621103997044605964809112021627153615430
+1932408491193512375077001954464823146678231602554522550896013165127235920096414910813761330938337552089472955671775628068540474
+8216732019553272236739723100215131535386354969462704414412180804694918899617675023795044921436432605559415902678545425651517812
+8025247190590822148102225680479409002058106823871348717740963812585351667254545007307100968605826752214724522314039708032085185
+2898242245907570507615621864533672777989484514162394933849338212142607118088404798508269488444104500180113716320167923336719325
+6087711919535546884547342110103435389748847458344462232091767124995184518172878034781269231230242533893228603793308922587510107
+4591474660599204864799066811331150365409997858447042372594886218949250820247279474918230135657009456785941687614114216570961562
+0712145092385555182611993058740320634997625075753366666542910024626577807784857468873721417913984050547176339602792705731039726
+5904226911569176720780206777188612328120845124057780320649670149526594811111907198960857717925291216166167928639613716137663067
+4307416456452371611701931195073322788105756639763524372948315105493615715372579618838296610933712476520491005806495650421658587
+8328103991782890592563008949384942150246156275152343753139757736003563406755966669814359044466955928045317799518086337670918431
+0138083133435376046718367707916060720252112445257291714225747183751131216668718597844623190537189131972377334685833227229634752
+6238721382625606157004023423898943602807707672999152909288657052128785368828226605301253816178238566671806542598902348311422328
+8320139586923410723937149546492213794676826048701166669784481756530412597915193651538414740148097847037639468257092287852640305
+5479022830982203377478476331811758576901670233527290215872232363518816501458927070562308753377018843087767143244104321568604135
+7369186061703793181459759961931363593408835426106781211446368072605366366571248851597783995945722926222426820630491316650527779
+8828573417201809585216027386210261861298732060253123609864528252840272478045882739663756003736716392199489082689850824432511971
+8111646983909651153366476446390221276039522740932580204249319217339578537772918571217444956420257260371077236650618481206170288
+2935054551970379324008798030984106801055948226939968902171687217907155340893582643366397894579369212912093597160438593641683669
+2485378257568528389277310889609277386833678172566456312002344737328227016110453362502908568225831332260414575845627976066579941
+3482852162228716106007258452673841400279159876124086723321209861347673279139378292982201754962295388660515249705755465339980807
+8586012495756212505119149505421333725699491270326513988475156468533804482583378661782959257850441126447111003717332538997317723
+1776086627675735007130894098661445494477133237650830139159997474669449285984774365441233470966013545796673243563388041724650925
+4871204375981896728514583939521811481161849278118060344334503543763509824336823270998963842004711517359429526921820434423765506
+4949119417418804810189631493303008698556136954410752013975187350631734375598695358460132019129899037320268439555839944615572946
+2352205983666568424098911534581381260867463768189900460175744875437666192115066390019086651996365032553554531097825841729484867
+6396761821871154925250940721334814793716957966097731930384514803099552848004844714015522077211735687647117734547230837853524693
+1596031648179998000220637673943792334209148422484797868537888852196932416293373918035158752836265069893009384789762509582269339
+9695024706050496247098862490788952376578622083442656866053965079277898118236124486093149364786379996025483226916387856904200464
+5207178534801739733741859262250257717063345689422848102283865760573174574242830519134626672907219548945944321186449133371889496
+8091522599148708961675484538617588113615426169855145369191110338586586013267131819054886276010519517578355159744969858769754154
+1409888192657898889323633959345553144675637666158270953101126274823625732454329591205013981131246606853736622675628645701807371
+9520905296639004266979383969455080705361676763621326243504360544161563837353776252465278766865244727756979870759572455920688699
+9581386171160687133121725147597447299189214610587624098233087649334093755829602691095533964193964555227483958747057992036054166
+8721053344317784071933338712749304229416314171955616978192540365793299631623144229526476496982594982691261090976385827573975900
+7821592310703338108652726889016577851582851275588755649801212540201927028394346407971389167170778763825909054893860501536766294
+1680216758688189041294684581042122535978201496230771039365667061380634389195094311357702877874169983055267901138828354564408227
+3161070157288336465271541894601581266294703722546655378330486847268915166615856440605517140340676687703279431660743947236511822
+7741994422834194190860106225475557703581613419594307564273066500384493526007784089212735294217591917854424698645245431154845570
+7453435530259083182485810144347944810673614929556646679467919668579911140259730381818980942598880746925296760172341499274790409
+2328005309406832991426090784212693827689769275846169654962563240745452602435209585710235753460014401490458336687380630135023071
+5366592739312999644456849006548399917819901894358497737731098338943033079178655254808256654806548883980302404456845406302737523
+7903862311453131512315977712627346676478344399846058399879029101474967706599628983635802084695117268292559579897221003598626395
+1226042367447825280036345293351132154926212820976803484997329381495188404459278925205516668444497544901886948777923893344531981
+6856828147900151315527595804653628550631963940129883617356848115429626055627960941822258407367220366681493979858804129725050531
+5342427449777364357294403483728929672993293331804282077540029002773232860603723492768689779320843055290078442091489307669129440
+2646993961014124319764296539370434958358249722078956842849671467698536721940846395173191197670777284048312934901527571955362838
+0198542559113109732314309858412233715215167131228324026800689688315670022802995393900835564840785241774828835077665262843753444
+9550183762744591451958276893980778053478437092327149970098767098796188062615518630585477187237482484844353645352242801527565339
+4554133259430221270883589344804016824319680145988501368070988742027201586296359667866696516024912143872664381709357471736498210
+5093801098192097809224518282804541968783581829389873304181998214634779593308644761544892301474532546795113168811568716153209669
+1410860371073926432124196875939453572716037044352794395231284292433400177009767688979893244784882963302195811252949131002020348
+1963827673323077855623143768105648991600618303185458508264555147286917125868559346485583695956446151749324530132278047444739067
+6874456031627491486993438537612795741124963717273593326065380547768578196708046010574823669488232340781667689355939847002297664
+9059011156256654537948571823030159169978023672567790424242785131594034312912382632898662220373433122635586320057460971136026042
+4324851680908243245093083193503431558790765585803419091388697495752260988154385332510991556891584925155976792883412406678432776
+5169890219592441180988843355694784180780002217839745830787310928598719082559628331291213329365294364549008762394123896795514907
+4029304916499522070046006091292088087865888798317559803991873835903034439822636248876206336683085957754970026069257438125567024
+5122833726152490145361691490840338977240905109443464507374230617046450541939205551391476680636725777819582830317640677472291259
+8887879121383290774133008351057610071339235010888965861277804156037797773751958774639837524541250075316907358014661336099985243
+8039061153806899718406603277773464956989757949717475056088907096202984062415028201715624897091896396812284772715615886727140592
+0697572299245622972158982736674917157478112408603912440899066443377237594315710291599368603222944799827489902803052151032150505
+7013603271652485049620063445001242816749693945247727354086779497318820787447165373787134099987577277741625609459410605718145900
+0792184428093364028147126779227116462983472771162905140500152025984437549037622220978921623538498863508150200422542729027788614
+4411728159030287378714419332373354590292666051672346415137756916116829485503628039118411108736302251425180386282192968531233608
+3508034331771430567756401746605566004814192531598982097023747313496871602413228109505959309225451717487757635602112764447022631
+3428939513944422073187530514913804210377096901814387277664055693937327821063211837805670103207586535472844416128884599982345779
+3765013258236529201610750246167509469405857415384290132571908547691847116538830356937781623544344792657443940779980096189839626
+9024565602139835552337325332903285437411134785405743434839219379066510469685518924233636921521087402359934033983973385991471002
+2649847962568274167726165208946386788572121523811142222528040146116227215917720262618074588389904637062666528544746561556536935
+2620030538510199023964637151697713281829456055441798954059894139613970616409824903577033806155241943903044175681019965795785283
+6461188416880024087073825761424480883587286299792763357082205040327994699188993856940062456204962545880583868705703598889787721
+5944413986797134250694896844973795638537262177510549522817774683727110576630405084332924025735617088037709220742387561124513292
+1615973751057225002195236737059699517585264539200525680337988614003524501832730480276366257598203042140690301023569755795697899
+9008200222469601333665860661780983941015300488620597776980944258674129973552734738060885268066420909348372616142102733523433267
+5003598890783029733738430164315966147920008508177297711130783619606431201578483617231981134136392404255762575061631480099367673
+4714080230392459893569173674100327560113467502678424574866012722633975629063693151545366570327641280682622355521718987259238801
+4739385038824895235096103000674296240229268577109938375885209481939108319170129231324096236414336990925757528939018270228944966
+2361210030668060864499350273214477998565800871680472680681932947260121232176894643185754378295528202618772690219192407686919753
+5156059412217536746848726448056144396547837914584560922069735882550291341190213498634134528385275982127813806960692781201779053
+7966885142214723811725348168549783205309168240872140544601559983829401790243561220385975487819401267336194223205730538148703619
+2086985085185073545036414851529838204481235650803097024838796015231330542654233028002529608154776678617456164886732320375739646
+0833105952434512974899609076351921948939569136092110228925816092118172001373677700416412487399777738494320581470807407424704877
+8185614688665309617727123329966574828512583312557787490171669059879359795468437113583190694186011613831079902014081217754134725
+7131783601536200912167420913195076409694857630710552837087267662216383925992631278943851251589580445676689967886327863559646484
+9888310805734900531289699098784350167801387862535778038559729898236704661594447329313866535642213694637004811239940871137589762
+8123715241748226553144892581245052850529932097715696995932059624924557269075540247991049472713937530723957720713793716760718395
+6093034172460809629440737053209815131819638726936540787299401716655839213840485847609031890782549934060830350478366179240604434
+6633327894940509763972045245237235718323112502675490128278367355639972323817271838806709048068724517131782516093900913433491465
+5582353019666679291426183344951264862654895560952921265198755899160545875749490172299073507227437486882523588711701507976499572
+7489002650231525223980434094738594856401532028510616419177773329613390523750901433006132084090755184848290450781826037290985462
+0539323854296447671459242043430937704073386171637825236119340677027183609466820564020370547139050173937355911835070350187485451
+6965582154750741810065288181652685394941853476132562873871859640024361243300296805283748325817168878484565585632754351908511680
+2886210467566660836736517150078351812871682359935951946868379376912994012664524203941072154686353570579681603704825530456774626
+9665362335544365210262820037867343620764616695075643840510926473275049084133707571284177399685539645626628023165977084111958392
+0177820463043321585863992470028736425683626513381632161117010851699245594406701811450201210813697392240877275493182279748367019
+7250981623715632368538564967386387747576695271655268440119068242579103997269027655460321699463398768768277613166901925556040578
+2730921762116366900155596821064099866827590787028023864778747307107976624095851829841563684215591447795700215410952638220148923
+8642501753068607515960160175361362264643558443610150876742595480796702902130477857992388072241713968623856298400849938588555032
+1187308644994319305723690746675187962892871980887310999328792568364489164541385679772588717510375815217942384186220430941913143
+7605854751867100384861067666196612302899049367936234596159545293447341885894031370313641111815396044152641244256403303821921174
+8006560725678932454993887223171401960145271946857211912769628951507047840598467703395747670926287903550867839502877316151413748
+5747061868485506527664044246509977629632520838572005928929416857628593497937173916677705472302579778727680532363758751491026938
+3023153622006915734476058970896478596388304728569523091701672491484313935627044876208043141561946195882862365574965158147452289
+8540852691422877019070250316861163162391778272197273383387116022030059687803664857766804536240988573448290819394431972776651275
+9021443311810736715901066501558981319880316837771114344162148017989800388690774710489918382047318311988709068050500771418272212
+7599513906333939122554708100671399521304710290565461919067937465641955962609388316053120501043224440969693966990639899533003437
+3190313864768728595063193176469208637792413542897116168001394022157595453909893711585707042678368387735204900683732630413423309
+6043003917729256108805619361421477310316625655437814740309514638761344462517487426501249646525209961899684542352037279524879981
+6813035487710494491438894246146083397270552071559892438473910394670225142289451782904407545380437720612171136664498766583513111
+5704425501897608539934816199146825064755643795555188152948142674213138361295684789361927194878162187162220359319096077044697338
+1170042273866788055113160203247185045523345121557337349823787766288071325865947069357672811750151752362658390610542086745537803
+0182650295086344086825098102966797093995388649163271139864646408250278380402342942834021881070263294572807189069134900984272374
+0906668841731928141540118014775032666661994283184008007242068962044782267000273516374045366478779586459658472979356032532424400
+9941559950477797261120283165043361871515058911345852440301289987592080477208449029732297262652194811701835630896804400526302181
+9586422168434769367306983212903836891536506488360440148109923788291834492143450307170521991049310812325101209435949795579328604
+8845618327364168114007785559410459235882830447965260478796725064238526247677648804067848274177910485949526784938820751326532317
+2508842138180368207641530038974478572707059622379262380563191970615374835570345785749767510398007047615953484581417608147080414
+6150921916969845997446844026937752931358496152526223613349123080269156525204842351030887676736715854630790139383298746726376238
+0031087628812333418550306049252849828620365883770156880965318518371047868891562748685920081560624079882621440888924178323074068
+8556547813934656680983629186991073869359264408784267940961601835440468005712703124932656473056207782384291231611143830784642169
+4764006946356475094019331519107580885428818699148255825445877812529420751612646315832517900095651843319599421976422128038327435
+6209251031135205676846184796239439073588798115331056299413787815047447544760251266043212878984345103105431840273907195809002871
+3654931993884850780377252970969582655676559449815451929264323578834644743068604576736541418957979028943061560532360261664725787
+1145330876015831126155307819990268909839073491920596329763420311698726840745194869089228905040694957988171983477254803375572985
+8257437969668449439729079801079379205727147223003815670652927114347162605507272520770488283403449339977650008075057150876981627
+8526350745722665602676982911174850303165259851752432760991481586280102205346134401601648981884690319798225175260769925489404224
+4638271898447020123724423300538195550321048052825314720561544239062181964769986570926083174181155377779882057584541395809301918
+6106817249634524848855511452769182264081765291797239837907787970553958190403210902425419707216288535844322802242224844682625560
+0987012833422099095295557450557916850795807069003361331869709388270541973078686998103429124404642889230735965872322730527661759
+0637705394090134454432592452488278594036085049343720666733736875565892704518648963039960363828210137149300479545174722900885474
+0438909745910598389431226270312843755719991811348892485728211852221096700168476622881940496574796916264512821293932878797623865
+5429545451401418793893535526425687987849470147455674595433976709030225358630706349020692453458568350635883987698939555558472630
+1147145098629672646090540159437091576295858909288901226882948677153091610088843747423989951237804279634707873305141146001310035
+1453067258355914230711608884942303119909820139748995292741299997309447939834224950618749891034712331269306844559292626045946290
+0350632260797112269078999525007760708741928859358707432624911128337604559525225243942115958112015615876335010570860522898738781
+1402978628312279477469329446037732401120697968328000813953667479029085290308524043626235410022744559135665074491331563473370347
+9337757755044278436081677756600946862635252212939271849678018763209718297572192696470355304192247185638719953361091249281203364
+5405880207322161294391822123973103190408090878564615457135856917654118957703067143223083955082019279925860379183853717628861577
+7799366841975673356259200026023839542055869990618462031135739235438635258865047764693545067810235010528954960166478294307447628
+2027467028086256924839310527875817129214597755080392073496545377860632428440004957401492609606750537328284161904594401425287572
+0946928415702129545673169191304792948477302426781915513863540380482590408165885780307409257801864775225156808756934724074392504
+6885597618942836774284752567772379904321306380471869189416734595292130350179577547119957964477389742383246612250778027835962842
+8375378564184742787926400597138354486910116541106048723078444753508902260690644823241797242756355368838174606975331846084479482
+3212968824505986851162688090961261899834237009593445525206396148505570975743205626589129717163778397732428341839974826649188402
+6250784433605236331523177619946160387836454523224441645894992796160653797716355919979290100324224314406791061386652716371890152
+4400989435392530316607884601954369502551234892963245103254821300716613610559994576020035792556553491043544497572846045958494663
+5437689141597501417826982456539318735177994543195003033035189307876601341936559142966278723819207128349590261078232012690448383
+2240565515565951781099043148895044873938264025267367187036427905278273314523689584565134739736805096906657362307932608184624022
+3576329018410785775670826940638079688618282322990520892260090365771287681416891560096002562633570097542699787911417555916230717
+2453291822907103982064112069025122300625453433920178638265846617355201994938801382944512864303440296743023682910689965580508346
+3275346241221900813564939920509014369583021411699796257800366335780055834288641882272217012847000156622653258224710526325808198
+1761823047477639207496107226016946214853880512328754599996142453344143869395811453079561049784458849323538032761380820785136205
+2258773098932947134988484220635633194802789720564239663961212480883691013756304617477696306260192353528126108628749643695576613
+6833244981505084786837439890389565039428783638198451342774797405426073205683183254178026538685346206428799444442723636136435573
+9080842459252171303872018490896413638818633597602353810855257937546412235233854346618680040369752485990328489156699457496819504
+5734956183309699603857071255358660306282081929816419207249476965467352584050195709593369245076183392383809049796820142290983389
+0663950400843838925251438784404925348605007257769726864605575147487057019983649102686292523010863667700171976798290888401737766
+3133554911232814826547253321321519762370231796859406653514455605268584403622162920523841843001241629651167179835787795168834729
+9915875102181929094696545619337694209374642713183714372607433054204210229685880508097695696888633628128273726076768020385810595
+2987095117021662238907432053186678763052465613665295736124815230360572136345177452861949998291445717212884676001873754746660396
+2589155650613427623626563286829473395485125944790254164155482476888221798281733050713864337019212875437294907722695910181965531
+8195108479458493218118347693154287549401864008165971140576262020179031350059154171267408221692360825699802778787719114529741055
+2994227854778559135194271668156980433699910463754412118741685322605625614010496732911474348010716497147621915462772990056635740
+9885103937597375812527288674502022238204092589207503781840088970784707532373479354579114899440649532568358342845263798451171893
+1120400390759648596081862269355864764100400822617213332109125827310532445408926542692499006220714769552811438530408840934868695
+9637352403752939344901814991765254063329438135234927589317161742716459240954818619945185528105201605559036407476820639345279573
+0967725725520221343652248725994878515580037117626550685849684690414565200284452932891511103030564811419601323232328459974123969
+5151667166514928638097099027082126182546856178488195923185506331245117707219875304117100373941938587261574361349595466933901648
+3122056019614029244775838489907181693402454194031630939340884628769127341314464687448572665248434305566402372170442289658220344
+7261444332642187051262725693834547125915901896179000263992637439997458766108204237403853459573909864356641282495892771557042023
+6977452997091657310159593635773017261586291897746068707373152247429150821576531204588421265308077483457611680883539505380780214
+3922860418447742388907173493206552834918162458673611316176697519544920126038326376534410690399328547067085820148163398020288911
+4131844303372153660043567296613439825919900174540571926796003444468128320273120297033737036976412016725245066800816469650561843
+0565592489986925533018758592782811877964316768421296500160427160146511217146432195095933744734673635804950107620352420106654863
+6645406729317349776240373018557665618972564221260681309297356903494539710063100566543717860365197783559220679304253096607594218
+8395581134093404449211217585032937525052183907591091053649490577579801329664352206258963567937765723904612138153463659172391420
+2858367788679710677058155486700833423902690944634848842142528244040019800469662248189870722506296487688337321695524703236140988
+9562335938642263288699025637860876864417622879634601222106055965060418025394207515941236354344664880329773638937529679471456359
+3869629127425084307826072099872319475018151572502025420028453624372211412720817771154291359747053407476074728284771551844057529
+1190185706672366345077026144989614660307994733718658435474012628808621940611349704306495070342196599139286091306151010932970462
+9675509101851273861946201556462769919002921112388488480221448504521451553534147109710141587683279463216951321945573166307639217
+6672697005271871616738575015318763914957713525828413258526916822948066768551357315714715932196912191677461856418144576263544333
+4907150429612203297659855554908990742757537394357200499303314336795187732766056993269698914296065846201908473023132752908744956
+6150083396086150456609926582054844276634569272470435640456573226419822868710777542210573165448531019738194685407995076708226492
+2678786284405544977160356904372320894983311525398796027674382539921414318300162458602130818377816924569056780073177178248997811
+1585303840969268907598807940355932272770894001504038659615940425154386157294260258784536698627961267225191113300660353374029144
+4866449090853757246935294981633041248861600653432843768265539085865624263955878975774708775312072236190746445124355521953038339
+0619885412382828558999175920193016334591402367369763220140054897008235791975355396141026004273210423619062237213937060537525842
+8976484958039104695613723977251336268561215466702146950426183444969792826975925369611735319989524615202694816932040830397174311
+9564951821673710247264553143623225237946783695563652359502341538660577772441234930760198015851060420035149363908475167289811549
+6152784468367404157734119802017549287296220448855141063864170092034156049229526992205564211402819767239639089903951267480899195
+1084349314003385023967647400823528491190700765335630550586981662116778098851626565057148602128362406840285312235675524872617927
+5940674859942896006453306875133525569054425493267698876245403823203215376527985578976643008721792339745957322665402353157011446
+1029563432263058113381593903721587363928336506888785654392441615160711392515188910321841843403492466442469739247826795396883496
+7172639941661127457144015058984534581536740542737103665437103773621233103380626067034160263026558390443198760839727420004712631
+9914873013707039718441199896815680469326923849342274027255430706708553663676894461369886145860075954707988128252410758852549672
+1551922530995012072301491677655182006822391780785787705916872826260151900149221019724939267128249948853451126842232399605725462
+6980483373104508461112547210954800274259585332622017453698311994963928004018795768275261593898964198667538969022507330787533788
+8940619208645823836214853361748146283829606466502798396069751370937123229891589445495370452889766339397264192786388083894708555
+7956574006856378561036342289467521536334236359576203113726730817643632648603038458281607027513534064039819509732524551295593096
+5939647576077639500586029620496592494701352335060993013958711501324112331829653462612315976140447947573865479895456805542744172
+8296423959232512165579460974983453693457497491285869113279013506974543084139634238126476293873284263151589338438860044240330996
+3782355276288558083473518137834514003242038994143031796041577911531844210313799581374155317783854201414730465792201716701206550
+7105406465035531748842630956573813909293101829709167100331101814849787778408887961527614275809837033921260676349397115972110690
+9643615107680266865840715334731751157919061855580521203957602157773380969437003086918579100512932764454793288187949797876169125
+3320437252833110321043772044039248321368660878095814104499448998676046985620748260108371162632325229365624907230743947154301806
+3552088981131531046172808385452694435204741530370783735986679874877536428004908486014008409001068550950540888673128998784481805
+7440503329453373467657006789991046671852958451887155184801369224781302834630349870843861530093008719949904514151022786314021716
+2709390621195321800279652002200952192418979261420927427122958490897500556999549527116421814590121223682055231817153659082402135
+8861992826208042869383343763880314283402643395875744203109296333659792215641368608715044344315779183133340656043459727198349780
+2734853139703811794155039071217208536677070354393864907407146911703003457454092806351920281851834356124440898064979131802059323
+1762234053491518617088128044036706357776327020285634889111113700954005526394521483443227952188980642686375398780347144135711592
+4027397751732022026309364751091606371427768246571192961054471672221120559486812200168063013361795376094462318094221786026438363
+0392038021743121561693528064882454352142444617962196680006981383051817202169379782864384242280286939946138589599414498933359730
+0182070858522164858867574874421689046928982559988292189961850204180007351631664423841067686122468503764793368632417463823286265
+0700191191614031195459835157848968083002627564348814468750050055060620960050671214092145749062318287857521361265309131257106421
+0309993332034066779054757057884677047198784197094514566927373158826040214788501636945490789604082561095662632988383214277496388
+8146430655840989789550968117320096504739356599535135443521661785643633703575650679430439992282453217709233862686803968241138826
+7498984628272507825242938050646337866580174070972879570659031107873223367860364402212183428942145402115290592836227443279445979
+6978276114539892419020829624768340474210713091442435775100177879638010349673639613552216581396012901447719087628078745824194120
+8522095336564609176473140966826492093656451125709888847406519188859548795021576488451306844892007565711047730272408121668647900
+8524767921694471514347227180326839537161579546977834075174921433329341884828393393398191832645952423890037661848882505051151043
+2944580067530192277404349067174032715610611074091485944569506105415953050308842454649185132382815370040650599793085560858695708
+1141032332340176333446374984947231196716478639118202128308413932621313966803046203929215874583358851861354789012133869833074749
+9480985593249065406361871874582636508161948209786505592954264261087303579799611153927773325602584185048591266936288024303976476
+7322835259534879703369663910307964057121123765236316839734559189401161415410496300232441653039670294405632163031483814775087095
+7887660928641822340331849719497888363217187995951806289777062854449559129016492535377000453799053164705981391283757823729876400
+6020813393115291018308864451756852473844549771230553274019875173525511163873500444811237248088951714603052752360262642567865853
+6201967072308522428055969416019910663232530141827188975690227560728650829855364963013282370083361622353100870401742620986225707
+2869802657723987122733883328526226736949680510879014974422147235169606191520933028844627505009715152702759247026991603640320467
+4241131697918560404418795016499808486429648304834823604182336854359989655705275261891160035233666029073733408580774645759107173
+6464198087662041784095710258475229347049766003901523983606673438365749432588484287371422883288614656304912471987516429205303532
+2029089639113957845701115097046043607676790299218866434022020078360708383436488957906770062559366765186955585351813372430895635
+6464504289920784076224333417714908863182256990967502428628619515039237321418833968508382684390570422398059844256244914931448759
+6529784435502409492045275382927262616866859838773431100600230894559679830532230924353989524323228472158682810144077054469603044
+1378563204070129032409938042343154208174485755861395799608824865872543930138962034925792279431758568493941395394754047686715676
+8867499345143102872671197738475892292486346568581939250404454964808538362896520373387072413955104371842316500056740851235207639
+2274346030168140429762079586632175197653839654847793978202115595048824365507532766797058257757822432716594523867292474757570615
+8116418268033688475580223253494948603537184329744599083311334953737050247127839879240255833527455107807664847505065047983484396
+2629458032033571400314592548790506246485500676837502841162113579334258598171571921210523629971864377357109335285657941548264619
+0524276024669364832317266608416143775893545796330992023551256594493130557067547024156422646526989759981543218213803553279470269
+7049845656048970965053022592938828183548869262256486091586477018991837255857719144475359084653581143521408001578287580561915936
+9529610539570129132154472887914287431871889778678946943105713104741010716248000242330469610192173796870030679714772937881344366
+0545264556901297919417188117578751509627881737016436472816406518703771084849520268761391513510275790321817000658619656930708957
+1126630442325657535785952978581421903165028332745161812379117711348541046986438165712940213350699237254925482467553006850919218
+5721411832634196862603413999653849373180502518946059378586343176647830400545625593156677745062236816423794840646924829283523696
+9566889818345214089079695756528442838502922581513940730675014653702918250796815796276266282500947845827720283326159797147319082
+9317560741024728849503640154852784294588264197172188120649331980986731376355567665746330692183280397742589194244588569542845631
+3577828329965372354724624706136258680035391223875847298805321085928193394693686066077198681054782793606636920380474314204706128
+3316822771568615892652610314018713244424614540516258058981790879447066097870072989300359291800915299516058342141748356513095635
+5061676595203394978368391202469283356586340799916518917181619890218937093078654617621002548811013022192072875054917226111499567
+2293159175827100175340065081112035701753220885751903235819929349733241991099088182499008327172200193308932710369190557345577793
+7287877879088510408061450710486988984638957628372307246581657037353807145126249736162916823230146250853818942298633104586163230
+7832024984477944259180948598164959684871867948848537597567339850852013498502229835859692193114794153895539003144519694217709429
+8852158774260606249546637223424939759148603134570091996953512424441839401422606873114052812717989308319825300637980593162367504
+4443868737007280155976070920335648272365458102007219456742917706885599061474160397874769568586074099945991122357965710810304405
+6905794745598083595623675442819199614676323588131811003338385631872023890221085694977414242799825541355735846812034684719203047
+0457011399186690441251124301781521567240706876614307067167646882762698974983127872249705063133235031055532098528898796399551640
+9652581539551646223682272835407450811885069347498654352393131589816331647166209087054200913809824196442611900896852634745826036
+6159069172552131589074592658415752799244670288018595097465086916954714517572062029793973193555030320732773860687445556056374048
+5349001165930930982732148212936887040004758525708856986464739067246746909509060364496603927468208068059374896651091078566710130
+6254982141720413268677308357696628123925721390150502950572640806864637896561429156063059840807574455370484872143372214422469569
+2175489787129382942852202790241971823638922108920609980574885762787573196139571654120370722438096597478384547338469999448759583
+5779677161907195059713244890541696081649739347821725617254499816041573948157136918495996244811587574062062152794567408848302587
+2529817818204143798110200493373689828340608796471631850589769739013205825657411890682974212480864416875107897957894840172709126
+8663943826538718474564967927014748693701498556781723819074861406711142155938775092841806948205850959520646877840367557220520678
+7792447422465445177106699668289442956655097062959653482152033676820332098951332376110889269353539366684304599313150351375802284
+0121046685822850120961765570267263832452267770816505513149214924261156051159905321694021977473033018289683251782668439030324894
+8869657128937432079954235872959567283205921860119040052090516147170061627077989260167387744379514761600478703309504193576305611
+5381561915778733491108127139487324618000049052071735127115368151009776782599438434551832876965146125033956869670863387976299721
+0949362683385697791271115461446907297573048650262795825751967646029677499691298037462050809938530416641818484223928338242122429
+9766820839983470977275951789763019956067562051439591397901411073621068841669094149499180916451056538781312613407170881646764399
+6524347269748594984863393554929474287488214701192085748591350202439606866037583191335302568028741994749726846505035406608976877
+2807315518903493816008029815670675803410749049697801438415798820359073479308467800153777926573033244523898966885887408576598556
+2253435971693966005243248611373406144205306206628977772254035623423592393288603285157497164481644751059433660694427679833172764
+2802621839144263944769655055452576122669485060013276462140874654840615169333830556593045220363613387004343762888697682047116295
+6079893975072940528060570984236651746363761678873252309931727588216926947288076839743652207728678149523270862367475616321714661
+6924992946415404337508448250054422067066309322273329866764351438985216249046429085623842949432537700067268248539671410894502789
+8240333706088312915806196572306355577223650119535205051323962302240268709606481125217437426747720173549677961990418013172593155
+6781963827534077258276934309689853954408488415498885594714929736965951139633336078246485722224486449322009472875775669311469575
+9358007010281073437748629060353526682504603164238126641900438090676758229061250503441387135871208008336678965627603224246244049
+5356708068957856933330346985639541006539430131114293957097055267024756313531830324556261486697384925986987181884646073628504968
+6088781492829096627570053299366443750840538654491246720498646497885473443660031433479078885663560146413659899024021823265546612
+4698755327188359177076358836200498034389012684305157808211750883923932482111066086636126223845187785757048164121301047675382008
+4187475464845783395113764420886751702440050366103999318308171948006157647282740757274766917041519563322385269555023048099709528
+0571195389552617367126852668538451980401879674162973150705011024259186076369903231002763667511763488135226006543931654677750804
+0619275562362999032336486727097255819748979447931027384044606019902431591438640635467977566427621673095319535200747603235302696
+4867604449981342383768009732025809614182230646572537976384930951101533738349930256172344711040076994914315737263468451025930022
+9527865696943210023342715736597334765710291291516121893348495349788313734498145749015674214471321122949483123539062028956769641
+9765176523721839937410174251025970316488964877877371126040698433360574265827174483074565633308845572364434646203497713132542776
+7378651477723436227947997821691317672343016210083663443777377182287912898006288444888091959123188074922030160615537818420033213
+8447189492947088531974966589067358589089364485475991918412867217338548681050492469752464750298772894247076136639226285280041834
+5454360318746876235873485912565983134779435530640178745325450114100396790737296942281564432762776663339965033474759509011312252
+1273643557029602462258772262515086262035743506025601400592823850215645680844288819770466248021756708616474262140257830085882080
+3749316335624058049683001015861489646556394155367973498744773935515065243970160613827515488862189910777219950612111041830333142
+8451480666232257772267491027370674681436846933893722515862731717525412660342458091112720313220482317659721562206466780128741773
+6590252632454850440238194247507400433748088629955607174486085725118788995595732312569896819608944355538496441101640124949497789
+1257684894384392174484251124503854845960148691603301944875996738800826596693185375085047729958430171553740436704869195063748372
+5735178593590752060263331193146970071579446804835972630866651058153595857973419849597143669821080829676089777998056446703836684
+9360907310859244502541304513473974522087020370096397612021384703925636952795854616525882877878108950663963286923299046586524224
+4736748114460524678435616682271235781989815828869520783049700875658488695718736121600271316948975177628944650186309894116256839
+0122265134749874764508072046641714144031116931952372994620287753392883858943809994533079487667165865233880719017940897178306317
+7314139776044966808676160030164847624119585864721750026892048897546015469276703858536945215709271741054424782569701147500084232
+7758065860697872155705967293772173137656465001477901257876428931468366029449777184812467116641975319314916341175480998066511678
+8213787357873005347083763974187729721493820664650580516006337664286359010259386041876040802392491656717630783835571533641496104
+1539726264552952565436503783866624559510200362458151625173082533487696535010112807775556729174429917223668593210128877186508887
+8321470309679685999475535888469479559195982218922599887296055650137375133750432460874145869352229391171673429325865805622380834
+2056541359048531447828515960692963929079449940672170706409337197174760052966541653050946881379320800572898168412293068662723053
+6860373992960297640329729816572073853997874011764757398797944036292846733897735820446934726176024024757470895603256455220029335
+4569926110072668348278664329257941057438032693980297647417188505086076585913708391932628924011735966680243663432137597450444007
+4011230494392556854932236273332089389934747612548401261998294903567663125297736568382740395489945640372131150054623072337132335
+6844595318925439547616931848005923901307170686601327728283791660587722758968622818978597514280133292570491476960507397213932185
+3642313707941792113315508020910489195204450745180517492522873324890987317406946100562361363175345008151634614618218325839525506
+2427692898230648928178646301964171781644216637535917410571457842164951317391990752953058484915364895813865613835337731245388877
+7010431184482412816244666073504621100130866578971286677458525711336280431605171233723698610913008947422033976946085031938114793
+0877515916454772093488878527862660314336276524158489551235818954456016892617227185085470522620693855915519816376238143161430319
+8799443736799287358483938545063592502641553678820618531061987381595925735003006045937462381053795139314188939327005235192961861
+6759340733723316487592044207138087167698990178309899096979902164464364089126370344350744470572331313727851480014896363857798812
+7052560097987652474276867365814450520379120040581256992867022098643876725081745248682691582583629292763400638018100065591005268
+3106774405492401515494177672517042073837303505772295474776502959089196445416987270369786947855131616223965006450641692994332025
+5855582574286277020845503779828089079164761761910842413066849248818854888626393445367304058754822066188520015897444131019700263
+9198472044843711981048071735258326011544302082682349755642269651044020224003915379747598044212429909878394016016714106491656407
+7815377808589332772544290119723706266101079820396212755543706404343739006942558946534655221133089320660150834947988585978442816
+5845893139549225714132593150193123229669033684893833205775336633241518807901847649594321897137880458298454663559120194776464523
+0400879116612606005027575801357996533825782630360057558670923510328348895013335023158934967383007297478557740608358705255176983
+7266683495403368714481550525556638200455893453737443660389337826017810731088543589057015038655883579293647540385262180527785917
+9515154749550773405200793344557941722519749405852747512969927332977178984307036495472318127241347248808326472175619457986406723
+9518368191888409210468669956186116750302181387390597344128917877355951593149853095697850106850745402883068932235000062455347402
+6771238670568019918070196745624606843885430053371888544619960477580892136283363206743364325496202732003423537704812210825777485
+6482929731992099113054720411204927077100453390882438863808021020983016716953161187024589380636187873278841457216002930842647147
+9086580408882584727439595283961649388079282398490521121307077379799427026353954996467076132654318458754445407020982965846766574
+9211933498567658239813690464315557516873798138696846826984940696375072209871675004339676866312551085733908702422475770451671522
+8116601759554721517887607233127079564923984623323605008410478991117346586220447102577578587384958136197341044972808673740184098
+7135146663669772129679997894669791690347234150535985440597324857772792781041329129123706810764665585549577867626836104138395091
+6171338134734949666403237923355751356314985925381428193696582138260452767497882006262979715518886220518431969713213052164146287
+0631430030464172255146123719714749762611746753803707576735960990848350628824677285326419791772891874510486806367078208015683527
+9792995724212035781617488647953282247761468865566020082106220151676123008979512284726786406279413459522157229217252165905352918
+2536766618340462486482122665210247152075138704341907443423031644884751559830028648873890163595496896608683668686938870179657834
+4207985050934314372862959059606329918091261977012574425026916852113090691158385845006538026326042605485030114114277066770366995
+0403083121980863784638665369135497943380554934143397132755814677874063414921737247611566476833724738395380308234640207731607371
+3017035318366003181883008020161130977715784016586015636467061595058652062869875350107267130020471568933409734170464250203156306
+7978597058687788859694752086622825044743069638461579429486476003366615826282892684888720644513019714307671128574626623134255754
+3225178060856930853571262377435203804205020419212526191171244624283460959473575918723283729545170705498401123341048944419740415
+9391613362743685159686501403436221835235931626375947101387495019232220333271032937655938586143908770909065649064710101953494614
+6134742532053652776330925214492259910738874571044952830222662538392022245336085949987893286559101791675451325204933710093660895
+3150091954112952712726674404458997796890860249938694466648235513572474974162093062356467502005784802581269257972393197375619808
+5518818055326965608441276354480052128774778908643152331498791242682676747511171669510551698928872813137576082004507231113018234
+1869442353797750668263237704646436989107574039444714294394574053634166211680018322567901718394177095139221750525981664718345874
+6533895638718548550755018968962814261467954303937753456123595613702977896395623181616704065331577434094624992851719491928609615
+0190398690201868871739512766894228210227318255924906586297140986714101681237768762073978231156784378903908446734627746278198818
+7031625744207762150055633900029138852849133531239672839021846058540394772383588961074862090538883314417964060795273709151209027
+9458808924606129446923894166510777560369040702494184195952257501705875876785777050661631817125173124207320372163502777664965913
+3571992627283246607384090417534713518631913006344389649603958134572814682981286787015904497353080342805307719694940285614675633
+2468021847965102322233545270789228088801077254585303970545296705237224231512698609584385993582329483075661032700231251161660423
+0192713398720255736106913269405387578211504390721637672765578917354808072397586108294538148319234789867624965197532780016350565
+3634551422633123938462201786680417505451646469018713382722643171537409460426340292141021655461958038710203141816197429713424286
+2547844227738650654059981449340163279595536790994781981453043554676804995664853696521066106987131049223085671186846778658607485
+8528870512517578936416926762107480564174061090150629794502095506665701012457777925443164598343164919674568006002249856403680494
+2627259489744462745552373437029184782032929858142986221112288622061305496355657681071521590855144706970497835664724912122006599
+6545391156443312660152544214378226475642958908136790116192718647739147551525217967757101506789062053773824320749961986081365820
+9807243716856995753119727006541625638999515827040154011379764506202860312616961954158869599676568905867509226176218277805150630
+2073942766462908233406965969896132634247796801676354098426177499898295515362604488579021522583028021857262554533983809115858178
+8347131968232485092731301472083865394183193666260253997648555077371404915951205500140212998582177455804377214724298329527661383
+1594405101691517143629153539833183982495777310394687166385933138800061962945009756356701243200756906586574077923344666352145020
+0197245967822981167194710233250484229803417371108743341686105467298388178153158024123847938905011673366872874417478036778662336
+7258512385396982458981727808434299320938547592708453258132441101938548683407696744955847650770224320115020029123283233005466171
+5842172497719189784583681309409508840094316855599405125810349460717428156132068389884811129531014665690641559952450142631134435
+3120882941134196144363251034342986015603525881548802680508329909569735321266175483509995349121263055144465010373367684170785550
+4158635639323481056067212351252293942485312028596582540399759383658505450921291350114073361212206891492359937785370602986743900
+3248674367436665982259747983227106329784209726320992248877150489251570771053020539956408865849029873307934125408634817191607873
+5454247998356721456240658773994350865596498454154991883699218368604475173834985657275975908620474089305230670921518592231403386
+7351062162946891390363227270397968233004651810177775309863584286429947693132180002624305405957468154601633114090431896806560396
+8578733043161456354664012245929168398575757646163138337526746639222181428391936995137008559247216584486677942670927998985802859
+9200314360845834380351667184778736242928721806415925103242410837162869501355174790557366226463713207146043374288777068201363073
+1884840380691470035098733943006470724355475360919052895346183170077857886208887006329282319454011758272954888828936243319780379
+5906121108044999002595816055500975401842454091232971454535066145382445630442880279299409925299375855072691591936952415415855608
+7427547736672177870270669416923472904176994726042270600865769556468182342137641250127961474267696372215125069986572926580684930
+1283565631209283359581543095011894542058022145233771315616803743285668523226044837411757706026740916352039927306329889089649349
+4270078841384513763036784211367232205576108266657423596077336951308763566593324577257390215814671195914760219863020884678789417
+1094797252284852472558752948074017934025826602284347674097641546447667688812462875419412834529814608042996511263599028929742238
+1967645060681138182820884931078366878249535027007771792225806188604957386423876036386080705880427884926800392921951044407013636
+3181566611581199324907272529442720663293855144200609139564151757908337725071341353176155541142076746946246524270499526229012582
+6539374062743440091085243475167651698361455560983223707251591133463685518000037795208788191244350973724875956194617703899137414
+1430821502040369247348912270128694893351423782952149316135243013570919313886614565161358637079094402119428463930234964822013013
+2907845492061431274313604396416192334514224786448855288597321564420931438182778758210128537309848899766746069430202195659612336
+4975634130177816916191624410591783555638901610254745557743055701024321622685828565315892206810167787457147305784539222040470909
+3426187794037654633853814952285180680406547839298481434679476618025289610702493051123252356926166123963245694601391065308079166
+1560694708414872555648575097110162943981198563540849019446854403562264846931619983425916923587136273462584821828465235074422917
+9261979271695865979574032703343588466946379682055875729180379739323087400969273393174411780309814669530363099378105348978942035
+6060070323917526453062047842877465074776912567111669196792162790002591482979059554932579116312700674668070694919873464603223754
+1894071532823340571620020715489409265478540234593867913381245139145940908648942949383027523114581382713294341230059675979933347
+0475001838386962980608799805753326787172142674741106499743819708928855603482127536974433291922816520616537305575646417283646800
+1407873654137191433607314317494815145886982224527312502679184216570574189580738684704012553837521804108283635888649341886347674
+0746298331021251518403002440748995086111379224255590828431961727677994867561042572035686044830391992128329363200090117946273786
+3394767633292754355096521352490384715569381533683416319072637548165685703657478638050012390155682264692286629389917053497837436
+4659095138863302858042866246863612004771584058240848977405503610643181773657781348444480569875240316081167661626347187543347285
+7911879124009359945066105568437670726515538210712672838972140937144499494198784053146413298370949806905102557089313540518536047
+2387001299041180490187017325756798839893484841126540625119691321202951445764540357103908077323391792392357443606419429134662703
+1311387664343269938420538390428981548672980222893983525849983661962674897972783374663857036358464131799985348402057774789061484
+8274461005931054626156020913275021215007841002783185917701579638808358640962009486666957046897388731341995785176631521816719220
+0104967747699292212229371707417874791998945791320492326714053322534677090261456035102963665329391198512545240166335302214953529
+6438295329258114463806507486440728873144766916788136148990852634546220929994618127547833759089567150425084541257262887419748944
+0763510822819190844430827630471119922358130707131670435790654181644862502449964467386506947657809851105256327118765427086936245
+2850131634530202363427136221800593088389014446941597649063703366121196898996686256705732620416208851855006823708510518951595042
+8751603030878422139220116631069675693727662503215348707642267571256820475012856064445690912370994140681017385311381651837184429
+8337808674514385942347760110022916345088925240957432454452424792146056100857933925448423669501901023480223134384961261737051238
+4413770733662528673309544847059059161282542697670213119975814848684886926540572546980353008826625285683672206383376561174283585
+2470179376522057019705141639334564346002921054122405868536589549939044185327352857788406922050956188186959812914331458433168181
+2179183768538040087965101925166314083741211822328135691819236749579736222030235331381929418960851621953749706426251383153679388
+6697638737127992949029219495456980219928837272379992149835670720157263752765848341694925460132961677719444757263352390287952092
+4093217437367696270862739890376907333913414784572650839225342564140670817115158483271922969611210426005659701735005263854191680
+0504868284114293941201391805305848644129473248052919285116546768968370400211720819698688057290313111673099410825833594935299522
+2193387285480585675810105037896679125123370546559641586098343943853768828725430307316784909701983568646060993578149869405653861
+2934591075689506327550526527978208181872636707486069235044785075612292358262482648814374144402086535106182407978781842722397427
+3764043018357659628728101790307107498150768318990432916850503907920600389618490690749145152636599605594698036095369786495988258
+6957155927715716313765479257750780421880426026172174055737331392383266819616843853222801559499877374057106670897236097150948636
+5427827682310804721340200045877249335498355065518235785095376215323629999016684789788057540796773407165234965827360566567682463
+0931247633662980846735922260231265500967979148521116776842985570907612389971711829938070907548905323760203422391349321697221760
+7882789193682587165711403864901445874796286061561018238012019307540878080647271091752229028944021330264150343818926048069144244
+3829234846305757977743751433953176195429230057570537421684266250781148509555390682508579644164157541082064669789683815095364787
+7604939164496265670478495045765555257915418238903189606069500034604107925625520169975834751123093859423683572718773062691097465
+9536565688839857043404968751102502068918401627692404156712144798677665827278179931457967293092502383995754188611043728483106278
+9597088053951878542145390264364113151329590157432302502341917977233379257169202042072712802096599668573120272798291944153363375
+7607153187541747861933137718609189822023639083176590969309128534131402001720049300131597786926920331444518080594310667529269598
+1927075329456693896562301483770530596686903351047943440879405951056391325510081534440975417269136288862213745763314617080452571
+4793088300460286258221203503876214260288694619740795021100096527276740956582412254816142704747725930689538001063488725674114094
+9964651944235263688993656306565044507502459642744800444126035956827838480470927964887269362894767336619648517065502062761621016
+6129875810846273188094595526245494198400294797450838878997940481886389039479255372079045644823922532826285987109316717080651452
+1158870497644577891842220310991400298247186591687353490986090963675370236688750155704648708257105452733670085922368068618952508
+3951586474153083065442516047977847063483146004542723388081748533379792081337808607910165722930346295608653437371334690508592931
+1348798137260798951844725481726752185101778730990513125012632961668430932041485231492712161518123487434868038690945449294611190
+6621726374054578571840509185550584952608718450715584685612358931363303426238432883301985179247942967408291991891183249754595852
+4638603540391846589823234253913403535906012903538328082937776681713183362324668976651509798060188640593955628086698902190682737
+1314136004568121579468174164410670114683609747309631647110337083615027244209788221757184880343776037559026360829925134683110860
+2743916110589248861852284646250771021137678508599837301158835778690463663553082493519868901155377573114305779992715972859595723
+2324106156194950900453760356879741607730365869344607490682695136931314492042609961479060353962654666877592314030242319785217157
+7037168535189901999950898708785124945709252827963059451445136357835564541820565609455192709322939082485154440865255543678569770
+9896528396971770400160528156211153078421941311469208430939294234515837583618887123400678449175339595403746664662044325400329517
+8261684885541466594581605303831216257932122772017718190045767780517645346911853652853978624682959833140344555022435113362676062
+7591075563360347900183625940068873872381827943795851765368024187038497412028598183964746465300474453614206176090307713158346489
+3374371123832409332000144159517441149498304308931146086397279524284139118811410468196667079250510555507523645907234786379143531
+0501327353064942573752656984727083020738199901757943687656464477159443799349546909245912076525128236088399431523118269843367482
+8613396151458427790408589367894556692924575676708650976493092298687011565830641071449135943255849354462437020422889320020232241
+9743887743932345248629409670762729564753828800124861494449000192569258881214737190612239921652995520457700328791744959299446113
+7181302058928852380763877100101757115044093853940723929209952955676211472249441292704903663335543383186649963257659728968301134
+0388255348661563721653151594456333702528830265445870529546222473972548233646402200780627751622560467191291529956825231887562559
+3526669851709736895997935055319638614407522325558293993145073133898821442020970359820377176459127571138998803488194418913023474
+8960318055715147737928173496291103297340011637615159200331936657806625012838282253984371770704650788787874077528191805071976481
+7124181681951361717176138891836878456339953961111533220751215226320942283255447821785246102801554680118941275936544271258524058
+6005709566240667298294089625210827175355499791073268532752944587487068732200218887976443970173147332812756704491687536620579417
+8523733324824779870890616722944885692254782796148238417811553337420218355790067774624307813310722411932853894530043351212104621
+4208314480849782328920489549263981924145677154566910149000272410262683233827903445768177081248117495913152923052663893776265183
+9942787773857699223811513925994334863462094677096830079955240744467436994912827703793978101340756041298804409547081408298801222
+9436460738640015479585458718857778968516432654013043215917075749663128588920464616671554576564466134592276012302780087016944245
+5682263919237157166619832653999221365676490237394196490562353201595416072759662040168607378605240879904649331264075658653944374
+3188760460625654041085468641256306887215807672289682883500357801180231951265973876967365453175824452139544361480252271534860563
+3489612971636788170285039991175495323686795856259626029428439316305263410995491370010061781397716962628385590075791887118786041
+5311327330508694662530309261695611418858308192623059112240071130884198746415297821301302430358551661316850076909001762997643991
+7081644935973288072050639441580584025029531691351232277986672643518925684337072256344249262810387549624475090299911463668556533
+2269997305729536278296569991307939885225827949212711278683260974334694618965859001446604029046584493463719653785353337281283459
+5669018591396191702482439366148219818778884802332484502882028894694251543216632761518648364549018220678109701293026473478656784
+5216611642715035439533559692613121139357309471021194983124318134640525984115565217254793009252347891534891058775512107043759248
+2075136627102497321632846769129196363043810766007725332614332304423370092169449259610020916402169233919813196199842388493441962
+5246508710864902175515674209765293421695856922741891032048768583212886538286815573096956696932708558353574597425799726517739782
+8036312671737074585001040104552777443725646270711497123342871845885341214930320018750607319709014145767035316932229927380726251
+0928548556204438876091471205246192546298228533150898999146677973522875037893164503792472130409496157160476844265385841682474739
+9233703771903675834839283547585483443926383504808637869079921199402511859863654798938168359018632590649252624952570683979540091
+1817221547279336881324191918747916105439761395909101897519754743532665651720607836479601826466707285601138161807075561528644357
+6507813758533570073431536118758351858756886547831285242021547001802317103965340085013359438004591048652288218222633904693766526
+5939230267672950104631374960137514687520839197558900123956846637455545802654473302741665702939840951606373658402834814254928601
+8899091999774572904211301414279903590789989799671058329810205159495566404297154849221520843334449344645035156970528552300030222
+6795649886498390391442973828383660673784035290138239807079635557460618362207456840361649348840778636144683493328779008559160150
+2312967328418841937893181097506584921132253955130661944022425054340098558673444397656011485902801524597729549862183491017801616
+8364392130149044788968141245875416756772094094121947877022476352773253705820364822300001844264751712000950605882778006252697459
+3173455702957684349309232875767407323242741753471239292204928826580888927330167241766284958168551480352850879501139241966892452
+3677753858072439789438100033278254013052115660199724677408997086225534466921024361672151595117485386004966423349406051295735713
+1033555069901179500855772626876468463729168610634688507726870943003645664213844575844814874933857419440136881531279514876328051
+6902431911053955232595350941009434993084829394137562877137241909400659809326832785642273291709998822359902244140526746390924526
+3598394230231172238038637497155035177663453584383356974229908339909881383831792443286626244348781344679035766390554002582686748
+1986522033280153369322100953745103819643767567342601672718065640720320991063977205827436045236651592119137181084201370425284749
+6005671239600468501156161076186950720461257574394357624099400895752471978287422522141370855745760936595412914180235254380961690
+1248432656688783102677099988123915947205672369413239452092262942922895352363751338938332396260328925306803441684111264080959934
+7043361968005295354938534781857472787124249512274641194624952254981027355960086055922235901916884500390183949326239914435749876
+5900769760705257904732141569222453308536443186947518812790214535222294555869866712002026766787105689583023017833746154510155688
+5602689240796761919744677404697558271913792067417789140292202440216539736230658588620970781000844620550456371994946471279052637
+6983815257060123566373254198705908764725007305820906210985164414734561111049679088421536404461082246253221142258100082860407483
+9787291977224975917546280204714841440857941451156318425600052380180319358748436390813045531423344721155836168161085909646309385
+4242317405737007113338681399774018133792533519976132559943781717607228562711266632582303687475696334211416518106220430942562440
+8001103370755032373531777436355301854609759653124445242732075706459884158212645376386153155459030396899392086527430085304137547
+7061352207839212087427452963168038388774060848015551117972221521512460122751953993512403134647980990954916284061921026824432536
+2639034110356917513777636397443311536328136804898636889890450733741495575783711662670202058347655591164148410498512181752116112
+8649347704311634713230582416874077536749261618798919119607870454970552954421518115988625118329175121493449500857931770229652333
+7998158841528743978260913418602919615786831528127648656825638874370061930628233997562266898051264651939263641927874506380487439
+1169319905978231587648398211672101766334393172127691275996797499245406750863796639040056909542250284633880406494091612313210866
+0317572128063301907416088057966656497607301508200217804677889135103287897506118599601843251561058377858126583470533794642274814
+4690147674695890988264540020570125563698789420115878750835681272646540842126992805764557197985389253255527910197264650144295636
+5798557941192958990661384529989091262630978788566879170732007097819131006336590152363030155153413704404260928053167322809868601
+6850987001199817141644762090308087270676753863496477045191783385382914059759989907264265980509298271071343239640773196627310409
+4389027546704283892663222266104915372633460042956234973983464977451929104395584092104280081159181521725125037452942372440981206
+6675905477554320026243055974304148345728455542853879050278442548087322107774875373656985055242105650999387599625064478196226162
+5421451962648003632206646262643905337837657920982111146977004270602922886008501562566012949545116457517171981566495094457953170
+2653749527617823956383177123455781619052217065408026747322738616321944929384445431993242259268884094539560852964142946672208945
+8593461023191475746268918563613277494098559522521079968069246435865433845367704112809898386514701303501214965468624316127309978
+1864190494247307693037266993358200097794635502447995520938928657994547718890764619887745240985736437934807473704761456024575292
+4959121097171972205063831718099245216438006228886790229146916547085014590026042332430672777678300137100806650898573540666242384
+3655898393459642632004541036291612193425851747783279795401104056847304510228417238922574433467131806129145867390315264166063875
+3665579208506648402815517926487551967245716952452342336509872884242496327353828450388024010049265610889985970803926589219237453
+1676400095916770050334175293677803863116549153471866784271105726012628596876429530293900006500470621643237024986843048814960581
+6303887230138382981362522022235864197895867379102358980372057655831897690287262572451017096062107356032913949946624176978299116
+5005151176823509060156202781958197462286719252108370751542425598689093613819219880986961622340717811406826396835254749852492414
+9810879199072089316354376552239141698257935918222963398002559226752773027118660428719265494441568442234264661966547139854597318
+7873099218250455002270603753696336287379126088262705830929170584620542532170428705348694262962278699570554235741942919271113853
+0853097378201921331418681617335834926523454159799372408812168044016229123296540289846574743942294543985242874224122532498334672
+1490594866688679908867416614545427520723745911612132408696699789261886952468259502210832466240663473598353736119026236378375966
+7870513434223037902717553793135590258545562641705185546860782749440609431080399391577848963291799745623426666134231053217546405
+9446201870461219368892707181895875357863356844636097852807754420432074309846001997057609966109454410826649254380546761753175861
+2761057480832813584246237846523502525922933474798627724801784019360724008460215340269094831023982649184534291701279975122991786
+6747259709148196213568727070749193520741364779274424639307959421349714799461578583982498969579857164144199424813392167578660320
+2903178417498559526330742642780679790900780361831699904848420604973586382034364851787093357442413598696765925470890327590522104
+1850819839601928427102795504066478105300817488452603819717168073205087377109510653761519361878295067555599575161123548496116519
+4527800014440544203257680309603709183834604758224679743597378438522340853371773245388147497516647805604078269186299047096706230
+6498133304861002880698895980139890714606455707071690798907848409609045542981039802321508092873754941535671659985239738644320953
+5988405032666743320254142929561597654494413403431947291535930103688912359712380841156852022207805099821357330225186728532082090
+5547768444839618341918220237864475011631317876613320699268333350020360283617553420136149953194413589978795210753934389762807735
+1597329107893662665482951708145282526843200385584016605115945831916977370397498490572333755725067314085934032787782477551454989
+8425608912417288932359069001529317862434139520899814966998471303722622773872512411876898983545914085663888123444680470167948505
+0434379133165396213883414761877309648582182115178764180968488658223225128338783723464562383576437566308911246233632408447704048
+9663996367177301008227471941256368607999821009483324708241288407336982656214907935931597532047696000543001055538357367423684843
+1080054249718909513852149584485289714580193379500564799748250805755830508642143351393106365614646908548224506838553676335276275
+3599779694595660288226660287150289204263669082115248096828431008225170485272045909181946378454893228880239576553739907190878426
+5885850036699891408378122906193395367309415591691241926759692588330412581784093438940668271882079466692153184239937668982303474
+7878175454828248795271539884473981581982185106585811627218428403581816331240364769920118073711196193240357920319448764087086718
+9383157433735677366088538314691739001878394272868474296524756761536638899101995873845026009993980779305151574599223381548532836
+3668859832227797331952981131294963911962283005597571432352599223356213488863688452877543275627906341710804574808946808990599277
+4561238331796792049632393877616772107198692076748218412457533127281687506143050581347703755397549089646358464889763941628738646
+4287040673613995225940479030356811166110299081667864088662964809883579567473005653984288637714354335572597312336813053771357145
+7067167172790181728147512916597493867072803164173683458648511730308061884633961295638170464699169569357249648229427546009552241
+2411562579887913980455816507682929933659712945876292627871263596090842188654178242939374681016381916432972311121058175582055725
+4171582020877122298082911042822107332503076877376941726903575210668249614607891518640837866322224789915987615341840992350582413
+4400620040237405249285698955673350511161843009038833792839643496604322064832266848854377214512824709405806535993728236489108631
+0795420398459113177519012283723869747981824916722015034363766243369266801152099213940570568038081676315926730528271844090048984
+8736235449371678977947912073661875499227319547901313273871106645387069884378420956151320072268281471236296252518071417869812398
+7190598905022008877003332225740349664805580192380729307470319849086922459614014566654582713365646665851557294353631593510036953
+6381552204220558217529826167930690334372579521383903206328505035888174852614555542283456959315756641772011982607288085297853686
+1349874783384878827773365548625629981523061054390679273761674753812182403462337719746346989770142792526923785272095298042279054
+8890444037528702976987014556298735324481383261103576223990679497009263015064472090831542516594399577027449370238294863246623636
+0336415324118608522678012840335823229090847361254516690870558705257294993006716462941193893800422308988102399798523789694443112
+1923359529945753787122624465725573807149022119989195390997561541611804328914617110055244794800371476974622186846094996027068986
+6556505900937451676724626863029277508817962303859724405355623034880805936586542708527460464895044273023827975806326940478307069
+8592969583414428893231495897818982129258755657382413367672348099201190652878055544751096757376276397486791497622706985221853529
+2908214067134856191896613437551307015999440525676444599333628882928075642102806483213033250837448355509306721853006604031173677
+5140214739575524129341946985893116412008106149871779041808900801409064849278864166852383463573647719274024968463791254976359299
+8847571119606652336355242986018768524604507411735194803338041421026584303361841828532589747052208612636774062068296366532983021
+8655354613872561646045351810915955927958378666435016019460717328781560793954138282423423334855186987151419088975164710160358441
+0049260799204162100696414303845623303274803491195157588921793903647526766706979672202295037308810197036167390246126788340972486
+6425819895447745350399433314412535917516434906996482513931003678441923085763619185652238830813722611071936854791527455947241273
+1522067822697883751451720158852174772439898925807262503934468921130385503850561421474472046621939053613032754307326343494446468
+0373529669975958588899685583408106767873002561071952257411549791159364132364256139331134266337194556486549929770686277721381623
+8699593258141567800940600698126100601323395696274203924322395263563919165964829715731584976772134953809087705318959395613991572
+4912970610760196588068419702343479920035578132234944550622679160245214714573304402887577273891607583288099465093463035431694610
+3905758432785910691737893861264914959634002377051354781210095863851654985098474884630562136246052330525659496807184083910344772
+6004796506916845030772132724200525430268203485146341239363234592583508467825890468047631822102162429469995405739029446103026786
+2936254882880449606977442748506803270167246097479977977827447584435796513203817330397221813580364844509174311882193765156654656
+6587840516915974691152625347076034414185867253449830309514472874859872212804040804281552578684775759016088925401886242253588410
+2136162082678649695650433358835719979490577896244051036608023014229544782516370023231616157535453095718156293168346470255374077
+7531511647981041419067438947595659704304601529630424537788677553031920743289991068705064547597248153946867352942473723492529159
+0056165493810107660174271077633956520600765977621759777545425851195592595759244720831020706108951012298629188421930844092200174
+6642191140454110070088900972029229475358599582028206307088525106506003848087788102905904900131739063517620939825620312143365317
+0312737363283798477941966380713988316123472457978241774897278441026567305606285826664686434652740990763564567342068867452842418
+0562084816143782025599524978888894444210155619376771675521151554796594041637061218094181094152665322539245369886205219847245940
+0029405789079825038952711651290857359659229927344229997950428696846444420150303484487905236128836752670607196713086924265912777
+9562937968844743614454574043893713056224816312429825464738549426759328345347674841205841958347360767579803402491577142236137115
+0533906692397009484027899629862953135204910641799594877569760336943034406380230261140675352675702660262675371335224685084951739
+1782949915965578201764231201307179274400901440982114344774078855036237671988151622145580473895458193522528339933303018706591388
+2624100076711766326191346479084275280944607050965314374143191066314104835834695035041295363869510686680641979042639548470149337
+7092183008459177550878010123635992307868170928762105253223870251579666192277376903965022436031647547645865700232025464698571152
+3958091554628717576397311569044621708700856680671753736603162545139430701751294444844592994780440200375396353670083705904818899
+1158314027781793782715830446196630725174972102720930236759032571130842037840584037988906905557214975416804249578167992887315936
+9206031432141826113994005343808438088835006886050009647865275969654889753018433197685269199002634601456210696285807629459472336
+4978328489062061200804108082671938204870858983057488740461332416429168822452529945581949038775475758752323372301506063733079805
+7738055653647518591404108351211994677622659177154884456890162864455435902069510745121823508583748140331565330826498449431014143
+0674653178829590152076432119041481195951363053106794226287750227106636545367810520707295978843237959311321898828560534345440055
+8038620990007430479290370430002421271720574168054663731040351369363896772189503927548376910184417619479114290519008175905383545
+7118330213438952390733597389988833345665275766596109498963112726494459652684601428898616858980054673653547857404417055361966561
+1587037091185968630608431240360245295772438686943763646925036642543820946055469856983284464996007864493360253900748905383563580
+8745104358873817076497065734218673552778861792932465886098953358042048623712145278501699290745480384052380874247143800362538370
+6251997645750683187872814541336341689788360883547457593458471177846675162375769376759272289262293759496680413378317765946726569
+9307054144320271279835934039640502070988256340708987512314880763049398513262419383032058404111149286657762258132166819869740391
+6208679111601546062938461491996426928719837110414091479969117767614499297075986816870114797028327349760763930021316392342344670
+6195338739848107103644806413130142942032473433624064988762100818410644021199176248704887358790343589713845228788844183335779186
+1206612776301905227273380391656909985775786692526546380296204581461396277505352115889617471623174433491331255641939009226704644
+2188221413330256108594133828534885890151834345250541767462459786862391647167810214086311680548340646481922395107065550293841987
+0422053725280997492804556037165046616311376881740818579026242231815216233417949738101116086586716392810175144442461269235250030
+1446402688506317648015492449267953446562377233978895904366659114613140191253374875252211719488638375761957759777329556920444079
+4742234209552120961058674900214350131325585573620862943651827639544267432934381233345762116672659741592229252195548093031985971
+2686838533752676886446680927399440863720061868372851834815109578907201299828776117754439315722227995606329153759209194448678185
+3375830903591078788002755338696975595441586005976260188707036346541857769978992173498220429575524475532930877665817876092460756
+9351987353933462923395374235495972847763917223789357531623204700947268441087397398182190787387926517802157283116535834305980686
+9492332135897364643664989358260446062172464533880475533980243165095186005367740562491795933632109829107385087893207785894397713
+6433768862702582156901779207532027093153001807004150434114821705300991777142257598550961217676112326241485864463713890885328141
+4370423630135664116118217486548726531069411489498186055038679029605744527511210064431632487827249384739496221986798075711280160
+4424010886610887880437216748921409021429656729228727372446155715321241952848523185619209556774687672654909818027324033748491821
+5647085557243826965464774431484515106691575517669395491646712200606275072075247550415886971532904779039992053369051837694948246
+4648536696394853995288135284563546131345084094639405448329957974626886591260968153163248670156108903690012016896947562864068947
+9335817025706673645248672808655206936988229988506868855512246059364735571373658692183981236508753893624162179393300884572562525
+8454550045708811850843967602772364889207411447386933113146884803720821905371224276398839301167373376393299604166530531671536817
+9469613971479940226446065344175803391558840869442680476409858979317446638566865770776832153252927434674599753345041690804354354
+6652209314699751202444785726308628207785053079762876873537555813669271605409315256570040001991644970781331622466129179499281915
+1961444894849498696928429106294385830964606511500699941607840002024216695044414216800293243595307021832292431154543081449089313
+1962091622249577961316459709116638715944104552499484128514903058588880092425282180366103208523455810521574844650965568635887113
+4368421159409460609897114428104781398719260897374658539676968461604386468189383954460163078825080336107872167576349496495408685
+9649536539795842583228826048018046721092374785553431643665884938389496673231436870435149786802809160883735413992798925929876704
+5235671264707293479931013726706891341489539237837731840177933783526465474894432047982015526419973235553573918270319559547403086
+4039735888376366609018757028506161014783678583356813250677778613982578318008203758267120384291005999279443777316382864592311739
+1217739163779382661260606469702245656794710548611797988738048091846590739807732824364552075368990683393959928284317293320069867
+4916615035875154768600732328677330949063202236875210951540534956404960395079564144372822026855682749788976197007630147709880516
+6877745432713411450666647170018266444463633969867263093231179811756276204043142296040101066040921365338143870829243201412736978
+5181332217031028793650384590762724542630876907198977592730043310368021901782721530053394250577461993296684728562642042745578204
+8059743569954838104598948856222744875810352375978155248926213114786009876969666524615446586588275065587752809296977777941299366
+4960623850950107986976011274245247425368704858396317272530283837294761704449561833295704741998045363670811422098828233894939307
+3391941685834457637274247913999521308752675840541536848418544996656831007389255133631777457133457716285009673478699826403200309
+4519130151833287959851246691876615538787874185186936205145712978930546123861640155395430711723899715676633532061887829247109590
+1676546877970973940392277995447472865522499015178996256227821980732651914936762181112328377073844485649563827098289006561421904
+4935465846415256812459944886042442740776629289289624483798607070666905637221701286036356829140962976615020452048228461943046845
+5324252244416512745242538847575585469682159371913734134263569496276780441518422322618507872746192259540742513974372774167973337
+4061947105362693262133270759088934938816594942342421443896871674922874493598103930292152723174036554995062078161445343075609331
+2764956618470182052214734830103729160245043907968784028181813618886443201986039333396356809943270121754709713915646568740151206
+3370863211220134665256513439944166456784396566762502427753466744044215577692010267595936563128872570057590311781066772952724628
+1434093271982951335221748052776429614044261679575670437872151960576974124250079774604982905427771724749469647670243244251475834
+1955236107353798168181042526280355939682930522521300010742221556820749544725933966041624888393993154502962490618839145486969576
+6290416028546495661266540757687391083370341491184427521635724821327522535027514382783824919995740288516481937621675853899158115
+1271233716574270260984632585239413670925887252984501086126979534236923438493445631129740540692858583194337904806381657298903618
+3300535021488010384891010505876121956740827701335944021678777354223576529240510607458801670448052514469687591418109583216371899
+3485417441989301906542262637698405742722722240100485896839477201597733807155335120248775000837222824525999750714790729423644465
+3411348746879651113262757268624543364109755847832677598538228869268434533167862688737780726486206863057323257234642767012961381
+2165814758833781311422742619981746792464126525574786109619341095871177233773859607236931880493129178559812250332066463408514532
+7726034975123054527871123751165334996022991283473243555448093241244802428165706217812562663617393968824053366244173854470750856
+6095264928940472527983481330401867205683258753243162756860090551147348417813873221392674935402798968661528287131244490650915944
+4846998428123345187768488062434480479219313046695253889842680691405315693254169660178067961065703759896641710892485894972873800
+1685615608144031413476448920807056587474093195656920132969415782126007882727463216577625078022336565533036012495150175153154793
+3655761747568001155088833871531145294046756206587264284578974630056937095900549928662096625015556765632408742933996850251895951
+0111954704076325038375601656210245491836721039674987643056715722213989286056097567862156918863302428121309646750177612394901330
+8415584072851574023474900634488379027144152280913594573298990276864512420566377677406310761330579752357658832083046689763512425
+5360991991088493887837058948075647761797269956784924198250160336333432026534756149206974204145691725795668303825556473066440146
+6308534942697410882776557732300657800112150355078878291669302663342797528117730903433654703116183867380240849386640798032108726
+1472159005438778436757327262797064431019220263757862409221343714482887707767271424863105342534371712556647665588514796238299461
+7911386503568215258552458522450938485043355503569972624134133652411157539448177529209200030556438822689089819514432813580599189
+2365679543813190286281972504483805742897733392239676734466218958339246807222637911353738424980809257547217933600526785327528737
+8206666715147505843269892459203855284050942439891047557154055608815102510800979065603928242478158845237310517156379667384978425
+8564365639950704666389094627317673103441553979461958229265682055180735168285879029143428791049454750378104825426147990982959332
+4829102499976584107337249497306375535937865662615510579219221293219668812136853030161705938471830225621587949094705819774556069
+5123783679768692703321434015951275136482214434898378095577232958805557078721200098045359198446613744587543829867662788092598136
+6929950567989350660377223378484336709625123004431484409297585830087971734242391343301362221372782329683381841402343240854937627
+3027430314645534840941417243615965839776590781088050407903488696621208213787375420065466391992905505392720776395628578270203968
+5561557545896908531566696290176040220677116087315281719465429326728445015278079287297460019260738872427151255654689514071849986
+1828538379287013993210377215462458395873947138158932974395044262987261065763556796656318930386507150893214229366028840942649836
+2063121041445493166725834460800448260568700963104181570946402318291105228818528098805135391601388005156357001178185451101272800
+3370800872347836800855502143109732296211615709327616533336180819117537969874343031967516246129400847851680499950308763513532698
+2261251707986576560067694894090522658489287994163408241552992222074332750687259975120713193581210288235466997453538082950570613
+5547333609592722700682015971929817349283991994515812388316385424977175852402318951978198762120074865379726347089860459367729850
+0402544338102912384265553136946539662518389179790301064640333604344279296879018653656722109731114774692564467347146643170192535
+8993673525857276993127971955065805434826324155448624528360859774191561165506877746667502530039089420897916681025323026574636061
+3901599392791219781553830625484740571991825540511807354859441733493239937466053566374517381465227962291796387571020809725382544
+7574422026948740113868646418886560822423385797395522913481336942061412395775696211559412859927044430059903817069457531153931671
+3666927872751409403909634814246127285265889024700225210198280286825210509773750861772507551910169158603017385059974490577083038
+6432266277247351230987806521470687675699096976848067098507903096237956371518053276015484587153777797643144785970196659271124201
+8805175031746648720776866745620376390338985825396413633102505797368825729966186841638401277578013322523402620704692665720430906
+8623786671348700175861755678175427019767971457395145977447813890266721740858466375677681653108760786751356531141090929913781526
+3195648380237469630693855838585465684458789117617495694729011729035913248141836338293691788762707190185659273515849140203833275
+0597402941284234251455344083137079916499435796408338558567042346638713911874856299057564768580158647502818908352952487514100356
+0970868650564875484386825809898953941148685658470222784359891344183429634142985332602653810091182805015332286021467238333362385
+4744217325804259157671625823323830396696824326946849733799160663706608011805733632306227156863544912264884279245494044730337851
+0084125575216079610672037870038502647338343776533232876650551512543864312081271558094734273891229896844012952524148474639077490
+3953838752044271045872553760612072547541462596253868540540395181295139378941954659771594736894686221229277026890071243182491089
+1570455075037097901528554345355410026197839647129067342374536771901052967778273115724862482455356615889491970844930623438114267
+1113425143150646440502818701009316634243943336310155606852136330886016200376990719743484314150050963993583980070237708157561869
+2850497678307680310432965409960545878246397108725852340253836659713228648432015357639072103145170515437738478376685162370275788
+3326664187179079200022042294919767104163644624649594061308737509813605056856101998334843842071022724849290393928923994480353310
+5498899160503467457596940573659595416916940383633806231810327042150722695852999362605105557507669885448657908253818192962915295
+7340742801283937313388827545354690848045358633204829321755059875964474925792234042792682433581007092726558257928146358188938017
+3788737611929951605093399738060446796551970972956586328702617346062935531918635358396384018139217900704517134300111877098173771
+6556088236400468643295262663772005261144129747959817416429151644418457406109514416151746327186627985567345268051259611187659664
+9265455725916581745797982714801820234080260053210177213938914050671185571980281286595729366143889579286214314682943150406601728
+0316466611292764222191535471075816173597528297677167091929792260801201488249926367457821134968651224754973624583045814966898991
+7240870813182642979734405654373311183972717838426383954790596720674570866884378092938010438980361304392635321123093916926377699
+1098769261784660364965755629864526449156402293650490776352458745073647855811975287018649518441512140869999035534937655163547223
+7318570673563180482204840468935262794048795191854962451038993504158655689641517360974735911839513301305317748540458018312631163
+0444738341332226086089060414609016104084271113844087095538006211914540457624942221411569773470678982159365460154412977671269730
+7214452687225977763650799051005862709711542484791447215218763058978813997928801482608042879518784727437915756166238817248827266
+6180378877242192988083619217841832407955378736448569454941330027911152317402955093457538120111385592095583433817050629741079340
+5629107620334905196700840557766414405147144002648539402508824797133924214385476958587576623195377053042403089302692454844253984
+3318554062977863170044352262420619308431178765567333623647941692615442475752129139395428889369180754179899164103774056228855177
+1724684496632837895268448877487345538070342201067523252247951553639414362390924781555578381060846820725528271757795755177666280
+3668536899528123873671104403554809934477255454000919778770432207141030247047304569687086172422809626838419879927821205317757198
+4281376208790055629568334266876725167967493231201019877577819781783383068774238210201096426961674885308966481435486534817275888
+7577712459257967273487604669410934219901389126865013214764147583539515778668315529487762810385482472159142915583111160208903283
+2092476036780853093515438486821087167147843243339127524062892009959789660882873649427006559335981769826686296878365166850602867
+3343172251567689761041900651298644580155321777412234282871319882978374041565615637937824367712999898962026386244164131814440583
+2523107617535787966332348997625949033914601433430397210697903069041012073594953603672415272693571514416319482962732360550203007
+2354311337820780136418582226046355285087018441007811818178174630131348892691010862349686382003869512529793089372921566890105315
+1170999065500729991421364651545352790769082161371433138736113416719659099975772914182032395782369105406892855739430280792570755
+1474708015575641879072739292610329996968899496702225715923818519908679748009454327877467225863186123383312506444593821059541320
+2519230317068471671990663024614062738285094805102560284217361596105049865919692357067522503590280759438003713619649669926160819
+8477593117311192072667283113407927363527106554972169624278711433088640030184820529565097341512033077210672824164404101920707697
+5928625658638382607550288328629457639763193426953494665267869864411489469568811023649446369996193687172148618677078694284120641
+1646459774821145583534736023501469753322215654392655710781868598002276354678420510784519315703507997622744075405271188494799548
+5604976454282399594837769165955324714117059445288436250408738807427315530171196984735484375626981702836635871509821590209332491
+1535805646302302016352504827863133089568000814854822798689081283591430708834238105002833054643250911507660006657799194089124227
+5554971708100609197716368094861383459498089313293558900360605415466184945588159656825590482066432370186681671169454435798038380
+3849073431364569441656271420494005561747519609440641325324675204133825604638188550112139476449622000662627992498117594394096623
+4191048491581987672722516757004987334900086209495744999112552193520096404679809481469054957100693375905822779214877756331765654
+3967826927260531495518865955487463010124395050606347758705435971911583515293152693887305102817702226005465633434328368776552721
+0431488077940753541035965504802229919911746684489825460131664577839381215244988219702491643455403072485117531612606199932108314
+9410075360076281631174487118204030545727872004911310355915647215932318325233997786962419782803117783722823043531791703707719546
+9979899286512850189031098302495325193753351855488331350658951722090011555997930787556662797780665452620638874492236108755984250
+0652520709290586245394513350104966676213533639227604453023649959625928591554435452582297988094318689720723128469217871904823318
+5154138924950867908591044177967760020371009497593629645137446770819235001454567589699623753759581616298742234368099793781827967
+3473470305718567484348272233839660441345062709145235638650446308235096448960992127705010353860654270452060145032963280540290644
+0926811026419214969150491345419181845874142492157134486078145329290631845342202476471135442659122079092431512088292118497802805
+9354612782399796245605885928858715130206027789349453872862552261402417530015360315458931199778666063128483794096976323329377872
+9050549362931470711847062862659110650055274307045585443522892077774880073956334195774718662309192081402741882514069042809280212
+3388599022582995822369209018970901943500870352576118339149315315976479926966165136544818295802570738444044829469770910136539354
+6564372944547448237407512632251508379320872549342100765184348768929229061655816110427490635344170087149155652249787176557737086
+9304726910793034348084164624446844756267779275838929154374342302538079381563499255177774157465080422281305646532991405754916981
+5079495135477953063596578815549589683659295982170939553637877137130071575921564130005951724009912627770427858856970687414583660
+6190459320672966822341653503087470382689354052580606552329874275327388332913948910878502521194902477705810238260537165258752153
+1741863988657791139389205030367955495311579034712194218460880036525975053623461402320730996642095747448443229185546281279794016
+4885628580837209961221029576497258511104739050257941549091025711288015307691459924906488083252587010968968824529177652581775801
+0763397108119317156892696282929270919177456927168774057189218655020688126030914415663313590555442617356391166888501048989509961
+5152773773826793584772678203560374056030587370542989568481592013810907285435722199937156448541686535030998055918516459522290076
+1305239048493423602262076973364789510528152271858803400583562336066393859447415629511735131940444974630579121650398527184965704
+6991327733592729480669828930382613428226140528036104065114673331048967012900401318314500711300298883332334369070527930012816139
+3452427216705740390119289172699570798671134046758624232397496740015824965414235594660630239994200610360038450127723765597890208
+5175730522105055786800808015853823181610779386663930878893825884556056314059074930365519187914921351319328315180621551748091601
+5714910102916106131414571159732353736678835156815504392107562506650484480968671954066774178137781734638792008562430877641109527
+5369362810620715036409904025968522864824364325482506902964133711312038294053559282742499233287959154156854383883148516152426070
+0230923585180985083743915234845529953134912525464096240500757424789301872897111680226897303301395426146920411464973830228585960
+2828878183082532630135919486366960583430058092282156338048743819662184574743797715878229822611358535700802659064501248149009579
+8877808967697355352896283886616902601338873980280498803907441157295597934158728665206373488691687917104704283343745205639622462
+3315755549989540644308207351384163575736340700335343877848915517455194885659684732058284726257857232622941934453881121004726782
+3002928241602670019659934407449689182082678896433504272332382719662522606641231869982252041696766531509399818750721950486163498
+7932472000788041651204426873094409270765907861252426634561030946897515784875744395710037381070458145660220907030271894709835605
+0606375828713960156150750275120802286593052131450659403286977242629895839703700510410871815684746087294738637398861554742127265
+0927164114710800842124744207418934599056137681039495980981311410777428870205405129624149605463522859752503128770836084491952252
+2931015631747347657009129018143774038849625686108045440606651923845534431071983109500879593401459457270781303275371634919948465
+0387570468949867854454498257661547651091256802128345749601432500529628510635061338338862610989893855279059054348321900538486115
+8602609964344200881430293688135456245345432239342905412584133371544661893209862399991442865006457440325878578391699643241518820
+0476780634258919055579958686158323045730786320160920071950074973087521728400869220442510810405620758553467843454120670874658001
+4611389884432116865691971525430161735365815156176932740053507703667082841676421694566703484160697073157865364859324160407900243
+7848340394578239725877088114075619051748487906575872632940285638137907126466280399912812673908953355586620975122613901023009092
+9989300098497815617534003740634757576144040056489564419015441642507944260710401355749819839918602861170379515547533183230261689
+2978159531889967729748526061427217809996789425967856884930963977509421860822261926488518659963801830737928324899351448743506636
+7739373703546853709971163541284486539624807396328266253157406157316793793115843617866707276779926556010088380028395990807722966
+5262595518780890084621315703653759393744008415536932695809891522083236025326969192829600448033930003810949789949558452866508165
+6709958307107045609075677759152351429582355756238261042407300818561928024091909129169346687529817528488405441096301840942497835
+7939846806218683995681953891663100594898796616302246789629809345268814966245162531052163166438108697094692065750286916247302592
+6376737923232528630569024819762238692074089057479592609265302063789788269041103846131589957468529143458603367428237467202691677
+1164704135075482622437354706246898083995113224930951841406301203169957259318901636559771075096487643893444519082342460614778341
+7571486167299822050740707597065176588093664070641995447134130614103674235649546121137008292829783010870775335672457433796269838
+0786000364088666248224822824647357946129181563136369891309362023665749511277214956791187825832905762312557124459238096857752088
+0224756578418586950260891776975306306690545499717256072289157907934175802791666439540405671709869057148319796761025632922961188
+4317800666800783644393485986576298736917563650897164304571720738720115271226750820847348337143207594067034889090129746637573061
+4992035733871695023603260755794332051946719932307664611429871720394241080075351265170984927835215008078524349098428854934511014
+7791275210894880460866040577708447085440157107534047266197077167838868317086743808903866856598023308194718747427381845326367182
+9440053603247145332820937897067937394376812799936768352012215925676355028026697201409962671443788824047418146714929473243964178
+4694097429621088759426437344831944205038778311615485599880533035443309753228841592516038076111818420993913946554412796041546011
+0591550477943256220239415601324460355602248522402154416815822080226505160015237485088369250676462054718340071691237191715854643
+3754782628510988470286589139121850755775569961153502324797466418949716647077195388880488321524207926209705534645689175931304390
+4293579894293631845176289384983754244067774813502510037057302019611329180738850594681778906215406264239719011424001198377631320
+9407877792875650325539404181214900230679005444970369243950847777718535539213759142124477926938032002586130641694624396314012506
+2378295522687601357905408069624354294555654221781438340067666919648970200524898545019520189688682193849864964964428853699551465
+7923565501350073769051751525297874085786148453411032926127268603914648170142127584914619282268063761170983684501064629044484389
+9840829700300902841805899697228329095218443610475399628627070805326825976451593789370050027841655892248443960659103428515769018
+7131899325280315528312838930296738263099442057104969325259438333829573217299432626262718217616786664813337230788868035555543551
+1613365891642882106953566519548821305418260262459032678151796367238313756913498686906585565640299870573937524634136703149075431
+9289249177275626622021358990349141206245802827466686634188302681734388914438573274476670571970132658340810522019108097685976679
+1999547679043388007539431538024419806104005321474063902499212939182657952169737390109212206767202350076020372910741798343053860
+0796380798378956338026387089364560910203624767639137927998294096484424294854533260048523991232484163916572752125119143647479084
+3312139471300109845789877486922941094495320192955690413961709171195278169767812527830359720778178037462244636938901054061989359
+6446495700380140348116004473224522745585963020017740642418321329101387653563805874445580561212083040164396327873544239022001568
+8221316129071405562026280838341093594207054207388991782744751735089766826502781865742057843922709134454840546015717044077633360
+8884079984504038495190808918953678045353356097676798230492279289061735280457857280913457619377057884683523850527395740839623992
+7553178237304616708890828475106185796221210507905405468874982714460646413397054645663825587287675092464040250385703334315092608
+4773590965589763472535194103574470410955536365729704648777555516672917330870335268784268577673152078292448804242825553568245947
+6215819528050303270969774851839361036143312160025453398613079612450766506304878967542263517886001609950018287965333798559597461
+2170641880151969257726247627112079520687196427192459411452224132231427774555020194976266757454256306589376845325708061001674166
+0808706168526831621497924679232450195651965661724083005213398910330404632324992737223126731122399064939390308377239660504899222
+3551818900906904056676616710573047283299775444456072812898768689067250392820375890588789819477340760813736549269624861064751893
+0906163675906901070688176210778473069828249578452605511950224714556564390138087101450788624170738723043479291100038259738176381
+8078282667536765535434830984808011662048300628237758542292327990288591220497965448597597894673766538440553768610799486540893085
+4239348796188542060619155351521608241401936444825596707153268722768490308653700045149495791462321531911996176024726025953987339
+4599085925561530429435581768120454911625188723603840101001827808010649207159239374191781479981311865586606666121770067310616172
+7104627786436327756821840719455701887978236563257187943017156401785911149438142292942970899875188032869983742209547431350943402
+3524068403178617373975067637980111980036408360680020858787573852832862969725456560160112278450433733839443039332972392923338691
+7361417128175114993261450629674608141894725708171510038678649037487846100911817687890240766440318417379790915067480509929873884
+4192563045095005960884279637612799513276543500165975164906153877957210268650229031342852943158004290795716146485254485943610979
+5527495850605424448537975358841328894172810067249914112763981461492106207569150714303562508512966364997576085520454249415595925
+7749567920199753428291369733514893066123672937987655345561072264405494064545300253825630928142777746597418333809686090132329222
+2347190729828800374979423249344630750463633445579902195914226451238506679798785890126552693482294276302768079721653123608475225
+0152265832264604743532240505688517479981918489770686750786602858928368893549157302414453807821089110756269039234757397043529808
+6533482130565176488100655388961819118126865617901005108218775489706817843329452026358354168685608881349897826461107138466301657
+1298673036456454794414764858082769061588499493558362877721489608505337579335664200621558841720543957496547716133300368539580407
+6422724558120550176442233652100893764139597343252110471726917934375351595018103999311490022927771281873120822851829841201522060
+8271532119297676915199374389042651216528118441258413260870365096855873207948565556782103615860771982841168346920959540519710060
+6184875439923588759440136066343058630113336838104030510817176224460276957688775424874821399346650313045479118572616668489003296
+2897490483936533080760701381789308980122333755911815060695347160990990030052801534871717538234667743972256918252210649169228903
+3655303333861985799802708736697214310308014845445976122762735834979387407451810326226050509201808567673064245381176975037733147
+9657194682720093768010430501297373816646166065617291768151706574173498067197264972548166688571305758669319121229890115185819057
+3103510865220902456203344829140970552995511866958564974902239021728149583173073409170941518663482580344763138822732758130711321
+2350688930344799523350604942490602629624759567547933020887009924743050812335493964555189623547661668513628841842940808414417517
+7886476590659571641831046458439879022628434419829165109717986460127979081642839919400368933401267954441646768446103515126565637
+1110171943300926097143589488105661141081024879644220948038639183302967863702059520939356184545779690411373217502283638534283105
+6427345179711846867068806487631152636131101160079927489950186169690439565446479010213897921064107507425078506360801250554414400
+9449471539328516576998441231176991412965843783160858329264144663894049487064693073174535162944480509103362252131259963289347661
+6448977729584408680822098278848838996541448014927561863895692613238880261580223887644439627676547583170203035028358611234118545
+5113424393568423046116537671317616837784363459294529414397028767453793820041115557136079295159075170242753593066820395440768961
+0357417280340583283641050541304196888459267811242609025317032935293813444330705702581551660482757892548218860632259447912758396
+8759325176891928932295819377731294216097307260061594553902071464538665097894582707057397147529275324299057601238957576630914051
+7741473646777114825234899359211272805439289189063644808522711602498268477174042815308766568204260129647306647359885729554656976
+9309329125552267123498982148765832181281490321112798033562587148057414223743472931562572470841497241968346307379573830843375864
+5689803719011022683494640589564528393539106647783122400405858218032186185463041208001667912281578057825422723357469418158669943
+4135592927602852287576618966571253116928765233133651892018881037343848794704599894714843595981667962009408311650894622157342917
+4255899203623494824224271003677968232634091967503097880844441755720576147137952557139636719564772738964156856519335241825543143
+3626415788714735175257556917344733999894086186508542273673131627361802049868502277018604195271807930087879067221107134172074310
+7958546281467926023449343568661101832138815620051349600621939712639392675220715111033777811540451328852498746778968470255323001
+5507407940398075053567751242109569783310327198481187906287038704370431459121242392319816826310134418784694594320070284603132253
+8500952612124145512973435903996934578404485074378319984371754538530064680891506823775364453662506914230333187130946894042814136
+0265665148790173017555028894292865406694173385138855281737615651927882128657965562089006870021634293021436977249028055567123606
+5915024874219893422458723773331806018064564044582475437209765195603359789772265483078502778595048000442697079452809908661825491
+9974005988977051807595272626225779862046223804794634926553502843630881070875123298869912614128545778960915871587536819171698115
+4134066090737503736509722416899089791584075227377094759873530554067748069082533106208531237181423743510501202120010884006504203
+2130661127717575197825945847274376219456565491166146558949366985214290031939401399735403160414646904595040915898139346351713694
+6324612167251656207707087624536097155449639896731425226748776831598133504224173609907231060039276944120772510687900080346884581
+6779168745096711200457711019042996058420593520557512225066879514823155886446534991145884583182566717602534510076749929656585763
+2645365584973687585388329644555202088022989110607367050144776537693714417352526613252012599647340542087230486009799844093446266
+3564846704113295525583758182164662009216216712683832484187612989237709031101278092921642250525269665257513687371728284688457875
+4269555170494408895577906466689197972679804550565920918614809933468304708581306933698168463484178291731316450813136298166976686
+7026547610376955852909877173580002842485362728362791349023862313373489864426541187364755041770087263084268647054320360965911322
+5647079585282992247752748756022346611926842984561046976951468976647765336240687959117772104657541464074764281634923169020133548
+6986017692163536989579104384975828200486159266813636401205178471888697579916647226641294586286142850042407781409124499578432265
+7557633520998487338874304841131912835862129914096167258884138035045133191763280844957441725806050932560746430226219247549692154
+2059549946818227720943211781526111003981250924876459433602235222747377311088585283118957625555745513105052583294040713888376552
+6312790236548842295363447664682859100743206688687480099078223631017589800121679494388116457487107923554186562511797306252062729
+9341961249268388400507893558690543848588537117611908256806356375473026278316829039260672100995233732139958201591529357001905122
+7622440629036046952745648171252074362090378664664601861125598525510174413032785951294400218362705244805632366004605852186841943
+5591402799903315324575404129541681549710964981665090508369906992078809669693743879553048600144250375936726479837822625004211533
+0078063724382242661885925388201522364426479724179540766386042648425409841158873221737967588237291116048440934261723138640261227
+7668975572438016377259095768317171394189060199749631603972553612209575383312005377253743770387375624576792404785414546299669225
+6702311775340274741303788836209727482858012234498189667215083952930215080983474097496335600683835003845218991908331419228161974
+5844861014709438146848025778890120727743982063500046236695299463240688553674143271469625051120980545361183599015488717404464199
+1417923931690244544999340897859985367002505948231379127672256195312588278402509195472407043750082438215262579893876014989408706
+0852865918577980935645894147403286685964996381094297648429648506192278067863183038777421574419694387317777907505729693297708412
+1477876485508630104652801640230580883493634454785840756974806839665717736338880683347432665781835143575902380330089255654038083
+1333574195103318490380293307280457872559202823396902837942959887393577658742570521479101307298105809134466724699237489092865507
+8231986011655928132234768712876079867027010505901813055232448036254614645338353115984374755578779894249199293331904818734171378
+5291198257745669262198453729172996916240029288161181812810389503650167962679364773038871747909175248874112616641407342566234542
+9827656930274121781454100476261391707245667711266140909114058056141317855910068833712824192869630959336254369672357008292856548
+5323877306540282063144065009953089367459505720096157841731259977506672262970125862602619551379971955654409939177527714243403057
+3533286954907536500237907021493132000340867715658050587581466366920687545465498963798769329374590369604149184427380755601882748
+2772451245387121398103687673837186367345979531432828052838695364605611707914643359500610696276887453665009271796449018655863587
+0698238146791660163022661497107232088142858713995181413650802098858185207125972232613318849001183174321522406825869523281989408
+8598554632732565974534400037249824032956321514858885348539735224820260572526802963756049116642833599682551125312131721936464816
+8777244479719589766354029439548567013317807112981262942768196141952117452742612964786718669561362298781178596889656657857438059
+5923903176580798552139931019374192553986137461354795191944498128759243022494357593594711086051327159717361960027267213667050902
+7713620888965717050672864796196500874403820011858648932283473719914877636081597753296264071668416201048071423687724652867885227
+1226026168424754948160701743250583052114587429759744035821120491264623002950973529144113414105707200986835221503669020815368719
+4301615723202468195623453039744894794833018107887889921748034816356630393443669846540007477652862272296203141137911353369865567
+3701305132741529846291547614776780687562767296077648285050793745319685122361946265802267010089656480989090754766793951985030256
+8873911333836369977427224870430320356503521006657767633627578973429639446804587551411591770027775298708856911679457385890346605
+1569544828599021231532143176442191013631066377985711192575263159095165119051577468547654466026788861257476052155683756383480477
+1570683253965182842006010673097287497172850525327662453055182206979693937570550092128731857505346441332074707878996538911947435
+7826422261424373910786428920393564290525228206911026303685173218951588837324122530045948404629473803092607834231045937648966971
+2638900097751822798368796230240210897707934867384226561665436456581464223307579261127638844885560109562036790807667670390644417
+4192581432555251427389363044896326951734847648428400345150360499669512737809145524003991223977279428592712065139442479960445332
+3942282183806384991949767715266661401310060486291440972343510267352817495541237489262806877081824812836064827724828303648923419
+9223072015234086234796090436383818568296143232241955872923081786551697504279591818923391084950971313678554302938168053766302337
+5040295146817500973605556893314901715843407186937767008367308307925199801486021624397893053770707845409279496052311813731054362
+1647014082822566848815080638989025226353949427396868720941862068805915405636344175116957293867502515550210403185422186297987101
+2299194118400856813156210708210682041625725297454205612569506042325388570654000072012600316753710747599029554756191357595113351
+9406123252615695607363852828573549803486496914881699175306276755265739836369938313041363024110056929623864023133434302918217876
+4012400092952627260881136088985623398889677549475347950880378929158923209470729028820934081657587476645444580153423943137551662
+7552074556799764537114289715930906335072549730926411552458159805302034148895295264056331531618830126090300007948842259905560480
+2034810936658458335936482208711459668407533754842615732173788255099444966005654249703291665433879743623245887203502319367176453
+2055826854912228554738248289886125490164761646368783638608966701408500405439745351176591154838568604792386814062201460103196028
+1704883259604470302949798965476058273811653448846315941108597287428362004683627667421915628743842382745845960365444382205614441
+8276093407998769926806805283999661528492618490261728950220171409852969042576745011296912080496971648424710213822281461166346433
+7954055459730823465679899905176049956104235683646988019468094197473567154076726095028250041409673376986848760985312614035795365
+3541288526820871183022785627606776202868249144458419432875958263707872906136295450220559956136362126175679096582857639739948725
+4938942457166622758688764402917253914836669353169972138509951712963418233559611193066044779423979184123891151058275415387004481
+0186693532983400032989768484986211599974215771878040648121115240600011282719832395142348174280309789242173034859607865458058836
+9693011226500711160574222437812022981161460007590617976243921827767353835606291414448435195278815539213466555449489307049996549
+9509118537609881549110785870137427018215479109414974529881125038407426313589072435487055670013225428915901526956102119247020213
+7469585110154725916486236087220807528982687428584047123899577899339622871539124688449741918490207266633825962457784296958609358
+2301098947514645707894405697878233655395086728296961354861714139621104988822145498752087551938260818588440041204929785479253335
+7195002791628422640170129886701270065601981205842819128758172220230767271007555891989535523140754390046908600193906165109046248
+2903714800754690075212414752414239844419261581404644710369810146988392192489474219249291646325601976712417376991598429990116224
+6657841194866308789835186691755481781807363317310203480516610021219245717136441915610841540149737012207330154276656421683007775
+6496393167312732418345038041143115847682160487308598451735321809667649213873941020106124895016322422646066096706495173559340273
+6190352286444996698010567042083025249630998980474746852300834243586692391358290885793710964591096599205367697354040455225748995
+3808084112830212575642888231806203048547309288414193348028410780142000603799742289999737003393558049032105240979729430950416734
+2055001806906934446231057752350125761310442613239626005937018173389749155377417284662314193484961591256165582045826903566815287
+1770910475516651085946142895420353886980271498962773028208448011256576219469415630937607816862320717646276543446021775437024856
+7317728070174544541281155663261784538153312462326658626789839195595942323601274570763560759947639040733318592217361764664122267
+5163497922629734181478583586735139172337995385407882365183581289857390438660661367597010604158349602523776584737697559311077546
+1232290524053006728473192557288773310853272463002083064021874545276391652038777534156787659533007696087737660972241935746823998
+4820797373925070252089423136204599368358477176708061478789645953897583587905165644362770501568086914083487441612509546270070041
+2710844937068669762717114936914428075765570984673461573362652998653398467217253506007120061287151708786386990808903587499291676
+1722239692416177387037629004556867021409013954231954955946248469232703827805268278720272112690685704443311442687874485358911812
+0696442461522918873003473056316397138103158503920758588244927506442635208935867088943853508413143951321019830428306333251201396
+5237490053651269730925587281174140512120043151663340911938612562084343250088788816613613533254540244890538135550921235569055235
+3652159735685467737870844804342436795620955533935479356452033442056822975104591188103222254197338188275216408256009062112739968
+7134994798879023357613115067249723046493042657115745023241318111461450746096281739377465898982050597074346498759749836646750845
+5435539953004427145646816313257688146440880667736243466005411373421754461366941715230523658976477672479751504847483760926576034
+1189232066364746161715297654667683387924489405288055983423309925216635045159783671997425077719999713937624968743960815866938439
+3458042402161473455431554634378956977066496820341904422146434258908727947177474383440746332129391825690966243498723403254667650
+8583588769346353411734495459871858141713721510897174001175951449320360912321580651780695549218819369972998610310409490019288172
+9334204527475060600189111850610268775609506754404225935699578359127242186303638934810994186504201384645847184324944047027889017
+9180203944559928543575350648779851174917364441299737433952437533215087774057147807226819191868491441590442039396662591808502513
+2164065534579878437699757090955883471447031879403082053258427608568820018565147466627486801491876503507730663614122066321703246
+1913587358432681308736116815399127159387589682764288441702400713256228014611237877207779478537639968530764623959147519370506561
+6235255735630858442517033591935698933960554844760005512206225607812740106611830794710056776637176558829867814913080368920324943
+5410646760661322485781048142156629014814968811323925705022272475371023640394527122828545405831491808608741154836760565505004928
+2033787078461763925201661733809116559798197426225447373091087213252755823492809148960852025727421510534412088471340160144342242
+4053406317407103820908867515275579307068390637321468991384194322089645112923727349244540751951979469134053290718220589958599078
+3285805403257089050405641613610899794397383496324785340103859171172319440876039603408630922409574370487373867533449326075083340
+2983815868763252323303322070522064853273357744420576029234853609842229699640881843769482230526051119476446187157115583149336835
+2361402646872012433986880843871560611945683230864891757700569780134284216871106221826645632387373922861192629580123373279881156
+3429998671996373176825887742582100895464377776504251588052739302345778540285554961799280437565093922440989079226166655301999596
+0886198944491737540229136497483278400920360475905860689648388002698383026711966163612310598810941558644533048630182341670726792
+3224790998309426141510868353814679975103849323867287287851298934668662832191399524482143116612939771691776186144211021701423317
+4793327096193585617231688937441621332297850907599875602232326960040073326201864681000919760060752937975322888247984232424151851
+0809471069558103959275275538388584472907830398322459954494433179596574461777867507710018713571052848608078849868820600263934936
+8295056327643509778568235977901421687599218957335038414287972297917509776356464814745628543893936365866982215021206066423916526
+0069175389099655621827463771703163016234772278712340002459468537149630573879420643113985870282366118625694647368265400040980694
+0185330675548785458492267177712810772887558224559469934081174511045410475070695699952516120170917198086628352522241811643698589
+3432240470257950810314775679834800845473620978487244838484905235351184086387166599707527028976915030731776500593580501517198631
+7221196580395629622683771151068414253703527355840765726766691589948635031125477445246126627685840897423930890628894585553998214
+0691851299476896761562326144030082656664005132402228246129440862040530711922127884942717942941321981606132599740710622690829340
+6387805954414104944165651355643971413515987568344486496225929165033526273702557885861628429072595508259134031569932407466556139
+1855370060311355098279801028503699206359780131940779590143641110125855998712927294283001777864930865688001454553164651367990176
+3395026397066375956526282504048669461521946610830298850923781230518236171386053536666469499692151678856847055919172630657325178
+3046849923385707165827109497171128710135811605592578271326373856764418443760349195924655728319788343802029428671675457416769456
+5261821042279220321036999746346900717107895012894353289951489320917708733388530368251182473743527841343292751660664418023250390
+8824252317744508579970406643025576979363288136493464811540150480851485119103480579103156985795448940762007262203877811330652870
+3204055616321408250954812676138625194951030184386810613892670161995606664768252471283913135456955545480933087872315934450481826
+0110599619290339021324056958678493559294456117665436489672772960474962839844256174658530179997209334133515553960451214172384426
+3123165163841681474367010429491835679876709672710839983993762107872490425945162980229932665274102783110995818120564672709048084
+2232035395926446390712487234338471590552947684994788621710474575654186707905435367680711475885293815543060949577152083169955046
+3350028292251658928286123588620947938740352179851517866242963626384508167950485172272074373493999323206780786225244298185666999
+4138239667749081340443940138823062129167164095346506708209137890234837357780622504863833649209158347489730999565991588612008781
+4664217286110698633018092758084011823559493288270590581425742146586929149871453186482768470820080489858199024057046533515257475
+1359038127174952081563588721035499113638671173404164924825530484539148472501653910385502837523160916070082537168043390775386612
+1436923728210391122200372504366645991744778858443244990595402772009992024820412617754275410349299293608939703285522116131987750
+7070475686255460177418547021473687579971194688396164244442299931146128832803904423667313289561781005593542663645306028982529133
+8234121263247251924212841508107137520536152642698580769661242285329043039771966387613256643214231439403217580461965950616775878
+5413104246474816660429811639531866004425878342745986000581091374331764631199000564830359002609727849512990017018293163945873976
+9271235506027321498393346844536657245544343198147802739604119444238511848559098921026630558834845589124777635275843923942487146
+6915026105020117228571904488841353205308577369931061433915716936274811913573096342546878245443525669417786920642396110509919680
+6739657651695868636149376334284237799146008295879768907577994879004415279621922483186516644311320818173589692203657526672858471
+9876510782436209693056682744986249105883882516043932138260023370268816469981968622627487020614107433825722570906101692145161092
+8947476576936475757290736092762279169953016586726757242391235235637432154172158901821960951603571049760362400377076037216546585
+2735502157822565784279289258228694712999190257163908804541511707522385665999422960150232894155188313507493238330302410605425296
+7940101946087505879550405973067848188833812225296523952905032878875050817047074123446017999571197850004230072472112763344801201
+6857142063692961406887982913011490273637829211932192499375592176104274764580285681098203860236999583984675192011342612589287803
+2211465020826460764614937570329924717346527293528447660776999654426823206473097384092520163892337570587601913303602876478051786
+5272016532080322083507311689593741698084734458418980219100525429302190098183573551213250917695957795596851135451614813138939428
+5194225250639639525068156399214932189538746207985167145356511964074580667075083175359149568969997574350520456153735083289658446
+1455560636188297319680331471565963722123437735473357325582592487841750254758281060767877781711667628353861132757458093517522296
+9590937580052253974622159164858580322392765535712215396895455529996073185392085906968002802221878982904887664044332656986715431
+9536212991471446618363328764237863492326635377747715439634427901843465449556160996406079848698687609807559175166455209276718369
+0962150554158891455114948237812845566152678283675857088563676954226626094608713709080121062121158536561703886898127526222898762
+8414892749163551177217490205399965970236826061221918459810953818518538232318451456451553658102845761329243527433596909757880804
+9825158812532083534774503272169600063323718458433952873310136391419269694767849055513012348666684447456130828029837154887287827
+4062509382360859964541627147185929761392475832974190883249337770970320052156457280268514718326951417528373787461693447362886601
+9802384514195519930363615938594105163103928246792737359775050266251933928460657553568168049147890604569802307087230082628479583
+5935332407364708394968146809867463424837289762388992341535259500067286459397511377634976747563308326968703921946360640378185893
+4569961338778055670213869684862788995924625160473819440389284613604453202763523485241482845106528449769880720371645531620509281
+4202560683681703431369153262516802980502196714639887848169937613326674387122996761898343353693436995583214395894151975156893071
+5332713363776927366695888962587179393484799105075109946348286416315933464459810857879632369155531524704654845441581407617245460
+1504145331569763505220832523847632508529957830567158287689592530569297300966404712183597770247546234814056520028432048220079902
+1149483717724666058290549158624685899733135096369862966589441778195807957291623190196664952975922610237417399523101511538417768
+0036082673459241242094083136368293175771615652653244493296672289353318399016588588663275146926170769838811055155231491519921092
+2671555423322348703897548437846131134228893160392027737396758641632859270434645917320325207654186499204544521705733245689882718
+2041837354468721403869880661989984614132154115011011100068745419042193490192096797533733270459341389726436281948139045659902298
+6287265676207191576589342058985373273830354712920659876843903556929428288343172794038913384089049546744993546672999661244015504
+7671119447680097893124176344032941210873441607294204020878536819662836852561652631058964593184756766213107639235733279668108014
+1503597944873319896726432783506968518844581130482208284211813252594573116879179483819354129815885419312761420721174077013349076
+2090575099698794920755209276799477214063322134870825766478922887601572992873375806104725864045048652936083491870937541080699093
+4276983494146036588052551210478424032928358829122542012906258904015903858342990969060460111480318597431250609578131562003677515
+9113189915457840484343399644582165727880755692052210886524470220995792925869536099894161015143779391596346691130912281801612173
+9319631208845800137369253760266414764140198516858735371828537522929558300406662683159046086394078157278265484925694452296859315
+8349237034176302850857262350204638637311808275176159745110236526981407472953488387189243977498778789698586980560479570319641349
+4582085067641332005668306046922050438876194786256238539902378554139808224133740244623740910175342259941720827473284689401445459
+7345697903120299815105938454414060402797077914470248272961589951135290709800128402376384567445478103311791196342258909767408438
+1687450542289596593441156541948105976556022804241843599203672068561696047317558154471118174352593930389361496742548511304322359
+6498489819476221747377877067530863799486747795199009866503783070729160667495759546595972752749803505545796148381282603736838562
+1116947692218975950285800049524721556053629253858269322416639882955425601685355611062823222776368062359326543474366782696365362
+1876190167722031024686917347027779070009896358771654643412669083054810506078866218417271851286420021860907338434817211204686529
+7526344148737332091666585836660697055361931941977353720336283268157952341498338628673162826343734542380046878989163995116270895
+0881257474139601407433704222324056930283355591807454770810061687372318085122818010133000433045729252354366007849932042280735696
+5414676249451280636930231638752958380804768673433252210159619334608464253621441055450445428123593855381938626029786836437726558
+1472864902858611995686957469529408189014561042091105708978737612763064100403995245584630738467933358860436751349270719679653915
+4154741684647123464440327863242393005522818718477064168160551024239993656696764829360125195215986845682299044548790324197334138
+3620127277527314655388754016922253350206555973782560191527034271929722748456430219013528002841930398470078939445946816067765376
+1722243978849829693580351795930973604730338879610427564825410468950337347468265193351290232895574144876817631258161159766300943
+7560827667474386459711757237346751568066838129529407855307314365209698298457841298119589066095648716960974765231576411494919727
+8647954673176727645450541867878958992452684388452058871232181090099976607265059152633077058376469186824930991444056731009872982
+2534991973200933430036026714058825873362205723979737750638944916727241098322793656977758591967127159597583155643556576943448135
+7155096296084695428953865082662825849460303226866978634425536379072621988021237204615220061198468810868414563936757985215986294
+0328355158636181420325206501518296045012302259181045466662110690600154986730477840865756276397313811576274178347247630894639601
+6488666618858920723988680761139802965152715427776544103393791345032803457282545151397254870010332315293514763142030945537580212
+8490792796508337321795619849060108983218521200268617175020002271232501077412217793566906763151880182142093233096870432790215644
+6497520222357920618391446425720257029473583117356819552842063897560547456381395533477059429635070000008137772848031720176668971
+8337012837324253697188573699623123203170708166950795276999966009577648906818828342730326847639721034032786616971040641824194318
+8936005757600971054320025253057644372313238443033194219596927715787049581460393528422411161050154583706800554645719354006707835
+4215727593152764210346931899527305466845340439034432649923099270817579403876601746194619933095404333412889852431784452755466843
+2088097487158522551752685495115047141137278634729729587648195891955992392424399063377394353752520259570862609415201408164480501
+3544474831228092443689968228780611679861586419457086393251353177701671796943515744580842421181721325756988105402798156643588821
+9778536795257051681439799124663145890473401144931092912457976024515106053860305458288529123695426810921506064347775651216836501
+8629179794286699832017474082041208054529672919556607496647432513709724969762646139135868191228785586347557306843431128687158014
+7106456703557605702232569911033196736598272397024373712296482733842097318351505429979256730289847489156750506335880609744614597
+9660558924487542734143121356331540689398560467085012517453390341732092436780513934245365179678624863881161450471818695381011735
+3612453516034902143796136205048511802780802772294479133906585232123112871839607661282061340027850740910859483338299107807956460
+7138724118583930096084405139356471004624454913317962414308274669136174812224878197906201370412577330455805945128690650516949333
+1730291821726950196206552159924266720782365385611242853448279354949948923432277012453511172303822029259754519038931979427529263
+0548575047242616318508715072515332204278272517306960109310804996719916332590161894788700070468159978743034429043329057033741956
+6780889499085964528861899269034340070621419803779139024411147795371750105312955245739852543595775978340360773771494478163557276
+8779458235824687171901362922249920581085853186181780124486013927395708657432957030172044779093473433280766667409407392636463029
+6492579411705822845905066201120652601308459859010659739650561022388466983198156117882306744218369432413488854001765063909641296
+8476320260631331607201248389753502857961661494677170435281685503191366884817616726638971291309647117085069726218509290967362859
+0810139343653776833125734038676243930878414416044335363929863448842581458674823745747264416650503948061405425537368655356993636
+5246772266327550199529567399996744188644213516458735587639817991224447177904904043235549503266714688854194981790228117033924563
+5461999291173972450770635507697104176866762020802521790899644748842731393628432841194003711839701487245460386154522697276378209
+5508101058683508523829079387008807816663732920071304290119836347773461806818814318630035261732455767269492882409702742637950576
+4599609444549117705097045766405200220153090927581307100167391516722145681413981100426906534790499705750570830947858845925010025
+1009651634984508835728715571045793550385433404603846489058904184111368085059460823145504327889561854662565906194985160507019989
+9357881999324778923494272780697498659881414033472270442304085245770043338219929173021287371666801815069695486701740310076529915
+4608279080766236606674170110085478654830337635040537744779366742642067739517988003498779451425063495418123468371481260706586708
+2700839483986172436829409192485873721128692643705335631914640430691426436305173498220746572777225402080014675196382731227699368
+0086136702746607717078625347234495013215002090165872533540039551264212687781885399476155438281141614343873696580481400589706298
+1705902722746414058890369373242227296762941970919549616605978259694120130539911344963309277369189903126883321693536398430654697
+5704737347400443449757566987270236468633966314353505101478851263083176174429030344023607680553018559157482487272502931014168203
+0929253853547791644998906236759598501768018124990991199353184644473283908513254590068607924929473380232470364424573291631346278
+7114456427076321654054593005258016944651062956332800845969220254804995756234489111294820165405880256529733135691041245584370134
+8553075127747556822577563288536391683930679292906640525736392953226223500696613649419343205087984527799731174525862937043354377
+7195787380049689624114711568372766827743368052980829823446372539589421589808988393401756593651612425875577606936738214349475949
+0181544697505469142362834711903740140759734959010974977126438624042186356553593244884210506676336566524109269413687671228874205
+2896686735795141476730158554607522934103668703053995570782216706155323744964613382384967846986182100960586040580173953854307263
+0286768549279297394586785263108063892918942908459235186623403809969114153282154910435594392237358132752498428484045697160025994
+5955615832427009939764606346259378692931215536161617155986791397037887173705219219646647075071165536665651942885935717666403172
+4276536421804556864922554676992233459439755861177568827029918375612999063128068548901725736512083925758415949098712083242055096
+1725062474106111957956927114735687646594918046204634711666975260667778901437761819647914937715436330233142512856404865653199627
+1291532637755334170692403451392823323540177224847012033326608939686606026939972956526341007272336243309559194347525857345975521
+4741600004754011316928740091902596508371266808717732973936254941000335221943249074812743110404969466723162046697491974991225004
+9085942759791031775731739206062635146158396893656161608173687371708987211298821225045306367484626014700868922039873009889166761
+2541340395518961317950998826785729636172355473248648132541946680948357368185423797382627281741493372551999786014593359188997484
+5815863362546532185070737662568520327034674676319716730206859041401224197894669598892125005912741187360523778711460345399659500
+5019261584110255017064950229895215051849707546749811603776445037494938571872346104053773024040213974077890562979334359709174595
+8333959703819799129975411673347762248495046754138982930023526377690018754531518740079491735091275401960400702618787889510076010
+4581333314409607030057543494344952121287231730028937956224706941567517833092451729648212810249480493474654543033507398453170912
+7852221502784071535646166335599143402394637641678513241517161191111016811759837825114453186940577300367319815188600287295217212
+2010730508881189649006207896145313350898015140508068016693226343978406558747353752836658017965545008809220423091595161424950648
+0496642867065050893136545829132837570390366632826974250747266589629788809643453838849392317508541173149110672931572489980731531
+5044656574615736195246481865299114510211631762807229391764826087155637720268154669986339615396192306621947657967460512382581862
+3895441416167225879629472693046552479446299590678533650004819143386099678646479751244788463147638567925169013110241886917506841
+2313203706796269432481996570645174678020808456857425673026366797683548661197668493887407113195800476443548512276825541513285096
+8842881585797604763305986235159142379357301472286513544030211227645270193019240287343188528847284806872333232004379253392212209
+2688409746134847438143178885250323822851284371547861492401669288415720100963691981973327453125586959600245064339903637953701615
+2157845883601129857682095395770985605599007238545319703595004924079346833281510603116153010794429037127659368861617341676777914
+4401447994414721274888256152671021736338924549726141907269816501834171190194745666679544881448528084111510223352357146390678748
+1598441987414496519030297478102458680201205753852279934039229453001433839642149793337137629917651258040708764206181523433254292
+8502235049697025555092849971402076674867464110183607528142090872909056796241616598564935589465706229822069262366265937628292137
+0055816249709410284431305701461181450452686881595061600026629505373443676670339321519731346337868758756244867546936430600344835
+2653221234894262976174352794968903515069018957828772393070009300269049849197795885320787480595346792949215526978359438371233230
+2573198395480105527983836130766181207518943018866225650015829519188519988960108721260257064720088842555685468531102293009893766
+7692694226464861550196190446675400547348832497307906496613188251375658889565533214610868096123194257835553142178169804139054021
+7725637998171173785445603097719118044612631181543666841703322233562489202164880099839601175940461517268783567897496005081890093
+1623476912740353658966890439792885600281612076194740147557413318421891935617196959684345685434629547787219047616918564873155095
+7025393340892141498709286165315521796432685307146924561201314330411100254047950443336104515273461423562157427134079178986568513
+3037051173501455568382307906695636378996155638857317043809314274578391987572790382804869815651855972786188467330565714827922500
+4074893387854201023525918388726764794855730871461446351512218023803177488574497502040250654764531910469820302411970861290475346
+4505685142400586418253034395353236203805450253479017801928704774791824048811941055335303586560686324885362705510247805420001343
+3089154219080968310703760534064569831009505236913263817236675143668487294264949278958590434251398242365729091805726174530517140
+0036394729791915199963247134854987262729782792900430729405932713576759938708525288045097625035200406357341027793528833641758308
+6352067888617175431411674423431768301646476262241768575619045274936408735985350498083851711439785845206739316196883719103192098
+4796246905383107193048562525408958439687461541231738438567101188983088993969984494129981508412118318349184613817013959589269737
+6278309646817389075935268193490507135536415367887824086765490270943493340352420279233033265958209197334685770879485799469719026
+6501644826983757753799478095020135205854302975462551896895597291920140799672078608383168757287535179491461326280401680688209269
+6878526040144420355891683769364803589616260114471471935609824723068550467740012749917856656207461894693384857525476785223522600
+9913533038664755944016342494625355616351591218888135528544319832829890186060691211822484503271002284261557646472978467535245524
+6548210843247451049422320528853823425570998217119732063096360026534131251690098102596630502775298567714836475115745947762170767
+8887884056401989307352068428168695321737823154308274924885994114161224059109503941221400198439058269599476104839310697936760947
+1499621302434101869959148741723191678491689696644090274728115214408462354277075304721665902694379966811617179086736989510478453
+4472180192689505631132593579798684787021607827033405644669077356547531106428251322335834054519860462918400592332567647993370324
+9048351300356674084399149618697303904545693491523593398209411550081390607196236295352104843258693200555492607047645055200473684
+3904033119579621911938196032662442953927339169769049079015529114126726770405396769752836907821633197786728940414757447592836029
+5698177775039384194905994353296325732870874582783505440992449252246418852133705888017732270642203555475460239299507823556669568
+4584762886535479770675275444567493237009137069030861149601485784515963297935895153471843170037858613325007001549210631837023209
+2986230798529869904729567059889517914570160421964137879893497645563877292347055745496295096825111567999357916375574494934291205
+7206470066816931559279891084092643447735267681920960477832257393262206090265312234429580381825327805715755696980240563671249333
+4975196191021868367044398019078519059684387790904063324517862970957096304027938042892083911602143438683752393325035772333502998
+1316065614559478287404397163400580119624302865064035828659428240183667221604845265166461282189820016614382937134407772850983969
+6172722824726265969836224691170018753182037736393837492582066024393428721754417142086323296047227886511163988288746175386143366
+3150098340574634288363424590978979671688129464997330011306067549875063142531548626552657667362582081599069751262734236839198246
+7320831408674583797739325661435931815687746601771458516299735930183747747803369077854960129285952199586802721391111341133770000
+9781649076575876416834626425635920411598588075542620127671675851163249442163030188821293485762987388143543674662920406406559708
+5939935563329383384304248329695829758747483676028520127505271048590567171170009956748249750276404393523654234793402435394531559
+0252668408043754647206021991183069125065854666835585971567158743285135342908676173306885768974453965943775589652707957703958897
+6941205372351396701250517551254482102589310971175662401605631499693168133844709297036538928165453987035113124871313193061665449
+9276802658913609967848115344605249848453532699908586062377147315012593156326148344297014110306443933718879254374138651819351013
+9358073205389217401007942156414789371666731131537345827743121944929460937083473364444624266082970336996459723671391030112788573
+1765411908158890001229050208942988203575712050271091972655376675898080722954958732806828573013490785204118792568609729781493352
+2380302146221749454886974990613671789801805162408638634096879268990438108120689272991357553079627023448340790990962415597084280
+4048096687228528057040549427950909321059124104059954691594133361792928522598487445722858314871353602305792037504518403367795101
+8791402885580812697264727719699410880547796108771833960539902147827417638408675493518018213254819498104814348795878620396366601
+0903924261354725492168290232167217374559865613331033632981304605379493456181688182582298294804821827770454840207003173905889439
+2319227785834038175693137220680318778454701304164120192954225359327542167556566637258412033259709183354710843065358146305555525
+8673917622829080548174920911891769587355766435165634787328419281721579009044997104872530471989859299305155593643127267879722422
+6682290955279007939673997760490906289041187907827046608623932479656002087546101920096135789193088482019418559812270396482968185
+2423495240985101912282160197226440146044901932777702865325863608790152621900419953459804469566930950992382020196553029673452779
+3436610407681610128962456711300906610774647139359864663150800708313215865508716982334525964257676579485350065609743793059790523
+8492723526317024179966715344536215615681812917282255110526575184184812878258269018344255337700911624857617809339928700208173945
+3637336636381056356070802698487403636259922727330027710606038599582455818066875278487848716217844022297313070587219989978367370
+0060775392327016214743079646392570709223503152196217613938079763344036433088567530057235155273916070612559581478927578508356337
+2980025169096765222953776328674278356394573802596587538549701911336821174109269755308129020228887624742741743790423872778133411
+4050821812671715448039700197323622949979651733365312936187264385591443824448095216098907529899820693216629857601750862463957125
+3142033473651787251598564785166706147991399595143208797800693772522221250290172822723884818192653997830457442015732513857367482
+2434227934816021841461320189923052035591521089170168079786149675686974463633607305584810474242944486308070058500812306124076610
+7715099107942733927512136192299373968619398158672679676087995950860231222104112656659877314698556942502196127845551909712373108
+4069114461731658732633727592893010579600135097271095735648535688306732518715682620335083055144068477571815102417990371455419096
+4513648336048758526599148974167943082379478315281923441623546714332454634302169701041016212788185513022911448815223921787570792
+3624469067047527512170727298754069896031789622645772484827952155406739967506695954077541651367850929296976343602998185574427928
+7941267068022945446692718780586230511573764935339043083147537297266971720289420223564631007244922385010298582167405543731618295
+6806852318072988521804655880278600099719660787055120319799397720389095148995402664025461591174050670273042539667806005860061500
+7207008027571345636661751333090766740919387017591058445443344334627123396031143577924484316316865139392646603641126628696936857
+3077564139261564206167503001531356981773542928052096642681673223984499732941393025220000573381152245673838328811500670802459159
+0948542799001533682410297780373013799791748346265940949566539377367731087302452174028989049580452869089162990037685957268273937
+0880681561126138584261480022891283215404751141789014380796409952816321543905013512146286826522138659411899727000462608467450535
+5880091566261256557011783504868257620770129211977999169370084785384096209807922714348396458806443353193445034311369641072095970
+0556656033549253864960039890721015883335372132680590369609602226419085993403091634173432095151442616233244407104672122152816903
+0104165883408627525444104591380562545622183558159751831249938218150151310276941351661814981521482974647621742382874619909936820
+7313501231477817301767451446702735705428503662442130539627888646852578831768325107739301527824363969429357121983438884878755269
+4393819179422351389843662394835319603450398553466130430331252873486799616761474948216299677793061438633632338236018231007238273
+7068094772817742176160590443426997804722265949259567119852638283512544860402755698118178658952516755701578554245375512654131546
+1929058509678608173068953824208364147161581285515961193245483567752314654578018433833005722739540799467152027333949229966280869
+6336730057716861143854645697201406300653307680945816167555425942108475384088151314617817926634797063108952284581676269870141278
+6513049997339587705695549544072595339278305253913271901919825663866146612507671581432953692087570028664604274026412331620371074
+8287494858287111672511595795429201499531492727612182441663719617940686643391436311349735908431637719847434127985592417043341276
+3683439281027866311263196237695664936547654237370870765012602749829825808040000867227133823847412406422822451359747985192576292
+8080745720999988790691750589159999510681935221965279452806039652949988754070864815196625235801191787296756531552141564212907151
+7193959478339407643118308465039555507133342674876808586706138734909756613087265895500010160295176435656450676824231321652261709
+0364925287385399527025737739685585498448664221812361858587254459582955070942164513804426958941634994463722930608065187062143205
+1510248350334956246451724384468817066713416535078509857129529545180481755289335535116009464206553367625156566677354615817653859
+7881465671702288772143540937915254400157725015862757578041600213873551218117006116952755764443062859739372284691117745149958234
+9088672142145404730278835893039966187590126325943635642412358143475145374782213403246198035026788070070178049812453881844272867
+0338668401687420146135473027030982411204915710337406365921420685513130184588295184291465724202435316806267038332889397443572598
+0839432579664022013756612378573508309364105293988945101718659897497738253028464952712017100629220365209543091962896609529479679
+3205960596777307708890129013560513946330763313564335478005273643120628824046289255031118424365183741647820073945909472936879735
+4620269579622752421433383654982653678424583328146692271652411473449919421964392617935515652881545262048907644967697133592449864
+4910971218311134291321139032124590602851436712963785978946343853100496072075735946195731359706831946181264874128557978861454843
+1011713617018211148846555458691095625992954032111035185714620653734574566700313717404927859717431081627049246861417661324499234
+5786110524543942705885896839017534087003537095772880970962648591315518710892525409209474091669813346069319857029093908507508520
+8853954861830714292944628596393329384568570114810794672937003168548384708307820733820193722197605410037476744326684584534487320
+8506177470614128104032179365484641505802789779285846461790237297261018747968281039195118146388862647365824837138881138267868859
+0627387322960768524871037409484459085875896325439489116621528742302285368082254073124593119410595219290194886865353532781155425
+6809698357496328576273024691628485594217747112697681983376999200098136183929376787562599199562809870612840417370015973807170130
+4180345838072561608049345847198586105129570485513244519517878528919531649387592676465860801665435795014078048815567745274248672
+3354246532695167434429089502120887783749962531689888071529106417054905309204892456124468634666345233412562908228212778433482865
+8025350198646920310690370174859009390241456508358264258699021020277939851249666503547743318751810595431556900870080845029269395
+5024287042925036023658377259430412863334903203075207016434236014370755084100466996153432751138550920390967655897565334875107985
+5140055633415509862050689677756134057716739901647883241169162784527852235725792016297971735177502489661133426961482215258022336
+8037402896490266221826083726250897311919802495381754225581047474087034884706618427848292889662240224463663278752931604522244404
+7043755425948194930791058610151488175614282166409617670305934153837246327320668633959913213103337798602482509159766659520973014
+8270324793209592396753604357772106280615543278837901728489074421806486555551552367821526140160754356205673704266414947144922428
+1799358966488711764366695558613904123247231097498677269788824167860157320461004934898696811210735916673092405907643647942161633
+2879051334510139198581358891368404052755328890835533066541217913121822938905792625249238474950146832344471977043224365781135389
+4792241156268785166424579695585412116561708898561202729978503519790831983242726846466172154727854320602695467825448826562117055
+6892572380716177090374320438112277052543379149328749706362112028296715205065873069869487739216648881329625482801871208985853567
+6373214964682547847971295488976163394711102004330268920420740567984995588029489900437674583804505907280376076761512694288533949
+5155665472119733684583254908202345934203146938766729952819115305923223221786312083916415057710647121628060022705929366547804604
+4979219068691159117673733260174579718275355270622127824048810725346461586407079827993239800649367405496829848031012026874839047
+5453326819721439241285068650662264327283806902040744362117833297041970217611203752467289267570303110513926750426867300123044678
+0552826491452886926336136137608744868267813981244854176639767832954709406334434073383918878421433694185303125198608436174948723
+8232804838617139276458679276053642834353480357742672915996943482707728711707722990226821986645110256211853787080947091570985448
+4530019597199416503606666321373773776661468897805635174486648284631882284913728030703703554479870389738113486662451982640555230
+7993338222145807140991352100542338400006637591961344296816299971822252698512532704506078851263452743784059409504687946969377470
+7050536882923788373466054136459774772814292349043369279413441771827357318562815124739087054575308713882488227553010491099772197
+6089909596225409017825449105685851204483516303044569069782656841637982677940745207225513250507661349031619934115869792030545534
+5623878938475449105483656355950820776480123283684344289877071474158657289092937164564108821983834915760732145489786160801928029
+4816804046415869731980026155380698391293302660706933603124933543082802974288753245590234004708950597141938648083597306991959548
+6285742091945356496670113754904503990748375484181907762641311090270050878330341468974330973619534202556739616012441626266016429
+9943182264167678058972498083665971330560261159232616995578303066019814909746442924781284268163340228187122534568268386331093065
+7152421562633124939028810156815250340969816324770306713467508016775028986746579511353296216202084745909078793312626258806625843
+1270211232086431110376182218366306020098067244906289836262668331857252429211967620796216066094322098532350592071668917821894836
+3845983140880841145716906938062904326623489852177531923802141898083667738472813358868563811996856141869924840103531518902763682
+6718003149619307421590918630236184183948486678786725981990313301354204177947073223184765980604578217913950986068011309908008603
+0928467335337181093723613708048071495790652643180583079182628211576154222901059273081503840088736880283912228917857747961420216
+2166551801482676965109266503314605693500879290753119500152110927158165273225738493344045059814681043424105403563256277265130147
+5602984870377735940956944951929383106107020907201382858387070933315397423879633043403789726957228735509198228676824257307906832
+4033785332705686886894233935205324983504447579271074658738235607798108047836471901273736322254888901735575902110174004577938609
+3402493343952267342344754443371491773245869528553143427384549726736187617570093360565939837511071410896535571400200988988962479
+0467384270228802505542012448307525976842449031499613137353277852822620338697586513075361354863064717799164245330603052561106892
+8842259346260183856170976867586760896719736933276441816021638614978497367736310097708762890208045248689587229972592272876387473
+3259167318440772369838882122021007960375389506141034220872992638686407702750133638151910546511598120704345383522282582904780462
+5442641858108090041720094339574637116216554948307838544047344475741751117118100567565238848037532377180455225898883679663375089
+9577142779120614628627441392665993338561362305904130927688924256501300629907368310744468665785794738752761659537261334710214003
+8036648554081009787955952496618722107214483438085877494384608581966978660817589075759692849806559360759821555215575625537328994
+6018332837847583031691963477349319171451400074031373390713717042745436212897138228273237021196246257873177739985799453366628180
+2105213797394649680881845019293842601907281739434203168302170068885354441461289080251599722778415734193180238772976142195797481
+8846734820754645249343903444980443492288225807913782286509632765370978666435328327850741457922220028478728899676269184885886857
+6241211337754447826883159708571545245319208827655835686933251362672810423079630739434073408653288828495537708526658804579257936
+6272761641480084516721023070052621557056643754854336674557368573875689625068313256900499409409105292963555938180247719262631692
+3370472297661265053196085477234369632895929368519546792630928565306505801718550038387422423219452220411081683199640562587649457
+3951837878713231474233482132735598466639480024677257398672432796607337555329635538613813318615303256000562507502749357845826125
+4701181391450803850270234592090970559917694412710413114961034587689766035663731463069166460549538653431143701866309605231883521
+5130066101866721176356898240445132440597653755333619647577387320361484004480200635865792415170670027337193740214918631143418262
+0808586953125247209833845490228639118624854066699258124848785165048528440583631961380212929557758370252911013779599196305478822
+5521493745858166529682225371969453760228060851280399420192708176554476472315839318021751905690807649055065100259488774569707365
+6158697507308922777896716663452883986126333631244914987739404979553039259206951208801722656773710392910263349735278566679339104
+5235852402635719195587338866742022182421541295397761869128302452896058848115769056351269147058952464962337808384290518791915445
+1541410356265877277120453080537595028913680044162125110791583969590059857305994592466475393255534238742387386696685456308459612
+0685998205305456113478494375669069867507303172663122574416432766684294168665147860680796606372059541989820238442687325132846277
+1106867923762001975234815885590982053876420748926951108789589029118783643675464846081587064829483161231369554788911064379449191
+5812396650186976221479400172298188629572727898176974211003232401377793666992976058114854815038333629709686365618467427463150786
+1384329026943982531591592399085803625354634016228493888015194258739954993856952956641410330220082208258103940975869674221124275
+0959625394390538490258630101489160874897384983747423071388118372125410613424612801559234232776779480366009970965890340120701045
+2667599636961907870724269931710369308622554291093494631427897956168577372077593727180133140549717498300507170013965255252092132
+1737339475235603869117715688789198413446311276950893765017909814539886259628403094769733766342691082854440546058895772248646612
+9197218961185262852748275379196855788331061390003979168135259363646749693751540875250641291188297420332987544882702271806564544
+5155345846357272505381130365306178806560153732924148036950818502559878423925856638459435711194956693467002588044226649914787035
+0339515088331009475687588955523954567747189933073011102332237830656095392839856108022616789694653613303860633782147528467869258
+0130375935586298049775383191407798098669127243484570035128574481514435908283974501169023065679639597582504503336586846159045241
+7077631278309415202815413204154287337150040264985085284229097360757947744868068694211304208527582045828778373828218901884299318
+9750268301116713110151838109753966293343621088077855224277949045570521139532153236249008822916991091102238861514323117478408697
+7155195645472829181908341253643812659814915997068241585467987778740169901860636348467280424257966646686476472265113081410661304
+3489215851493494198992712587668351276298911212514851702684901497030382245009336388185220072052801963314343348536393431861793824
+7433750102437336219240711853055477575713689475760799540383502439038522399381791672647025184537779822386053913810580122038174879
+3818754166719135070632269620576055650986227950584996452818776818068696309115722467830916362575260788613336625118633863774586835
+2178221238069038687341161131798367556148830622561463128345189400786005116148867892392990638096974925106944221425159061603022670
+5524790379877915422325982255364820388029995625235481186060304010456803568052174332647747736403777805245458180638361448671813038
+2561932270943099179760490101865479784716200934807733561691561384108933097340199742932516818080682737612322848740218966854945307
+9080116601255117121383041648878380955264484146894062161454022932953200141179550531168588724355886537447858132714146647197563370
+5582470235237288151308759910566681678927176948236130886004032182125845977161600117740547183580925791449145036400529238606663420
+7837033717084727015977259234033008100455368360038870286352550514822219714510463917848677542164460976523276256801252857727025894
+7130094419267655355009949375142847444276972876916939298289507233195397404513990497114810662137361054915518609388753530456478940
+5388394232615483120266638817714522427995662494049561316381620397442848359037023023824190702655956805505137789130807808295750670
+7728487145979981298300914926600023112696314252375455071809186812868701327870915067718357028716612327551252066278398582389353164
+7289773656445897637637801900198614044295973498998341687324987147175709042706190580765940871231724558042584698396691392833921161
+8657047381454227627618374146397069336202044856822409754902332810974380485722671719214725867693990943072348305834409116868276317
+2768386266640115552548464265203598491327266098674766891714414339959283543826573869249667218521183972556730897770799418342118136
+8189160219232646049490114563802577964294955901129433201250836705921020927053769046687178122894793267915461627258608458791264898
+0219476902780453916709467789696795567878369111867867605857135264741583700268708214119151342234570678050700247598575853332533925
+1642635008587172832360657829315478456525706956941480551250122576528755981779071461911390584857611720174162647873804473942063599
+4967685799379026281672422049403080588839491839093762962697369896023527084701530700159221622072624944257435732610627292851813751
+2044450251147619884660437582513822729870849508689036347657931033634388064328200140554626737296767003665386040440053850111272335
+9965191238699562685527207327106427173242624391995490667681457409129351701642801367806048618652102824703936861574242876103982267
+8167136500949575593721265813173669081199030452059803613088300447991271804667292549385675921231605005292459008477827396828396980
+6509840801282604124983554742769070687886591529251914833953844029743868619125159895774188014042708540332420119945175514865123729
+3692321786307153306613998657737637076488435978265420180472674598878806315670458550057067811482012301407908299677656750462270208
+3553454561634700149917505664871758279230385607072819176680565522193204640320948453398810380708601224770333475704117532694153974
+9739801831118688634434296635463933483606562392700839399728340475392493400599816097076262424865867680957927823749646379318466788
+8207485786494651396331129651303688013258032982874538569357681541288542572016965208057337584986821728683984473782485195031290559
+8109594698571552972881573904540885927360173123269475341745160895931951290769944326526035760450300948152494775976334153020903866
+1739268973385061826289687149889229189956753685868472054090051279828873221786295847959246538258862203254463138510475016160891729
+6472588945675080220223551738194925153786626106262423384260557370130433634861152559973124770729011313810073811203315002214957767
+6317904094534761856637133735479679945651270156668746266850573869850630241143818143990553888552953747865302101114447970138765661
+6050111904910844217007312990287283030132792651432799525258590083326102644255354794948740529248987597130140253327270495396985608
+7218279207220544832644649289313013019030346375149234023654949206605352146548635130815666273562950986058561700625454917451118233
+4591089295985815819108775507988478501559092837715809067331448086286924500664248339776158516774620654659269297333948779421651033
+0402389695369287676425439165311946884646996933164719659142031175373351707836712648952147263228223229642458870791042562919539663
+1663280408606348818705021370639699925355411336760403455952690546859354756234316710656534265824067538349235703012760994218438928
+7331947252166763395452202287514396143003916184577374680861816449247026988630652041781591100537950521820855164931956884346869156
+0167992341341885278124354492799177573677966259864026035120911925009272011711402759093945175436356249669782240856162554344304896
+4307297970448548637044676901410933338328417297377294558704310254387943692431491233869228400552419559003867252598836554809147959
+0400912691036342469718967629054695345164844205186330491298158594966799688436822836744333087245877645780438275466738783338029984
+1522719795609161172147875781283157496792619720043728981895906145341666050986634594495047649741152246939806507306609930123284981
+2105358148148398274033567712304765375367909977448660123752729616799410712586037852322616433905738649313626209308187391551045434
+8184050603718152729487919051152176341217780682835043432591401578282222377677030156609712538101741280977544353648960619498088312
+9780539921497865045552480951265192490326869876857256607893887668594821322177012473373977135212994227092237257692716960309499930
+8387530951877561556746885813088050059098237284649866946622347108029066952894002584214015925808803683837814966224683534722188788
+0980315065961365338422640630321175434205379462185984915822930473041804521924781482514510231643402826027992447752984590090815631
+8885215984427616592965846360943654237762984211426187791836287528989189066470173789608783423601639354776027707428728361921725733
+1713545761488733797112097100438352878478186093850974631628293903780866218943733017611561596620119895299713346283509695880279900
+7056694123692100328413045552536384469910897094450012862955826233283495356986105417266885152765210669772149818027501922143072697
+5044288331991180937483810266252299436099022518584143328384527105505463981298174129945339074070183868941494344473296478243433481
+4945558387028214187495664309036767910507538072289226775563326183770144119596728765797237537898375774364456608274929793323186859
+2322622760682958787774419794236441627708513520567224931868094563846705540632720743482044172976408519449985880794628778392723979
+7704734167762682724779119792543440260650654515136102295412021984201525761889238911775278953009856036983484297176809989345351898
+7538438504892134535588424111693601136717057553968849287415515571796218046474942306436018172239215803280193264125771352664266396
+7105221455394922182238669063185805229847494225913363125711170315190206996126469146603174629254473614090501455991736786538113046
+8157168667432314271904818365481089200297683424381896431649087725330131885687876217074390326660020019876852812089717929283102567
+5370154297245853419804188360942032243192631168128880436140877705786486797146832449934263947276552080089455965696884234934971523
+8611893045023888017310198960086212752413461499017699656702018998940525757023063840379418108573223175879013713671744193748767015
+1169024393509843272061563781622978325016779395605303924999369153283788827391502842037817134058668089767959752756676201396896441
+7712715405049463369575317556974267677998279848759269048895603544096481338768211601218741510541248300317436674252540127015114391
+4834430831243295519098671812863396000922057166207709070811235493720931115916983299692520931163380069504267039634742271991229413
+9287385557045725218161176454965763264083042136444478713449129334549410452033352200798030615759042237027156709457224173930955024
+9440754327156472541302944326043902553561785824204549770748860453197398189036670911169331773914895138408417009555757899645501252
+5832453847611197719596117303718224745254716796559500451686231076822545459079358621425609803998655831572289152307921157534370594
+6716617297863540993457906819123068181321563782640587142663699479729095230755403564453694626863314955875318305864016967285927449
+6751752585208130882471772146338918033811645841373896388668212294917320582400645793013617832138799866544853495551795042553770974
+7292062075462511235154219336433250111030971448383048960076039173673865773457243289124490997622252180509835724029497464904686356
+1703189532838988444479300672213603786659157307392869303094005510273480520540799882625565441527626460538592793551679614793917597
+5131469474921792991086626550504407821816558283404370799177646663722782715758886649389166252871185413421418269585717891891693033
+7009640276492618793739187876608008054508113875022453329081433650929497189681068056166559133270910556458288747450052550799593778
+3775026817449250262071158797005661647517869545017156045641434181332078515755353689003930497030264487465467676524742489128433074
+9510101337115987091584562788637829217924129844325702143952753831115106454935897717213086048464400730491846668741988349250815009
+0460642398157894924642248578767274436367563791950971068099635643161955689433389352445513881354534070645863359289997626236597102
+7422701275758347504612869999447090197900987293675125648746188541872170309069628366658720207642452150511782301406643296921604925
+5722148742542704368310731836532013521833785510008023772247459847917061172721772791747731176316362682231389997934194900072780568
+6833294401022288062004523032063979096666714062815023108654665205678873446818506366372748896978903704125253114795333767006805633
+0409503844899480726742485372066289542014116663615248040053134473634302073503009858583019797024883588714394669118201212140331049
+0801167094699960082079962007695468661043658656967418331551197267388919434693010620339366679098731235659707521841235334772751876
+6325143950028159251006278830542343903327924750282184108026273734472327418765244935721260982532015689685569244807990908472766627
+7594072557268049752783928609937336033485545218183637235406635759394992632389014311377829965838907592318760198667367240484412343
+5995370105199099659966025879437447340499996959986818273399469349454086733538293008250823125200112169460372394345464200255398128
+0278006855752348475839798168839058164956107248521078548181749550904031782397298429598863198195066959241173235250539525076363890
+2434406818995447305231609382502170967538696884871023912846712870860599713914006479152902091530717543673744437190057705732209450
+2049303158709878586595288112356673888760379702189055053773161541139894881284696826212357934526729889089168985110486922861784281
+1480496657855804936389615128385812000095228481966854328817796490269872553734151219601055960998715934877799282526137718284428232
+8638224569717329657108787802886111345753795000064618991042853502960039658407299390014418474102137277340588865538873397922966731
+2915504391345921079597753766165614369426311302871553494239227907927104755401277811135239511652090480469130728548314080193845714
+4662543498990058418814498281187250236958894998429926084397929019382124044722273292092351973221932689481754974738766719140738353
+4190409245555651289372817877351684664080842342410487693494611165285252514427042631380484145603968868053004939443493512729765220
+0119636369629430093021488300230179969441757666478935315483114992540843688913867607317956666306088259979412209337113112892142162
+0522344915049743379719646407210766405374162220565183535557053495876729008927029380341012939110046953015244548503515867668213581
+5545277258914067549098676802369675716209629211229823278440028400844384130766676038181293025311537464968008032689589725571813893
+7241917831784954432887951874113610869422570389407469506150472467208362227227524708480496950010505902724279188045395824562149045
+4536217193131427845613009167815485956442321803951137596941709381463070724725318338865720453796245623311051568325407640234609643
+4950000863730017668562367944404823933355943718044346155630933481082791520987136962663882167172001786426520967022022083855046918
+9948462347102121864710644896101448735320408682918327475914042821856145185407258575043429392954988610306816855047216892742882375
+7607463192368539597117886391111127498537601742711656094819081284338644518509840706151881140781291037342960935079170415736099697
+8170547034180787962131392617751093115453333934584190242119875787080041916215989194964046994229463391170868877473670939015394600
+4967067863801616048208692428984726982425267929231942089387972467090049190181520316912402532109719978404281158192349591335918000
+0182827511598856652325488782019351042712700704721955971553105284410000877214479216605042256842199795133210940783113951447780445
+2845448586343352856456977029480170139895515001400772533947791028664521178270989590999530566461508232129548565121491303912378773
+3186958087525040737796735368369363073980409705399259078085185801788329795473492605756831924612159181775569516279264645527914405
+3736227582287369825938099577236266512057139246043733096797986415476742434871074557767615701953628932757311718425644125724233706
+7173052386737821682078985950554267597062731307233678638341260916391599502956775154905191238402444341035490900454688563799626952
+5147641961470238255748645042116320141678230506441721302812017771332190399762353180889095100320685446894708468194573746305094928
+3469096230652662675602711465325424276546888133056279141284661309882996606616677713056958440903862720614419241163546636652676601
+4000176045790898594283018168562878609386243501149259496688481941480198035420169390431588952838073985685288362095448469635565752
+9472291341301030094187025146867336563674988987757598438413852630025766068250538948297399599973328446303590662904124689712678759
+5558918453683884045568116648619640982031099812596210893142179251292478971547413993326289821580230193948481450670535256195029562
+4928975689440726890177460501590676962108712941853309133182477027909307432937071388936253714931106477057738446899643424898539007
+8940244387920877438974129853648880036120882337129881652544245505645048735775452951748876363983239868801033134946650378020657016
+3701058033103724656733182793045707161803086804756890720227008032425755334349001190669627279911430274518624636020186433616060892
+5795048614649402340472644254299779685615196268626556186825992241948964494636129874107575230767378691185971658847979564205979820
+1236133846548113964258787812605512858795064801453710507748252434757524711761598464790831987938492943750974650361247007836117825
+8985069765244610015917016588371467517920803422724008738355002305222843175513547415525425623310272808519127269635589538855868669
+4866637881580384758530553032050127301271010383021829168699459836736308865544704254424297016793922754172114529453114659796809124
+3421197137282279783180092595776656118340512425979400729754872785822827951114365899638513626864234673281733350488813180030409671
+6116540261589173059806435182727298140303534088364505375974117730218290182662177594123794279119735348291936701406861588485281875
+0383388028538445842643371054045990749985217056001543711456417105050188186522673179186319252532355654228417953034579705914850138
+3589398737652268493665223622209314271095213796466114005222254738357264490629049957974234088293478306962011737255628545244120278
+9242006644961491221804556688452952473719954034253935879343918188942010496090705258446852742963029458182305909452754390287793730
+8783068031607497439341603800503578168008017096526972920750091440007773022446775696934539156855822636256531074692478856955931965
+8800823547223548709312492609422799167744315137636030763502283934241170303284109496261288800964950861563894408561284405190045969
+0236871653896771373931349637525093015261721424149322538581449425146949187109336492808412768678305259961228548229258526615055933
+6808296006076261647807027264924130647898638203490518417736498838185026931804266322409312178542687977048973852811639981510309567
+6711783212313531503601350937924384067635440627869411288664439772524317458074685185346606914709019186196743715338064452022403271
+1329461726620692353133812940387503225279782302791789101276394351197294472993751698133198738485236134603208512597461992464092534
+7712409812790062450698418919781788475967301395142101015147156004348821394973951402124816517835984222889123201533407163528809483
+8878866193884252627688867520926767781102452754391877549372235240772045942305940402248699505448319900090404392151869967674502128
+2483008370299951549301955588790277512316664972307031593695383033586616221934522732614016251454351893271188672805879216575868904
+8930668992950485150931537517355790279447532793020359504907584544928499659083716918240980733762266979363328381222043500384239731
+5449783313063957701679502215046202754515996947849788011011244404372242125949053935941173427778943061308870747330558976279745268
+0087442866677315281344307628368254568290685263159851300491709072441620656219856549470063530059686910247545618397733080267966459
+4275923776467144475919672663054261638444876359385278313589184049205522647886045588220547740175271213225571694335593813888699266
+5631076970562565479284442184748121529273149320713280238168313146627141356684124916604998541431548094125068927278902251637629771
+4049873854233479495273404123122985718709224211298472591495302249456292201698069758048348513785824572699432884088465158829077277
+6601450724720706904135791943277181797939378581152182984849501639363583354753791712537234399122836156611327530479415218232099189
+5823047280117680731777259023254262177630139266484401163220777646941723211983561493087099972956890435877152661438838138706007958
+3871525096685339470645850417153350859644241363604522957863652066029739101996436761253594694922069548250943637910124220796682359
+3789021225120290908842849945791566951268040039302726617891236371450848884685584694857899475642048623621033883942963333740640913
+3413392907322042998743788130668642581010260731658079311951196515199970920919298587850590756579979416052745401954692899254629962
+1834576186290812892686277778078188491493029363265052305832102758282145333131211542287672262899869561233857209736661910966320185
+8640618069436548861856298762841794920426604496493168277782652390652529026370866518863711574378563335650089395301480857411365309
+1062855694706861343683613721473054277513151272875708166067829305351279095564881057460121748427296483260938003342506900294399166
+6708351271129793412643921214770696882147428525507519544681246954889801321262715754608536636546303081680171501901796848282715773
+8170065360748835664225539865399039511547738151434626699419911223518847738407528346693417347838281049824633463358386526323379557
+9773283803239608948889044323843524447778250704201869489766199362127854167469574262448141201863158740882252497005327174568985690
+9629170341829493159540502281159419978757497174339132063688621315745991750554750919122418499757801567167615195540686775308036772
+6813737486648360157997154949184994770910737848857708594705159108226498818076724620595499835896899658135344576077658527954169440
+4916163367448740109143119472115171909713176429892100499193749017654102572161123098799425438195950481418848253249246794538567213
+1943648585194380435794184207380836831419456414164714608475465257187830071751668999365832434059345210749956754565801799757863175
+3687162724713568040156043932976576841434569787909011626375244300886516755159434297033774573216110685196819615175124148320455479
+3344419757198679638351706919063941845054040199124828713172593196435249592482470220242606177271518431150127043364815791934444495
+1400008065520008098162065199768125759577818782918099045365313282741980846275621548204708560469294053250492025107214712766610441
+4165080021198705915210786508550601653226551217888163799551833017968067846988341804528031533804959471453060256667445828562593413
+0316539921143167379344751397929218943090424282667061717675506492829683232765044382831375540458280475310930354270466628024378573
+4617204749069035253813713597661824629929473681227979210717594546338035842018470292109616982725985026372103084242143325201934501
+7628437040946835252535863570081482725836702391432238382009021257963849956941583278276159017021059243802411805222128391491555532
+7118276592277047948538579672067937116293934455417400255981648387252807293008272125197089405857447395662820745517911550198420495
+4817641036360381588057889324736649206689772293316553388319983835732003282890192751493367420760022776216834345866178180918425947
+4046762929816361002114402224273088310438847474234192226897299571581711857975564268312621600137920668387355607049886008638057179
+9349209580226030857313156556379575691164723527464611358492523658913876021766102463374095835678962118324213355237312840525047153
+4458386832215216090846608267034928117933000209670619365236847239547649406543272314067052926849866069213065858041288568227157782
+0323889725674406704675299432615839196837602006707700866051572397447613281818928460518366859474985370527579091269025122957262918
+8693066533952054034279975214015256982660363796184125831239795876267900616583623647519579472331003311428117914837252346650454796
+6978896914173575690746678387000060698232734806725458177123404206650082946025871125219582890983005045333389163168584620102734094
+0208343185195645077429621338459120990032615146936965171481121547620265509203707449471143882951101626839387108073423291107985197
+3806694565547588080124701297594558579857621291153844744163973871845300036486064506978169189349641947450555475680771354116721127
+7571370673293744335868791633492268450482890329783462471218711903016708619390949407758233183647172103050542587791975330523548939
+6895867004702083992837053115350359081392183348123057432804437516085126480426796559419343457573809103554769814374422319272987621
+0493741336702343083547043049060106406621621423866156744878463280624931631638757753907480473151395705318815364246326098575320029
+6546610394497897246218305493409122075422636049647756434404729742804710870898441487104017723846320578576625101570540009682146545
+1011863982645118776769923031005075048502898177517353081584252680645039932448249490068383719149012492191034530578466311073324350
+0940022141946663679361628444591959010381878575634668757912852707910261260983582304441366347012174417975464831931140858093450475
+0648068206853955526969735294213923796512233785864528730934169006767896899020079186828212231303729771906306615698951701782896040
+7705404267837637281673906483600597132329707232579985805240515664780686649377686946124141035632716982723408330472426681691722063
+5719449931034079305356439666263973565128713593058013796099786122163872295053911196817120195135137786906005302955333296169099953
+1565007759742421563846584208111412785562612780177121771600395311757381072903942514964351796547320888609281738762831301074727155
+4840914538717807330571774867536594427640229999158918266573255879619306849868398528582717693006558964074770743956975947230605506
+8434170706163547151705112191666162854461320116071520338539133193324696905732424568076770881016026396766250345270611437134977029
+7078829392513262023910437193357139649522860536333445198136202621793588265321546711781743395796073320028953300954811115494631443
+0358109781392845465184944557313417160881340633391419971812545527651450314512749202620144080637491419201752326439158460989691315
+6502021443239860929638929077452949976769441697009577432157105021271893283919677666379901876413440307841861569738215346309784385
+3775582600443257869423701993595504734055924868316007937741523410145241997102735147790121190918364977637486443176097526249923371
+4637116062887697972788560169232687166734847960365006931173635513798426534363094553967229788862861423059133919581108100325100963
+7530945856385218994386045042760138610248296085030904585153248074916348965900743636913197206787899808540051760130445456596005975
+0082651589864980975976353455996961471089119847766125021188045871260940417581575204228376995886410553255809049908515562710519369
+1760176651046607404619158827695196639809040360410321347276093208667279377323033464221881041272072298115933348047136279306992189
+4449900653089574942697877619922022124081013931968320543380925350254859461377805018823478776678186127822712476112142520129506611
+5360537273314488942383696459647239094488670283840872805432523968819547360255856276619301822761467290415157270983258323381158842
+4069470180647648022724489031315390330623675246416531426538288357194889582860078070141817901349890459635960185352818352346101741
+7844251807909360860529020528005655952345376045413861757127236316061244993838373872852044455049706576181912407467785016013363013
+9052782242469623627138305243693885375972159761715793565717369599576257075617300500868041008633881912456191819467065232604757474
+6257367548773919654525538912712606831341580701967173140576682703453195979358288347264315572356542410824096892368844905848969800
+0225531033632269859821449136659749178099595609866207288912288428688139123199517309089785003185562015618879502978274246919977195
+3412420395378666741269488926730591786905587902546167052955793049551854045851796515140844301739953615780488764468845360750173095
+5314569125098157310473890637519564038989130593324658307078574903372187794019987998391252363359372204089006276213106238012887639
+6663953749875926737127213800088216077686383881272422931892106536521390323291590624983492836817664288184016273391511477345251544
+8638673096407867791116469531963581105938614830552680798696429006418115851082700139624263097469936097502648484256024821946642846
+3261638416472717635495620507090713763983290274773473746283045337514051847664087913092670813304318998742601034170158553214610079
+8880759198069479182867513797991706527425937623927208476182273090404608783390855357409578977746370113730628533384722500327769010
+7964841863629197861004282115308229708980836184692237168958174288698996726561927516939282475998327300490824455643829853959878546
+4078550144875137620442196894251820235783690433882002285566789090860837373159507997956136455505729693351610325429624900264497493
+6050282912476085926950954499140111563620447106769829012752567207785593165136710295523078591701424407957863045561973215300362256
+7166661176552788865443610475451627720514979209097163741564119254519710530732032781304320231265321064373366029789454524964576034
+5731838949398822830420671258681703806386818639376155723888774861742977966282701086517327314375297715355669245126118723701881276
+1224558805186365369295742263213010659311742471260411491616914473284160243356280450620150570408750609913288411042993040473195864
+3965363040687291139829734658431286318462224708522925124414942719604612215357576250193871596416258769483377169469309016314582237
+6893425774786606424591335564336597467021697313261577560777519605605111465025332099784940659090512446671447989183060023172745349
+4463023117754025492704298169088346276715292811942385607520313996627188228077675005968319409041724080200894220147117291796736469
+2838367610734769148543248796176416656292040941138404572575878998139182976355595776291061040689581132913463002164503763638521768
+3585007037968899533646050958305472231296473689572926896126127396786068936357337467731293075452760614111507010520769025993887156
+3025256134722351463444782906552873128386686368275305328178049328442606382059696387241124580313700815579068965097895955058791706
+4888785355196252887855666442682481926655016587897905441501499624695729356509071382797002137717002280304447105900656692938689937
+7373767636755443505506466024295128010399690845976961083809222125377563226037530095320414396885247587842781981216438439176626761
+1467040097296217610154727986310524824930119662672041177376733844872215017687323322767179584613934704188382812120901100084067248
+0055261010703792927114582278798343530536332871891286962151403775103518820096790537756954678439988840466572934380472009105374277
+8745186553258777370952969850546252235196298235316976663904366268611878480055244838332857644576178557847556193922108941720480963
+7310291886872239579954842039199219595404202222951474277713284211951970030467647252785199038918806323250107496561396165925992981
+0269739665100112200470147709926216131752562563116766321854129961314938822821859829783043904077776487245854331065090150597583869
+6022034598022521394602277250974332652859372516801989113143038045232940829875622476147452690929605127893923207935810728978176813
+8336719184987758081413476270877983896287998313373933528191759149653154025750363065606417948489184358633308380877845477894994394
+2211461131853873156810302948765499385999974459433061226146423964769287619911252503115962272972255899290410107199334224556606196
+1402532784763926313823670409002705225482185592078872442217786835593632982577282903273472588503956076522785281354947952227775013
+4429564170373891691353053299293858952840011672714332817264920331107567378250030393312486800497701640449816183190591793478209061
+6696515680454660415306312055092012435204898424655900246268144415272389485588150485707845045690614308427142660270754614963190500
+2858971388307084324374434247865554208042477256400063151868591675576690659860039137955754547923321131572573666015058716528677560
+8082431519645786853787074095747644469767343409908775777981556502295146873300678603062293673505033125364497124824045616025095406
+7796338540952910648733467788030865929612271961440794230689497348772551503718356824778119200166125356293580937006896521596909494
+6623286777262305838866280436574493459341503722464731387299068764367690003490556552997864648359791608273875942027789979081747901
+2820762823681177751588883983434913077317012385982082727245344446265775140411273692313089468167013918322825570599659499017461253
+8261747834117161824733335000918969440857899686470868022119901936951959497914248555296472517607486195543086996762943719289544222
+9801799673583374329577712601117604429044210658931033348348701101269055569381455391166077387776701104476767458640618577366620088
+4812671524372167827325442166901095131227009588677251478248615586184246419258110774327904940522040756539440861199193515869861850
+8664636186261176234317788607818904273283245654628256017166703040583397980518196864696741148650137946657712844496351414683354360
+9233785042626900594870398424394786589093845861107111076865742457098507103631392813148996022790966610376381301013746723765671101
+5599585345939628248728616861490756773613146232759270658252490655694524473642364799716984131253156192355158951050342077829511934
+1018115413367504225955575347257464735373797464835594482025360169817251469418319729479090655145106287600720398462808509722342523
+6277929810316831402715379663360019513470321307271888286707156176722601290897267704973159272389968049881611196311224142002818283
+3935507653397356468132051961271044279593473480413318195705016813924079917284710536189206698836513833423232062305170527285530270
+5930541214728728710514258849354991541204981028873011695299038161284051747700208580498162480391834623057628739847088944321070540
+2131178112490366896971016249779880442716420462976316622931349965957507940779710818286842266030393060843328131735676772739856028
+5339433698747921036431228649318038784378241814872129036313002907877189828316605458939009159662654429547906907634851960924867766
+2725144295031618884966653121214453016640389429569724950019640175004023672074204183536974715285043574870846234625695507751624691
+1101023040899658835128880208200979236233784480432079242348382094125974376887755928733596001730428491870299057160651502141598807
+7529805201863368482438225714843876867695794742159176187308623091428831090441762886002331398279108448588579520003248961018841987
+8520639531359520492110038481387012497220545183327686786319255787574425654228049283708164761318908288816634942299623177967850311
+6808287068903794688768313922352685578188040716704660250946776133077382541811421559714303292759615754217647905753791800896114429
+5661937959933192849164004778980526700005624355990312125795014118394734147334017327033918908976463421944496702296931260093163478
+6866390898079223822127023182717821447021210719486206672090868302561371850042810557962915762631762160188811564644765871940463260
+1983784957124576912722518060888269293020694751991232003856484645400501387457614453894654158242083061986108255912461168024044362
+5023757063288290577909452112558045920010016969071712896564748738667312129264760935144195712725562634643903560619975222875598092
+0140266427651227095088902077296483470532188392053269670883135265668245606745264278532552540957167938303029227319042084398428852
+7212818706985477890259174108784143029357600406814727037979412733984989889987109358055090912357026404921211609781959966663957665
+3885309358663398776897062600124335478996053317484403001725157655044282776168453835403175508740651996708988152698983678588345737
+3549561496006579864153172902480324325137781423364931522958523431287424861594425297230970169266435951937028485126756644018421959
+2100522734881499893473520957404272588614489603694208305341205355969403603944823313607027770883562580199458807047182736184431355
+3558566826776678787162145637003470985297896846344237649664211727912542844807936273529611661291547660198761650362176216275159276
+1697273051970401823436818435327916444246809126780823246257873146180484087471375537086616586114897794676638646530157453530809297
+1877141731822379123458355749374949833686834219493808460922026220049948042459289931477172440353720942293259692771867444391010663
+0596114677690135744062023310258035439858771664427542203238516588128327906442218908975480077474481540939986337760369812161668739
+7140350695399428116941903267710113882542083290951701275369344655927910523637037185426739245384522097331905044898640671070017500
+7453482207139204385313210256702640687353020750058344407280878423180101848431141829884177527114462939147014281506261604724365378
+5747051408867537658614820169384534962462911220360124367460201651929905485919878430356918185750947336103425001412723806012420037
+7672418158298677361496394053891368709542765466425399242228084774006250993472472890952527381058062695609973430135097018848485375
+2721910797057123953879416244095325096151158592383520642643416351496904866623597785985406941433201519864328401275343395705908857
+0642983563496035432630122777955167888076028823131047975325063367604577001605053104073667764503079932854743114362110563627584697
+1737450520589955785122525243234607141022634008326290553045379074437558301788691892914015378729774742647378096844792864200227145
+8049477947243449894011256046326611511617306926576503154750985615770186729781372043096871431456514521234719945343529143211616132
+4060930164560164022219102032312173710730634459253495956116881900466752536260684001258460015562183214690371015163609148581576715
+4339672054138260157605312889148304084301210593319661500758836115820325521753635857005220500312010112221791048318710925629489360
+9098118884517110952549620567550824645268745886275953112452963794466205654973301959016969502644339312155829940467386423970146851
+2030422710629305679756784568188030405053813130034967510951876362126306529129246017456183221963883892572064857246348841309902207
+4014325197777088687588337561652558142332091500654763031260105487352116429628561906919380099545877339112314250562226830515084041
+3366554959465306038343578751837494403196208574534790117389855546409717054044483042532146409499847066640874035730246190276785027
+7784874865116514506998867941821004659533959527747303526874272093224628939120659783314979799979608075209344316698881835617720838
+6440603777916554902557821762272317634207749152011454338456295029524399535728380230269435936275288518444494136138485427687743672
+3697767429372731488197371169546304182440802429138205900920907076873491237616407487249087243231746614255961699354564621444166710
+1737116215657118949418096366707426664676852506304031637797388892083081543972250240515279155087924413491083737598642466601038186
+5943501997584026886556269657780895221836455524956899348998644491412008841758015117023754182242908647650511196372757530427844200
+7126098691386230123347928604422159107062602585844839531380975985325229120484080904014468470157441597070403077589128617082084491
+0277414078111008949169676840880976444791578133697866086476338429943906280786246925904505101785927908752510981120731146336711732
+5011921703942318242688882518650473013576715256957336272842712546671709676486379489552317943731327342059730625728957322661925103
+0879272542563908841343149899911945430473689164183260890378649854294324088836226655479509126988786763035689227450447066454969580
+3635797692910230406460094517526461454920959082159212413377990917407487877377494660930246389887432321322711771671714018210018244
+5496909568572645176488382324921312621177838539677336553279411765862833091060541060811106495286938550448561214644311877956532326
+1372848285800862888898722477263959718622329488994306400315469392140836614515990231729283982778367781183582185203884353672168533
+6002585963544294141850925971586001726265376264686412361898087738304610666926697454083310088708743790359728974336913706461189057
+9544994601782264143680659072037087516325897282651078850550946582804440990613134903404213391711941451230258293606634693846961977
+4294296739368718314807261871407488388139897913896057193551518458028526780686105950168593279489650803151515173510050942218207014
+4440222769538547178501749374936219442687195706297985586916321673062155148432380676822216859833618467359812508595764374585042802
+7090291929148830504311787542972555491835675686001439326827409601590115100758667523079283454747571560861565934370463671494879471
+6306207613636744929606340131323412825985507087453258431275338612289333774848983021189785244607159387364635876091430264215902551
+6978625947059991073203270373760209952614062079324674488242868605448441131389947105750784088354616643566884781392969415722350013
+6876895254868693830649346298281314621651851243964761424180528331393082774872122268180557991527876049313013835528942921722633863
+7994555257251266617368145187318488777925218911343096210380569645729516845387191015748935661281511118325824054860678678241487526
+0561712487759666786219959935849355827031795611802441457990195006279656115907452353501575006228849649556626967066612451740817401
+3065700444272921097020103095032561392189274167240364636985217260309148382438375007728649942200430100798750588348282135626863041
+6418290958339960432209597429802884987767056126860829761197583897408153172039938420304452769552704862796110442336483929988890230
+8411149220304441269312528476234638082926201849344380193272700895522547783655344727512614476846755120115181365390739989354909216
+0361827006206843386504436443633849307138803846456656207910374387223474485947474439419270873842802147250905121223284959187002960
+4561901942869500550331725452244098638243866570298342595884556094097612128702524209824571526031229091793929079092201659156014426
+2569784663225002575851412395224946857021846888745089626571792624047307039913201999491767773809090290291368272189546699726924662
+6874345054057523806453164208085928558404937408086499251394158950058605789150302667994062909598865360566447853006716951800116507
+1806892347177795837940597487685027448543886249836281858785204813002880073746279096873385938335081449362375954555853598273582800
+7280197984136582079744511307894765629896405494228558457447110951049222331477610433641974978714281803792968381573777298819652746
+1797088044067027854938520030542484156979879022746379761147066454374087806486473993175758842146367406488679492927645706548068169
+7653106688789014002295870215309142445613718219291306854675259348422471093504331308963443794325054200760084750801107789128152322
+9003923022817082834921721240788410357242843286036977355497738812382673303415071169601837346379966066053060156517838544048108090
+8927903196351477482460887787174517966173931425526452434853205934174795153124436599267973662874006233354646357728472499860554504
+3649137050137288600334652169002894564926317935052375328874723351133720379648102007752831671041946276927861278960706248758820299
+7881676548153486303936365019720006418330263108526672450012829414081940012783530554845066547004930367871816825750941800388750747
+5617499751970255706526710234532717339068075364068621300856559435412791685014748892438638038434662792832126729610856601828058978
+3609505162338640897172019393757051075698357002384746777463891780931828353562474692966266497051217520058712600221078906316845512
+4218942164849049619324701770389240864171286359070468568203895572380950389773235867347931266228357895243861158024586703415416725
+3286877811857113758575603255834974713137243819997694752214133530728139390482439967896436662426005413536915227299430206070281748
+2197090522718698504657769582076344098155286933671656794750871593655253531647336100969432683359373204499872727545324036411875127
+9266329520011965890398156813860326403682885444460637962832683571266360623432333340007962893574859386016733773045469648300215724
+9360218780816808197711206028145267393233058010562551036732947883280144516446467977991400621686114194941533328336858706301853920
+7975466727102526807928730597288066888928449183473417942716701022737828267407136547666947638756923213101355014521544864295487342
+5529807372773853881156331115996145600478892095295063408262502214227819442322854320893250029815358897498644974831455098851752144
+5217677466571168103885153319146030362086428120742099054171064034691470505077333070394007756131235288630142015715989289401952345
+3238751872112411965525172279795754140090657968922574492232135102357083597107656178253770512768121887161690539858563177051498031
+0621143235328817027584926551312004300826256116914067938452329926333908173348351478521275486940271058902772821984682443421901374
+8675029994765542582556780936437230200725353322681947577235834861538086815882331325782379515826004655685444830286018743065534290
+9009226484124905023296329465126310425464799999137557622919308471018246198151834136297559364600044830857980861753679005100073906
+4026810600660421971978121050945152770853655639964897333811108395111596792046176724058242259398267547036042717629901672105588823
+1701174760060091817941457573061071686086097383906657079983926029247083644956175901708832562604741667581501354921250883246878076
+9360121868675405580012858168094642670756925814930958722345840360155035939830719501362830202256115680429221284715437831407183230
+7627384360887381611002122676157337577850291681707758128451482725333215128574377639863228270429176470896652784523071172226399208
+5924717495388805188609979501739528551778957144375491268555383034743525334962407264117945701829683575948250702090310348063964292
+7285038571762987494406954123411340680613165769286304746181220668099890216085869650378284432589286853709759806525223094629118994
+9108371459503424585162428035918267612861106220506440110173672498423384456764491877643881942033565719022603374698498258614890281
+2119544835856779238923121210216240209691871364625727861760840643200609817224777039142791222829730821468075117365482012776292615
+0287625006985324113383256843550124431381565006783532108722669073077586017057966762263289920449445173729525567088605286164318499
+3802234646726929017573814267132203009806257343348973659561216577528599490870752429375293883854127262090614163544620710283467000
+7574267833171812189998339587827378487203820258567218738257171370030553714438406356225807045913475052445364294909346459733645424
+7057209974818106332836072380332490777736818456915022774135091028181738711236811811377666386715288877847647340595585098875240481
+9197215476954479756497624010576859326493604058234153493216522641384431342823687635555610194191608220091909666730522341780147856
+1119537820044774998504706322100346395055393450296026673688711639572331613882591716507869222690391102545737433635859812821586270
+2028121903848368987212538442391618102128444213522329584551212886903253244685970973210284229639689302832127513289597893485709871
+1139101840913818162477340055623563542434178020287614160741421605723686784042526943742745792272929328869556547712709877327596063
+9107408768006237961652791681788083610784715577214377191666576416371990600318918309907846332307177843177765073709224406749447169
+6733725726008450978073741092474719053157935773438091672305982444490248804288080650618594239161482780330596854243463318510550141
+4618707611170337857871421415147893285747404164961249246066409955331826510336908541776726066361511390478520619795261534651528646
+0029871423726184455790317017373341560382122160829511677232857909382425970016570928985722750518023888742942482674353399294113016
+5851677764630543407742209257890179166834894877003624901201481696534056706522332095998210032002750686323425734736641298781343895
+9906317458124808949504199178481097664951999312281141056844360268819241235749855328929404804574246937697891911753442746410513511
+0301178939436270473741478421267690206733306236983147974561800903978683929049444127508643906957999471564453966363638317098479091
+5695590670680910148994003236516725327853434675592633044599651978504490768012904279502213144296250305384458215615813612885360699
+1739488113025246606429350291878905105006718514335177675021282668693092738324431010591942084632165356255063331639570681777622822
+0452464599884896996261376953519588463160916217402746423924422154683861260191652961898971705302933158251417160490178433853439776
+4496351983750730650624656965901956261109512227868877661440793378743454026849129576683511149685514643006637302234104714172349199
+0650873766138283576167959756442091757660353703079228843249388294567585567331488037468607523624545996431350612623181744202876623
+9217884841612782253645748182653936757610046223059439143748083525756745987386187135434504743166765496977544377259895573270803669
+5233343431863155649799928568730055354198316775389815272387174921789883067246402571006054994197016258947251698092729387460016002
+6222471188835586754619063338314127078684770466144889169048987130424673328124774962008878054843463980934491177848530073946295466
+6092983987521059016788973113331515120050882840886284842856803861355854867424082016223127983920367739842939341557083529339357539
+9152847423135593002663232861455632334026991039822394086654099188131348343461957860123922177650787602787823148319677335222779269
+0688837540315420699495154888659745629289164825587079409113672585691726485783954257060693018031835646491154074592682796993759642
+1560331745546205131052821650865965767504353088368099838110467887791087910699782310016063819056506494246788726522788847044002972
+9843063757395851013539217226262322774482770252168515327930783086524549572291277963238718919614771432829552926078930464389873382
+5165503350814374626462147517304790280393184056104578516266158383058163824599464967401146483647756651293496532192439439145458877
+3334882919381143165661074051363092147447735703148534066554968559573383084492917940343234309775642206678952812922080261015609561
+4150090892422827778476783958648862075260361082863595155851728025658354185826522324370827070485157038772970922137249416500335139
+2270729610239360993359408455484013545432335012129825782822705159183112780581412024925958595707332590452541348227573704213342055
+8812698543571227460191878467610741003808872140196791243938096775905061169632652370417102797369863591037024610630210903737953654
+4650850571724314687005845773201562588529522607481288290365062000530992710204626283641702861862037299641210309359904939817933700
+1541143632255817063903213640253364698002930217355939377060114361273809860644552941254027110592936933650281526566113066201345129
+4904443218069061051090074486584977672087200091073688866301081198367118241651115030647481869824608967401802054144740280994709964
+6714819600988123781424031251846423957142678675252652218273564424036686308763026328451858255344930462603371376203101104448466961
+9509079835837547622180222314290215064732353288206452347849664411672496172109171750484558066698591320017336090478613367662057930
+4411722606999341112288605914814611482715323396030160357274723566603030739104369997016486251468461541345322418772128759607222696
+2948183785699572384084816055776039138878581148811752092336317365102276231176457487558011884744609026187961229782054619496985034
+6425095624545385534119498681567553265889108179726785664829530547971892685921754372850536788921833807429343926950424016846919855
+3908326069100657803588698889883675042505627231337237747168653314558267673583632726264839565017058848634863075879312565153073799
+0321367266050720934662774520376532661682212427124263069420126600109509081952403933716651001460064949865799766176759028464538738
+9741038058065551330442704073919666652946527397570055939551345839830820648016177629571594906346803356773604688620184511211636838
+5025402557710775296650014515224591309232698067998266520271098024189399721692010614452489061642157793190304607388980065831660161
+3865371756663396962706440110406172511579502225888432146828231479035598172810500698253040173626514931478221885791112009689705108
+2972286823839979161832311952971045738890113686974537517223372452946515286365656547601871718080007574659696313592727664057554794
+3671238913457833340723922452738592109309375009714705044237276003225833183922594035143870946960395880735557105535062577056078657
+5639824224660978396027300014663032753936090244783494976851962014859592152013834741021570506331633866559318037963618148063022083
+9565507482964988994686034476299289689477300610763650942914931588839058915298408270882723496065586551944274748829842524532900569
+2950174215698554483745941905548644387438215825109435969023495189379067472134512077000118600012988374494816155364721054534508820
+9518525904194943790633186346738672276318778362232864095452323156494968062204689793145701834333799109246633884847638921045253621
+6777489268860937675801194897856962853781999286279373198884776447439334574892992495036091872659389999472183722596570197112840487
+6940178173947556103657708676822035069381549630078448878860057242455764188710473335746627500154960475546070307022636234086868814
+9329686102999304427635999138246997518586345169303923543680994865014159368545564362656579126189568984209672180187596509411904289
+8400290546843033015441275084455799605870040808860666105081155326036596425585507607789010815662662324838353003534213828215099749
+6262731155067666934829202231823905666280056341904107277513506385716411353609764416145090669300953084810469016331307248958077392
+0982572667217714967858091868055542854621721843072461742877828288780619596753823464439165581485796328231801786913442847252641526
+4848655976411335420584575046674979122655105315200347515565901735274063028061587092460808297171218521824980966675211293241764354
+2938658446761945214970070404972488238286005305727629688975307477962234711112158327154676636619409638849544823620779316735831746
+9233723105727772276287999774922758635916582468201648663126732610340191585232715185516172590941978497752196971596838962424314214
+0715690795433694724565717518703035300373548926507910938888351542625042732566820561320308097626791527666632661894798286702091403
+4964320219506572216963601199129841376254539941692757336784083929771858734782219556315822673159169808692321828354292775097642159
+0335559611733921504268377474272853207366325430567729920137620204884173222566965027114331948190426982554186105784631841860371363
+8033508558384267940900957170710292773682470738089554833769290979485707252598489360936633550982291403202103393568639544279214517
+9104033203529399347159766145704434677301867369574628242547881760927798205454869510642633732888078982477565192220841911379788216
+7987660031763621257245807669247102344394837687835695594169011679441270384265326170270019240149525684618010449694008041756350062
+8151902440733357075969965129856431003770185569733670086864031515027203169324745948550070082363039150127359144961399154724592013
+3790327961179853157835883754649149214290489479319422066362773172577179735157530589191336297098156970651227770438081844185734307
+0727046673630137406560803707058042940068228879956058420026237531511228698088255979495039662974032046384364026969019919437568764
+4204578688546460366354226690592321231974552743860907666913839079477111780605991648504857092410645662298682793993079551732419876
+3756294405429570395559614676089322871628319405115443082409818445213875343993774082306018456892013141571878129826624772129903802
+1915879655542608031603048228973067523323417771894628549592585367737979812887089684899398996853836990904295238545782994463736003
+1862917064901509743356712523964887969381684280627429777002084722985720739317294453681605121270099743339673719320682461749376518
+5235629358000506017419756442938714321316730985284287276160530781176188912088650998156658168743552720877268116184356043543445755
+9443882656574676998601479646029201608533720364834332155558897088411735201080867283586900504743773546108777074700728937687647870
+1677493272605889337983961765432999426943110889282768474699096119469883217687878946342929523139815961885455260346054616901453447
+9942749715588817104901581207188857800673119328816832808571244811062495461360073125883981969697016073423707659358263862951164461
+7589849154636259255662987558451236625196817855393407896633655975124730683842916268495164065502043203437031707489979618651602416
+4877537573726160052953215845080536556910640218250727320033197474127755187683283945624270057808449225177808596236183681916214308
+6307674309759482316304083895463219733480617515657742063182272951154632706337489064696789783685482205360435876431996285794642684
+8643739931017169670588941204387320679922643218218094561807636190505893287798227669018730741719908408353128973453099243266062517
+9595878873331613803340153742041195527735780444717553915355354609332848505998881213100337678158719821578770031967558080136888152
+9826258075448305567391906666815695574763625260042694682673443923778013491658161518721464450500242508138338760627120693213553580
+5553946281220024617384962807582191448987025563460515052097885240434443584003120884005027893320006209592895012188176773812824397
+5351207991648894581591662853877103686069327469518295438143903554689747912914341445196157967066587607931175822601224101946313543
+4718020971952950496510335972370616351651238578779144226177776993578212091520634237018822715136461197024637982739115303152147863
+9502456279815158271330961578383078627663170821879138142148906444928946168505151984176109046790336568113096829851051335078064246
+6953240969636903319954311768057533966261755313567448194782711138760563765547507739230406557393058730942539222575666804143511119
+2069936646276438376676948110321617772893399556260252358509335079746651069969820285929369016951090713864814429938558082689945968
+1521371174145731236232976467624651809029170086344894245707746268123154057519935873219521049882236870962226595226944947282873198
+7819821085451992801895188229558460134173236266804505398682944828070031878272264470195089873005628963880175293100970223151449714
+5581893838568192200692899357118035029378571475716773858918510887575125236858310172913692992079179964473799145336381338174573764
+4769245956084317711076182507252518842194925936437279722455907758875435914157274173921143663890367325067229935879996805150485626
+3134946076248319258593699700301770098983689499295660906642311982752703674969335911328913636983282731424392564971128071529792186
+4653454953851844259383149899336223085116998954459207141602572224661191223836954928657358541085552778110770329785385935394034672
+1848527104180913477755119395683294511819189869818050532796513348646616780772576901429766012659310230873210004958312011164035296
+2958092156871189322732011639055425235756904126336215793291675441374713359747361020499385226744232860514052551561041374928704972
+2212834863497329670476581032210400927271310708293108228424935554688407632484416285274174812931270321948680850009808218617859705
+5759858970411718249018834966145654061840913712087092866138009251429104683711023685469060131756225674409696442152891897372343886
+9744590632172501257249804338242668855862458498369585009073080663432870189779358421204658237236159348444067179731646552147785093
+1487302286960634890703793800583916358993694233181958170067964772301899115902690629049952516027344747956086526751455372742400915
+8338876525824289493587802849949027999302785007312125533604872964433845704867828931952315117389601715858805797176205231916978863
+9771708561966315440823738672686475996359300091791133612159610896088743156170335643885163215910168604808694162494306049091846493
+4260246980990607411798428730055796631495823134395302589335824515261468702425017396399121744052394058025204383900792732372609031
+9971700068769073722960546542881880186840993544233005529300285659415785115249158554970710339057479784757811267863305208596232681
+2366740530644754206054437467535946438364093779279894170145358386159026725061074970741778654202207224942319105808241561149108640
+2131299570746273126264570482316141085118510380774029845237350007337531371596475771574171940133305454244596824947855809667756017
+5149174518393308544163272712602730988826876495407743839625377436405836969824290538418225557277170446225596736304939253815552458
+4121823510749511107366436348094783330267428964699228112245771169272372131739184081655990835742337126629817378548166241761588650
+7681892302838328396599913751062470874471102029977403036886581893796472818466025775981658918091981433719370508505357431231485600
+4066251794397726082230815863792863498887502338665772599923859722198014368910671442996024261604600584351270667582157099044750647
+2453319243126941865196218141928398513931210505017908632678271906294188175528244273588712226403525451579574075491526959814201424
+2165992720884571403675858895697135732268260556618466022757708781513389984131289376166641651464163701439701648503883511692095752
+0809953098069693344801057772787094818934098518685172639722513866511171301116371082267224802273430384579466957516125344869179896
+5481982401939122614289521472353637017126771394148320518526784723238206085981641590886685015768028048372274104457267692145673344
+2306442226244080959840391166046824665212018683995806330612693877379188175903847065416666586796553782166003940513860649019698449
+7839622245401117642004314710277578314230150041129278793586315748881510113272583096733556513373523207978534603403670731996254473
+8688617881383905361473235374450468814839809922748795968256897565635364988983320676159901781893744135189821124712699202769736139
+4654535121453878305432208653573696687720659331945282280482164376466643366264403854440410004602377849435849425047260830549050573
+5901354141130553186089991532215523080159611047438619487077531580624462005235622602720033994742060589665151566143947383285531360
+4404189049080879563477017517544794830939312853525609682809863259313640891722874703005379977055110211171023836236430564193209703
+7229494566794585131912570254848123871703487763830158261455284479338860024826943524410960337002804517176829321597236274083343832
+3895863444104818475102160062282466733057017625695711453552783055209411033854956586687106898952724582542873871156820426292736090
+8900114835631317986947314833806014993742344316565623294563018259706162592235301529753004421871816938486470617127313453996556895
+0571759514976034692556387423658377978720336611483511537576020419517170544073326612329641870061597096528288442406290336718658618
+5351965547349291678130305501394296379111242594063885471825143788366715324130022316640730177505334429253870301505302005277723169
+3916717817342560503418340716556896773392571317597234277462755462162266315055085507027881148045053452399408688937434362014420860
+1395787899840181514485743703752177228078579014380638280483962491760489212783979634460850686798659390084425828810746413759168217
+2135670387347630269927889910568863392759999570308499518950101510541542088393000686133918165399672601047703855590903413630319231
+5402756885639965603367270976348755948712799599490635951531639604227412641095043036804481527401401591963544493042050777198305908
+8529853370862945970036024025436607369800687358272778049961830381455619066198750162208786259673987188349784621840620855238037708
+0287160171661419657676846666977667625410411272514035315874978763125830094141664498713238305106795904657260444752711842879767089
+2429466318667908141926838367968922957966923427083942277132655834855250930739506120606993470384477050842837546690187842884625651
+0859078343456062742869073421013869747003592646292364644445549193378529859368317830004107789688729965524376290149979489394466571
+8035239664854439337661491633430612363668270550373199092404545748888325504908156365529288450637845828980854077097067322982777549
+3141023341289995552305686646515529412648513395018325323202158482204644747543553961230472458295893311161675174437937559470576749
+0847147233703839410907356117466248368234947493218430919253855840473886381053247491509943700747999091387943188137392889875056078
+9027561924408681103294230082697546064172946790782404069187548612190839473120786175725940158419889526634026805571973842865999326
+0264435567708660940819192568711718952454625290701063992984178907184987617554072919582117061061638475508286749372288750484810591
+3758876219081855315432362136232140221117526750802434000370402808679995451358803624973049460963970344708478212627401394392324314
+0737438132749076462394577606428117744360361527711020670066707010174337101948368515240770186600234895342764130573542724774509423
+9073624026312594849755836859839861773390790206872160912057185754009883091290659157623485315161215679742322663821620022079418138
+9512292856680689427009039672717710424584681275009917377139164236516131951125126982668253717705356666975977684408510117347264524
+1614244135791303269397434529358056292497647554306953362312956458703923199969180084694524758403500654442416064508250070732846804
+2519174085201627296034372830011366838603028175377849633378995386798621551863828217907888881997187873208215147973680227021049086
+1003834843003895903348617625671797354229539053440753237068065646834526921585552402882071062806329627104734866652786788079565348
+9629790405359972301542148043545627855421437234097522244411526361848299030888697549739412058687417924390455152178947938956747613
+1220334555078453153775416863741025226449115088431256895031662080047877074330240958104951191074477627437218425259277775462127879
+5330046177874455391020429152325102772616525806909792370732670726443060748075990477694277944732782581654693994482617923050984272
+3673634429035216620140695806733909073383802026068407079504394523147664262305135669486209989893714484828370038683949845972371071
+3708115456116104837959577481370904415573625213784335620684326306607428751455492651914598239687297810388689807875911114963544682
+6275078866641136241403805509431449819259498303907303571719921144438991991012377399643498948247855847742996423485083104296357966
+4819771171509939007698439213480827086866218725106376148904562704537146213203839362150271333692094168029380425896012121918182027
+2363813324380838896838697582331955348538206296702138518105826516120031079298034769024454364560040544650658193748994518844922761
+3584004325313624962617797426518359904557846265454464840046448902633251444504148633006804302389871871448461320891471777760471406
+7015140209188781023966520963877943044151556490498938297548114159848752913311985584190436463500622710986698476383835553548754022
+1839528400463687701674829536257273749291910270980698644016289075485436646251865330303505791679775487148849253452040305315948402
+3145765566550173415234672570838174821210069239627979798684879235063388281638855085067234894023172727303768990495108093511731814
+1483336663514861984292197260930161194717688304395281475857151745194230301582456092278030099203677396095385627051965960418965869
+2854504524032911241727059077016541586716790096641727786446371669834231656716324311341476302384390592511402123780357675520817756
+1896892000036214095213174483595939108751482199845439848320000109938495152786801921343185996467957081886861283697079441114823751
+1013835470696140967938560803552257866025556771879993212750495494783316985507407134125075415195171213975980403552113090097922014
+7515529295471634503543767654884408021479006972212507337901526368761975637401627838535557010674676502841359449244736451534979277
+6386148785910089568558317754358991974549956833481352102962872492406026696207774586778061183616357702706148878186924821100084521
+0786007793408177523760641643227040330556706874975301831960943949711205745890553620154847773954039608277686547389729917607939287
+6601065186724585869718286730900507361468222773067014813540248318802263981782312642062065066278538284353552795463948608367617264
+8710458632884006689061619016115234211820116439477889276589203755014121466655765492211482958675286327074722685854832241409593748
+9721061962175462432000129864627652688757814948302475172688435098625740068901878583888711851475071264973226898929358873311316683
+4174366427344989068552152924708427538956427143878190827546384412926545762544478791156448578168011030464548344644597978114749995
+7360922452061081711320164728509310349083463549987726136205083770590452623618881507969241810844776231293351721107321616807591790
+2550845118266461695500217220306235111000226441822451555820123914245682646337932826709632824811050296875427929721177340139400066
+0537242786569134793043366211458572528023713869510543400208763370329672141795438795279424345734151680580842314157723144187850297
+3691971167907808375655388036762185591921761050859435693988855587355710680373549562866421201047569372572737260475884900803372055
+1007691946206878968978529598838997374929069152901229662680626003917658157134099448777326028788327501120348629153653344792265032
+6789665338488546383152814125714262232923477122140534949024472459646083579525928155625268840134301323030935772657800235228310313
+4868298684968408834649240926318299142611007662477773878693177513443928825272512719998804017438032952107625783388477428012876908
+4309202213419885445857524725380221565049288409243087159437144931986513177158450201360308556789291053726105045930369784581421376
+4918602058560708246713982614793257938660065153424340512931090185661823200932451770267967499779255156975310512692435013776152000
+1110183674703280644653992907629380068789930715341891132020648458097673681456412608084277373854376969813158591776142390000280900
+0445144418946628205657456424237128264942955311965086380583598212294732021966933151948426543613378750502788733253601313302851775
+2374366628960975291734051077636704217339955444337088817734748627762386830985963672836557693273405067738105684469127912825361938
+2027506449534260776940737096467772483868296281393345078755987162674894542324936567113913899614190563606092238595769318736510014
+4601609459626193748838141934701193459914056226332390088463312165368986927729066528661188656389710831973546586554245180984726395
+8820641417137341791284188339243013012221967809583302454529489453970560570507033795822714618813232104921926392983794422966946716
+0917599289793082450351085959141123440985146982836878988204562375158569611940037966919396385952791842444219407364739497415459949
+9477416265026706394163032606799526520617258416558453349947010427060666346412817629143427886670549081801335758913070396959720115
+0666704035859146354165211453275694040361967505403921624893044875089069215309652369723945012113209887458307287755360555234673115
+0255440161315757825615697585801039525106439960924827488627325282298838888854341592966844608858745754258454784788330547612148950
+0874980077738428750262349348089941932765130462263947980854368723919615602845763694707934084120416138718231554631967803081258409
+8981164868907222146030105839525610946849494940635627162577865021292617220051659027789888586435753051650333546661672096178778980
+2620946901150871449077949420947077759285135192780733116251997439655441528374111538899479815498280668657556929167956071921060805
+9030260608320606358567118378046750979991657572292125217943471649264668431650823749458443029769965695844134676138947512285494656
+7911546964476705302214543959264572361084543166660831362636246720337948370592526588629297565497381903059061404007654352003582699
+8922075574627020723499343655693848239182605712427393497956424335482790840429881008002039906918138130808630673506435738463196394
+1030007563952008786387120762737476786971644512140825923263748032598127575949995761019498818566016398257609354069772389656925099
+4044422726596923902940860834745051450250943536191821985629944194928632102239101274072099618807513448554296724965250996986364924
+2354577685813636309146827729776859816069210424412883327405297035176569137490665953223528983078628177275666747947529655966331575
+5477299131598928984485290428357889109417137134680518227595002407302611193611761790018230013945563583265000510580955975339191446
+1619521324601562573756521193045609645344126519940152032470378539517720502293336186421186366939997498341179560168270447355950110
+4230306307869293075421899272149696843537151044956328729562855283491975528896006550623263787552206307775364239158496535813468780
+1611641802461249957884380478543784809385839965522996094364642447223105495756896318541934272292804367584843894271046287233761298
+1709756805199283313621618096481348781674012787506990084789188511001769795898381723775624988249883268986469361054705514036409475
+4042054305280705588082843156563390558519428096353822906407664058875561059644605482196547535261726903242582076817607377960964154
+4253860999746516433043460107715275174182573491654972680242324213294530205657678192111601960601634649905585928529798955700154076
+6676179068384501343541631038132044675296273720164020679619589492139981245074167783663095317254579357724910508792547067262588017
+6293884180622784793929874980896521285454501177558249542530377203281315652064795385736617567836645686619617679168909645709168097
+7743521550856066318163410468235782415369091035062393314878499152138458241235674642599783367386177248502506902767835896501146443
+0483794093371674252980588779386498050198274197464907995529503130294921702208337296889908183028360175355797035085155032755797134
+7360019231801705667141478490298073274830800662389220682649304818227754575701335947775670426238672520023046096705399683924718657
+1560373958818879850684156471739380073353650802319300382801718291634025935869130174150899754981641558303334317282125650661935271
+5092493350585336373714086054348812631829949972662091014907535609939068169965945723736778889287001972766703372105697934518100296
+4734257102525392916687039288087104774233931626636454683584533774360103845888157407165794111547584642769928525653912147278806542
+8822290823497972283964354496248019949369662678090787983018405519062148805449317563743875081526769207312318307346979280704726453
+8280283626279949899078861531461602097441638970306234787225062938541682486544091938804453769368426982357391305981842832099966845
+2217356720554468128605404764499852161966456502338368106620715847133295711653095826628517163144372167241765382757784888551945323
+3293984824292108860635484259719926152739335450946748798660592468126259449417195090268999500256639254414418461654750409028017288
+1675306289991237206693384004427250238261655808453706438418460194044272886240166511333039026240609926117492662156547022216935277
+3798683710262055280473341604637975853707715733359848491914615475081846941708688479067522988710484836724298291195075742855018190
+4581874216800089134728449476207100847781237572690983431502108191722970308605570690039979318708286697553630513952137757229594209
+9413803628857147469961583711007745023208883952507321209502032469098964348049914806057645578293300641835023243516073565578336233
+3421265017714445796604621284137835957308268098924387669789495349357687107880833828961898545436375036341306978848338980923182467
+9343222636188028392447876071807038373006670961664292112334770077234449906744690005047749541517081971030139237186089097495754677
+3197112368581263984569948101844452284212008325999133835851189833940770803601768180655910037983634430639371254776873860967944989
+7762428156063656052457140048976461668407455298961839410706956245596539166362271685772723545123147978715000469199290892122691240
+4878440976953031234401260269958754462435834653516282136155912652234992770322924693740152133726104201502258366755195941397981349
+5410566039278422394352444668313290032035427902945347706947962717669034134093986739640503933965401015646443482046077453432046184
+4739388878693555231586220110918786353416678121114400297535390976972658914130824675010539898056712966138526147925359029678913230
+5886358316255011245098615464017615182438190446564591019394412368509357681569397482568515821423340665852760995420364289038278484
+6311541503127681976206070117236931568310981280275285971795790489631417369196648946460067342315632515195328396495936094906795027
+8224055001487992245066819015245704964683485501844381492046566836373072408682020849321689488337660828971885175876650163928646965
+0254578793821590283140178222280457619069765363934967602749676534057099985483967828656474230988014165618526645571684624945648693
+0109665916508637725280874977575865530242997110923401414431409335639376452646452851515568924163798404754643876369338378812431753
+1218315801760060263870530314784967603071899867258461326183988209146000243519324558810891158838383484826158948667409186010480817
+7903203377696988414945216232421892536173370183150633896237853253925354364816894136252089105545529048726749085139508534886223860
+8148078797101770523716078377874332667044042558325146665083596936734559299430024125955358519934955785765198216278595449870598677
+1116539363983086722722201448783346777178486858969772190694450961667734803002682120934093453206868817575132463247817949468716367
+1637275206589839665316460804048412011573846372603155744795091025936193454883889805228527990919468358500076576823231506244498699
+0027621847956067398935694606560509614067216464874695482321462823676120479915649013012054108931749591716879497574932046754706928
+4550965358813639986179681154209780873107404530149950214180601478806568724333935291072801881538682786052141302073521529721130768
+1636835808005913985865949033373364692120504151732972595493618693947796782831116462924175961942781719381911750675622713009187832
+8144555119970713260660826605512619993205968791014438812251863090080817574324870955751027471809521051989383021792494139844493682
+1585931821612292754292414253292528827165768965683611240737666722015320896218326640019860760530517054982970340862863680710846055
+6536681595996347954437568694119184759342070677456835801973881107420392523103849305532249049602562479138323295711575175876515640
+3486443061013741439479986438866229511864021882422370923187276377158037668029544320414759066219016776345013936686773434186071692
+8652668214037751054395752355562459984977103091936105931037362668574357365575540736744748684242434859190554622399068882473374610
+8580093375714553964201167764812992676992679093090175449230495342109288752328986692009639151993677096258635370756684860954291469
+9964866699458956436463452444822527184213143978744043079921280767307287341419726065990023057954791661193301961189038570454182768
+5099791381798674690627429376704901489902412978407791536768610182213492340739402802196624950327768967894658802241237435134810216
+2644824029820305111520479567245295948221720974051912855629977767969256584700072624737697630748957013069006968156707232150642177
+4694014156265815259320275858444952794733981468869946419687206201356067556770447737925027827372686022309398793525531551762030508
+0692322520193661664579545021783669513925271024381519716157761278129858733071273401229450196329877841294994307214799190419756421
+2529925924690763185785959066401191385349387731434107358942442763904987402826148766868356311114428295259838898928666272489020921
+2079494677073945124622995106365273958525412410850501502163733379133554803716983972906533166904636077433873959124786425510691812
+5600448283577862312179623155268824754692832396408303848264207707120544301021495705368104362648456117090809527815889327217546635
+2343977389207774815138566905589371213682572216665369482458860895527700507201800331270809726620829481769123927780354816652809008
+3857604203317914309286408408516621032904248756858927009945259813983765983907916658284682954733130678932128039594166445571290526
+7783506576165023166951251072092917407173251744876214934915430447355544209919802690055207660666887916247859978935839016078615261
+7480703460843227445195199879222716960672528809567298037159358077924188280933697924269515298429095424116709060884750185401083226
+8717064476124069485152260308142874514219920880901182710267169211713742088964956637523570820108183570127357202528608391772392065
+0183762641286324428853776063863402233453633712505217167155150999046272831538702513532943824820006210590058738974696140094824531
+9112496681140545311761452054846654072950289614507391281868179377997604366151409215985425553727631766796511079991043874131555557
+4848466672408480575274846878733482332783913190570793476048801496992752228173129813319287139570412963303092066006377899503587208
+2004264846825219154033402067536124920004600149381068226608766267724446119288301005499297409144197426544971420258082942394022997
+0140320078386067723015618497818762945156815014583969278200840575341177014900417018827299383394638626203285185921061940008032865
+5962478195492396384491797383201234602669716423445444477699550016949258636112731978273213688262995924599283114955724957765374843
+8311990015515249068920407871121923281094596878515199867380540740586492915851905851867276732161963585489156521545932776243150499
+4592710682075197276504754152068206668838563346968654451648904363538719952128821973082368544846718432978965867108316589932428817
+3552163482893373255049569753046229304178905562057146740570805257427023711941189943044300807285165026750415508222049580394911287
+4596021173135544782173915901528349195173147664807647330846216356295629295015969380040305219923049284417801673254103299322068397
+3943524404368165203936926893260166313850279802117822440456770151714171409778904837544726372346574716859663114202887576413543801
+2969116285326615235890680734637608834483184611588075027596448992877129841445196831709848480423954210927050978003235143506132046
+0153071245386120635128957595884412738484038627307517440237760302728984006580096280602129668935036883924996553872412205753013658
+5621357475787817996023091217050008449865559719579810787563038126520104376758261418798236153692393962370203265309058313384060120
+5031974571476436448786217419749048851015183003367752606459920605017140928435866977820091890996541266633748940714886983142086133
+4562696779266374687250665129144508120768763103068669726719903362264420017240549417302081941962780048493798236161080017811934325
+4744441027688831600256636793504579543928756869184371127623452884135869811364793667736493944686083992892480103958881983194171487
+3993112528998853349337977120649249691278774025202103634228484270608254195748299845801769708524194520077695532568068092195962254
+2329576931503118880223192095103946522402558163495818627264589763485690044385772668639064805859345298816707780560479994433943363
+3218849814933855133187785331003935806771232881004238706522431511966088657254108552621744793383328388740747036182217129765309790
+7924052825089429554499360417535494167874442982520963688982831955472793462543386236218475310833559387701937594241052466519691317
+3120730387098471204669336934308519377296835486747153400369971745719675185172869103202802955453713945706425356726081359191431362
+5436861304614177525957519069526164638577548380287496823470807113570761415650401959363470580496567502232543408020661206474053266
+3120249944908567907826123413136257067078494146549111473184473022022655595636232845880738387277254397911665634549126629364411401
+4035843002062617386757564723259476788690970258752656414372739557004284974159497458955655696811845766981760932359601002427208626
+0779143969819344348002577455948300927630939121921547040685880544649850641595729872650264658050333293212488609440422250520307515
+1460705203029148369614787086632962281691805758071437499284040866802949156450922963941143029043912074471289441815938231327288667
+1549240739672667607945860219999638499322190035348564953406860715951588472937396572245559080251322668950418605324345241657646723
+6681600989234088565629106267156100053645378516406056877177467623317919074902879430656553383602319342476881970725454244483233156
+0192568263169645194866570376494013537343370202553601755904593727729559768993904298684689230055250228064310566719259142616384584
+2226698070135175270997371657677443976168753242911675302780266617573092075405498205119010526964247236701457645067756244640039560
+2411523124866541301070099168413071292074360672744530325093983003307829914552999628543032410966968534244029432252498124255869721
+2032148958117324274615176859919802414958436537913396718375158773684001583339324493639015775574550405787223527127839505198335838
+7873829779466960857655228261450384972633464601331098096364008012962199690499598210503782863578580915221775299630382906076523471
+1033617798236208613493443460691499481184470043787180389655899698166528830636916915480716417683921961582857940369278335021557721
+3570877773431086041166388678403654768190776468384892784896107473099172280071916265352211077124176187206981633533447143541466428
+9162337956051462461244081308639454192982414597589520706270659960902459420484545944118766172576927213645046647438580806130370976
+1679386001024741318115842266812215689927333532837813069949968390429571894735964678235628716093113797167330012932695772923859921
+8804168783787089493714870963570663419696958001331927763315516123670935571014222651056237882407840332672169785104960709919825245
+0497455776366854139775882322268590872937081090128717394425875756408043314452495438785765312873239203328867278937236653265323056
+6042409906538241575209979144212026252259767618647784026916367882392586982801406891358315499203056053321982052638011533498889270
+5665573721287635790869699668106163302621832934471963587290594671222971786422361537494624465628017639194877871599798228379718225
+7432584741479817366719910925645646541846360875945358928938495570674893693392242341873215005147647843928108951666723535877703443
+9626429137239096178611195842928172193314671253797016055524388530347610194243157336306488458466944807366840872517364192307199510
+8872554743012955139567705170988677634651238832225827058388116110755496007697973600003490415480515644505946637930188314840631970
+3992491991103767989877164315291928453885661238942961179632807297112992978760631966972677658662459086278724019257889314597469958
+6669007755891601840756776309575869340114031142955328946684465711503263349456097268207290469828978418533272473362080110971119500
+8033630970428066315841260643530102154382783569132687157611513276699429626479061706898110708339849619210276811595853043955446869
+9768070537230217029438684537825935225327148348372819431279340284261370618005491965480298943126300044774337991256135794900355667
+3657498279192720768668603975934793465689868735015232170607621866439453389115795388712792645934981304662545764256708338815562273
+4841652997648921227154354900004136760485517640549167386012657306424618486993618255961405066483542868908453734101505226047480448
+4390654153631921147807124887078770782524389315313338172327932505555766712042126014521672948387933863420403298182271156860089870
+3083699675349781049946715849913203260143681249018875435801318149856990157414011015651215483550403032096067120964528627647289771
+8136660832504574374548878451558509361941048418373428464399511971079202695299106137651197289051575362091446283996841312766684810
+3676236989934685487277460614965631287879882167402767160319121856718994264197563392677953816932994293095294646864998371569945650
+3049112960977618674809680978004704430920799039334511606915199457270782728770389854739859266964607398443304578468934206463864162
+4020319901840360451062762075624924661391286802372025413278593393390727656336661248466535685907382226627976102440776444559861524
+0166268182450996578449973258577137477283861283683233635300267518223499975003192269667287508860009509128730943175015750710725727
+1027094337033962463834235326303117245639527702316027545974140882034976571260270032549979726479017186330571896766878727628563084
+3735720519280562035416027535373646170800608954405500868661244053278717672230128154298018261865339340499855937060742071802179228
+4620909442780453001381207438741771581539126274686674694429903202199824281873555557550181182902700089108021432193493732079872184
+9458342180011256500005493355500078007350011604607303307732963471459637499551951642174991940916434214889720629725398539493831562
+1757418742866953045608344774690257090125548479597625280633090790836185148048976878560947512134108931123436802430288121604450838
+3439908217353866705662826605127180864607977834354266960510252404933627640585873170058624018410480482791416937234522273135497031
+2172788248827330880258621512418568877495834091216163584166603056260778255791670347944634914745463656259805211952460022859276063
+7062821874356395565274839950114991325558841496177484931811683058289009845398038339874364587482418953564120109998982642304471400
+3698346712015383293895452263862425925615594845734737899372976339855075694671913339207356770288208509103055437248670557197975416
+5731723926926739876475885511154531945948200793682997616742493659519964588297814245753251250515716831733713917292045440536017047
+2326213034490494256432217527368652272393723129996987975280491971552239548286262875444742346718137588580994530639159848308302488
+9664053981063208567695237243202681506536792559295775868533828506782791916794818915656227027388965683683700700077078525885858163
+5667625010472277345606381058073451841188387271842197689932469281333817846476853011214737420944488058943262260113307982047560323
+0376867635943376210756229949512175221086640268169558374511241311647850185329038766762763270981601390818540680562189733654333764
+4491518223112590691196826611428935302844272864063278173063473168207705976253698032183297470010465109985370388667131449602003018
+8802699827748011182168113988637297474486522040228085650948530427329245143454181410142916723537434758973564869412497956238710891
+0653015424586307910784932154517633495234468902775642895621562573878654050393509111804824221865060266482583193591594511748836623
+4094703884414114132180304529532880233548615595688135936066808466092184620343793991343848249436804401054149903884653644876865628
+2718370374189505315521628763517179672356494682994180239553818915110898807872150301279550476267769560111595428023012737770277809
+0983429088572418894311039932871928790123994971756838750348015397853262244219489154464202472581023076365814977799205726076421849
+2244581657719291754700709306659618001196719303854922152332583798578459941542447742263613733064435246505660395020395510382351759
+2371191845917148718985406337649548363315059193935226677398831831786300690640380203874437098924585872141781137278459673035181084
+6868095538827304671263059227883616117642085424440799227282508929248920781388666797060697845611588551792908329555898460456707821
+1192043306305230972108032344493739345654505538181410336224627870081996078504793311999388842368948858806146981869977786056189228
+1263564157432629856155576816827336520937607635620996781728277895852539790604285849253279394716497232033008275892868545867382681
+2337190119883945387644191032300914026172189976929618448527119917727894462635110227775485639758673866947701176216601761844984677
+1541725580846818676211322948610609824222332361334426723507920844056410476870968277509960759021044456134551342168799278225221031
+5808026746515835625867232790523509089624770846326913802756163972740615072842822135746471264238978131846218179577994033108366459
+7209194492748333961784669338759539252535168061991620450390411453076684475148292681430958283119646863377618784660018401847206388
+8164592842234101218973444204368622348477154717654721601252474279965258123105673927507866232148031414671644959483263113289777725
+9536506697075295060127905565119738004002490249111193299408907722018709064690369235720344207608369516256550493184611556526526774
+4560017960261564009218990204461419858845480963206874732488142599183336196461705771053123771553268404282868440226650446328616213
+0784979620602852570679351917990832385632423349482355239911158425540111723754138128518596135522138872178079847769857439148437200
+3065506422221326046922349934844525141835749289303921189806839691414799095653902814723672937020068076690809012734952484971091424
+7531639556490305149862508189711238391327019426642515502558468392326082589336113833462268524671249515158066960751008937821736410
+6252414527138677204351141055246475557495876614593229376289610072418141564580640343324426668169327302426458833085549654617933468
+8091658367794443766667336494599463493723421496560610375457662742614878721712215614199388402972271203457264117746009414601292472
+4908066830822438120188614160836549308604180994779262747990121233555704249867768081188552478880193430879502515548138613493765732
+5079293880539371206967935767115987717076965982796395512686484284292191272158775216705810765026584234552773076439527278292069704
+5164216628992440501162199298685532131413675395537593848742057924552014924010292705113677909421661221880801679108009584398377793
+4121418969859257717214261444608216079650826208617995799712962734646420115576080668425510442736110574190180643945326397724337600
+9884581544962427545759780318699856274991305713483502351242287264905051143111943618139482715140793163760250713362251924403750737
+5001181429052612807248790060512136898354370778167327719757330132811615985502470639866207141577372460429670627788129417134404406
+6178770653157619944192283152223652702640541977712224400210339303510432403323032560310805508239002669348396267104479169736023331
+1565506146888751623012576320991779119855864177643274705087893960131150916233068282254723459661688282729513190349028463435804527
+6845488200397241399013882436401994250911820745822241059508913459645459567274421896167243282273985655453126249904632199335837792
+6040683797579452107027216845343063524780614029426886935760791257030864245182939630838108471908303610357161096840181118609152193
+5867358422344899058837359139467062379239965703229659786120062948805736192330007221916713426793575162507137089954539396331620247
+9120519760679588392286105798236021559061854045122019266108300186277736886734969411204978788065566311792204801446141473355188648
+9729762487738362702158800023376627553944314549674371461896299198497056817939283617350417487984379973531521250384859390378780952
+5278728682099899168824382639886768910340224230494671557124611921288793461227571446099109231672351187529971910075105296077357641
+1730149007222759960804235202582288759192771252526372328644840575023003569331571124411309306137954892577214909905859437364845514
+6359722384817229880817656694157685568966235098606153131789136445509767178564237103959982917552413501317717319150118113725281168
+8331881891680259180368288807257087972744816443005083134263401722243486734946708091896751081947017218318643507133088446490502898
+1564672123742228001093857696640500357335628593848961899541997547484403147074041514838330205353223636545525633021798226061157975
+7577934224848992516208537526305362086756191009198436224096722971843979917310448903629548517759776409320845391838217575441202030
+5842023675100545856824292093806577194777854067803726567456782139496624136800515010149246416535077787552986449619329516458032493
+0373167808153255052885634740314278397690578953752487856466779556596486994777425942109945709709335720717497273570846620327341193
+5952530704523306889233492671665454303269886039975987299656234612350738474857467451882170147036566336312226535534145167519693735
+9607859559588540690534618223279700864577721437927651039992456828233467681820892987538385235563873550538138831743319323285816092
+1624406727909111147099641441681559414299104318980440722709754783222151032344202663364762643657625463452804121615256537142718557
+4340315496406729909696728430969897055002939519672286841554008064322610667892226345008617230358420658804502966997298469146129669
+0210625023915241926959138868143886129423564883883556915150345946486026490910420790564346970440390087533686122782420012907572301
+4721491005031549006749404748103949153294842924575427991607317267682247725581223721840333859898813958860082395329629494670433269
+8089333321693829301610669436388430107322213493559809633043551047784093889175488034859221042528763690657356439399119706918708269
+0081737607011167672164816311361636636595718748621290008823635691873373600228901339494989909273621908199424676593460415730887285
+4160520455923507310701763781457568843470746581847988497318956296776248312754405407533119008905656107514741346097573287623338123
+5386718227154603611476662828982111704301478482540378612558078862521675877095588029121004214011721936617184276464093409939658461
+1979208081789258362592059412017416272899419903367802069424612928998858612300695288310086571610845555893261171864325093713786916
+7319139333841813731995304531194319105663469219744020376897814143833856662869242932535917521586466923358318419175396557400347006
+5043921771833079685531325825310432807800223715751775658072562091646020835717475241682115604301178255769370561929846716138929898
+5795009540103191080406839616053879828656176434583781287476876321448232920090228345539065457933826027880057345811966575002039185
+8576153060956850521311077608763009793771506275720974549550420722202837108735329754654396372138014747847396055096136010954168085
+0509043015950572569270166347532451603412568949379675617083809175396443490772874366901432037667793377607725671409709046037414839
+5757807520296047868933446233650750653295440658940733452331643306076758589809542688132352958487696630197185077693771148210415488
+3493366273573202706880963127674882710949035853748406509260478202136097703296547394474710548706092731416204930859887260446245253
+1707539941222225775800658254639655291940922607284340086831234164821348634212665200587884346716985605251686416602230060503804746
+7119373075229566064030462457605177717171013246215489918839015056056006164706313041702800263980277171617607329962257981016326162
+6663813052725497188713444974040320318581428866821251405183260930030389032259911879414867761739508256774997369921307923003380224
+8543233997255243697045277479565692227756699494957952164631865806868110331658332715068585534381871375140656787606232565908699795
+1127161017080656837915924804407883971278108801828959672411183897706979458144168384325785293840525608900932906069101189576035960
+7746884054099676741518894156142307630763897600710799726835033615686726465390861737711082117067758069961050536090277623500309130
+5637631551447663652036022243883777403508274485804348060822361386569981574710776219228289288499523332852532323527986372935987772
+4799128874055082677319044677884361786887526377254867769810507962743180135340211433750487850964619355570684078365963703331785531
+0073682589254914802156389462761084682583678912826358978335933715271645287806405047356166648799977142475160038979372628423949010
+5037559719886724670132444119093240447382541873564218599313650731701908225623880448841585926824993839038111972019595929993742491
+3846935441857871521862191302228658206156991884533871767438656661539104499878809823997230034119838267962065754111334791148146756
+1506245754838722163589450414720903186576980445131544657545019758753225527419416112605350003805887953770147934624442363883801265
+7711965724693431682894274811945992120534708309601562503539815868676726704850890815034768784240539682384600476706665486329906626
+5956050270087533659778978762952993742209890928275529257391035690977242967921950083594415755279086778292240063613624273000623384
+5061387982251874414971585573609892535056862802605728035065909921406395624271235709374930413322182966464210152496167481038893673
+7793264955081367428964822852138933334974506780923885826935088471472828950440677885279984646325294353993045156334916727728658382
+1917731844388737433964393775321834810791126648863902100900130682254900663770885502300591056044829585219310561565900983432788348
+3993621103753371559559083065225969001381490024230870158740460349214225265354617541796726739208926003200650331011617584531364466
+6446975200293349558151403162258385505474942322796455463090381985898884153879810666921247678344495019592171989327800934238087607
+1116773012813841761179870425820266292137052144431441290909627977940969824030291459806507439794936788928214828707352139273391574
+6029232735235425403035383736905446200540026716844974571516139411975848154720481565143793111521425975198184192780712740114138327
+3438200310045736349450654856319455355471806503450945057852390828051199118282010495739738213447341204668213941183921897766832892
+9512957847613586351781261772535091586107882959218997758350989715296118346024725200133884012765597340862400507624462524830866480
+9478843365776113648646455826476363854336443473601804016310466451767185956320296981753166811182992550179769973329037834636002638
+1745421142947154461000688129964181745046963595109768527672990383210124171587972151958957748633651595231193536560491908213623383
+8381825139460307549572877031135183947681591383140425137518397676071788098018785187454915609863724531998066262732015118963304139
+9818630925621801216199389879103728134389152002296761687336537102178195168590959317811012194485775439363610537061412149495648268
+5576817033233193054333141148999572966012541792116109714940451926593836005748304065707002129553500879663495665687664101078961830
+4255249811578737819490016920102133439336759727576849642889727534022902117660385461887412305323198051682727105599743797538768483
+5664318936157823403995526721241574938566862585452228404066914834889748254113822291330168260243598542768358287033612921584775608
+0493408359374626915181620402845179233550927620380852963377274566085358451742815682206366209318504599243115355217504587070160767
+5099926458337087971802835525020183140934847289656680603935783200084783016975906879446974951582977123093907468193624294378414602
+4993211036037539293757401608261712055642333911428904305517543773653002323722539705273891988338327482438288308063770111207012273
+8875724448927612453412899117913683062983270974383158999932195926949387111141855398745328636343443301765332909049991525667183004
+6179446485196106673286301271613059516541037127280321853066460858041150601008945716021915010720764523897185471929927560029444239
+7849437984569538042541347312104898444874295714765888754190517892771505925662567504469022216257045253341087785885957187833718309
+9972288762936380366686950714951282499790474803745721728891585856096753079311064364081796195123806475478622506713826868777638697
+5194143783169339034131894869316961917794611019135131983101366014715857076410377619181633332553598229324447853163042312520962414
+7850854551539305001687198329060780010579189214774936469033426991594801002823836027328068965959941131816419243666581830678041716
+2062179831972241107526467338284038440066567441767013516710832064119073030278681905009991848241324570216334414105094116172288746
+4795251857046503954973485018229646234695366724410250031504983138843493652944866619750102836093665932368212191653037534272918686
+1825362974498797050137125577095725107017850998954189361286965048355333973664280494182300562942448127524039989758648090694962142
+7512994410145549835156679857014752505125401506747737470958447208937721056830032278112608932324610937928836512547690813007773206
+4386958625254464154906642431853347789932184826155599439488217117827733831342079710541861559451261895702289359997911170346503767
+9160582845194443225222601665399912946931088757458941216770145834719498890068834370787508728005299127862046720974369218083539582
+4881031377785621947067985825999914746359269429111016243690638440462655472434228579718379181809439967478754245522265321625889814
+7583391301685587265357562950095622866121830355803288828241373074939869852539741493888550714334780322503664271906152272539287229
+3706056275918240737054417094100085374094932331005897520832184041773254725650156202489186855782648043533132404772816727073155235
+8593562217884076811451277453364735377701544569033315203869164836320799479709306444027657854268527295924524538225997862678112859
+4570537859634341717395527618756161556420569519217630387646444203036568601265546935410843254883517475649241288633895824882290087
+1279603976070610116464640212199310166444520867245963242449012132718994226744403248200981139871780434324112903659101791778621066
+8744850384566117283317344846157583437411072049976031321951124766354609384768681179440522110424899002915456603055956128713981139
+2086242661312485180876173221212851654741063402662853918748324706267356051777749583559232529239969008936507197332763290031477120
+5741215520375853751719868036345389495144698592395029595732821924732143612679143914116460149908254801423378398341400612840255578
+3112678009802694849286559093313827681147182296039209347542924704088172807791962585025279313952354773038812296501897230865202710
+2464335074070148432312036647984428094369519448454963043288725321796755075626414550577697084871002645789785381682654641241100283
+4946700365473689782081952042866282556327651210752194953923594323433725250140138447685850292340132652464859222629234697220377811
+4116813834263078090553178959891950239969717708797371397856902146227502290357214553371450093318491311749632101080525636146301695
+2152016442288947698443136330933042135184223974200115803798042702098262975256411368585240157169341361695851434355296732786801088
+9469700239580500443632308541309983452163906017765379912144038775472527920834490565234287360219977902823838503195349727039831496
+2028576502159755428471922748239092215954614499408923132851493814161260002491760119779606365853853991681827617094579573055586297
+3640678920108595929213187711839271941417061119448282180155978731064884982006841462863880420761509974612500984423805360525276222
+9057118337335912039094779552592972943649024122835147704439083152493402341167911887606112405528052285968546122798145084807566159
+4304613049097528789015322647077710992450848025235239429386820053371823148160964657760192249248892087179211556970604610852657330
+1245963067779593226119382101475675796217312455063935339967592594066075071514347181089457321147516518204553844378465193273590500
+3560863140415397624008978961463819965678362699058645101497391867248986869781266285523093686811424022579360460735505488281520907
+2803810314481228865478572362393166113955034570401397318410902932552817985751479490450351950758398971928389088057335245044158094
+6904347745025056517093981246275608711548205826384671869194152526627350920208727208140128575295910227390194690418706771705356517
+6784445719916791606648643520294851397681933118673503958741728387886357271190905065762821681465016058740202568162846967243295973
+1820495748778970925066926664077661706850366307799032827973753165199895444172414611070770446635902894354703969177838887030507999
+0792366480532040444153327711554056488308633552915589047332411364711058132183546270866868018652349880999177379420796287072716088
+2231884404962985945388134094475613555762253572694848559208422137166239633417739879274457716224035685193748560132590653034477542
+9227302311116220471908055555125965124068362598930072116668063472712158786276348904469695948132587468164071579543544049342283942
+9611661683770276849635190630772488322125598419492636769106569145188958898006930644639421498885045868655337164693651551682789719
+8113170194159795409724804157277970216585110875118496676005194638884485314135820103479833056690555003499859437927213123666961409
+6776248629614262117061005539488708741664752240716973399951870993215840911122617246729216135676971155075389185544568368200715006
+8136621653681348621828391620654330376833126244814473075974634681828022721817501734663865372891778488609175456672709780494092424
+7509035477896901683836806362847630551058479464889625032860924968434340014421918549778761662492676219077042005549667470710873708
+2649270641258444022173705146602820338815565069036316996296828717613516424116147690610506944602495068800321856748967379303431711
+5231537094318273489411666006633698888790246462698166129109823556983405782712006150780252324827311704109848150151626541203089319
+5293239066624699492800648051071066181862007268310279648019183315312315154420858012591159812489763989269552995744386956174038764
+5180720261104219765835445462051189983679962609760132661239453035110340712611783326617205712026077627868902275865901764502746369
+4450386186789754245435591998462910276602998139642701382886884245787698610667584456364442583085157908011542453439257529663938908
+5226947020891494666123742174916211157087031239651884379910014927950876644487562604700114503798045681730239237952766587287565756
+3462320891328376981719619778327669975981463699579856289946252639770341221258397441894692753073255239973756891174514808164393544
+9266128730309970612623389424292152551017956433451773715730990286170012828117563840968654996015507568606746254308032751484010172
+9555122523637838569715536561794279389081447703619598960381475663155959964617699927258813445644496349054324074619586132556815203
+5221901221258703935673357600398356681976947446424967337708716326590353253394660639230448040100077013280765926948098493319213488
+7738313289310543436800301466124075949448435224583670124694327098481119456888840896351512543815188557251685118660772588456625224
+6115002819234894874533900222654850689485882307323315708374429887345170183105778321445910604513739852020875884337203588872923125
+4481043241227156956639553841037732426965917364470043436075190174090995043087977394594850901991029121373900633832712403510778230
+1122190232976475343331179295988355035324572960682589565916578492624347219825791452145522290660285362795514899273106419997278153
+1419535386080392454227188259532485710914908620105317213100011817889875764632911121751593887025644393163109071422951719422847110
+4026612711274029089236246041114948354793310083266181854689070097597525414068795108775947050469531123122537281180760454160254035
+2729212202223251132035733428110959851887971832113712091873626429082924950281013969697115103891338579818898846568239238607918122
+3944336153317752913161793886424178237035722936447760222478425805766217641600209813232221230340238786982394323446453582721990048
+7389193916919980057221104426235427350670234767999865432553198312811347361703697530913350075859737082487587469312736993623735804
+3544483515704686277538264527506961791275819582201516681389283444580314635355964056417380225809498367162186604237676145482322561
+8044600252747925830317760868421526571377975782889497428302869692743382713250361972424374300944696385157823203594995989063758674
+3762181316198228161833937930845505733610147834846550265056669736693282801787541130363631664735877621678425882651996823896571197
+4895759837384473598984792357851123553619562828621778670882704444499813426092540279529447104250292800981220546692084253328082420
+4664284555514464728238600094152484535233997991752935740228264651440639886242409459644164822259574135218995760166441434144147387
+3498021732532747332097779512063273078194846290742584872890698856916194513341236677884416300942002054144602101645686192153654576
+8855689629475186087358536061769600329981635356231999344927571715122048450556630571843667383074529954198709235538731487573715687
+0984316998018946399866843104618259659452795653432490384229487374720689309493558506727485555071518696965289338830868013877431679
+0444954460337393289812378506420855357215741077375742703669752012654590715324153275679920752247842054109194186158654335712157841
+2806861505564373354176276173563926841713871053400626160801979041772088503472612997224598155147542728678254353573523697935567654
+6201924274245126686318859488923564788418058568530778365444195042057133158737326264356888205129275667061366349202778458019010774
+2825177079603097543301363195546845866777243546459927001122927276132658961336248692066215766333309788747162494346240324193946246
+7328522607444197904276536531669234484641234327006749709725328245867037809150903161226855351918234564454937188245329779811527397
+1625377992337069927288579727970280388115743434164021261444485502332859966787759877144357204976585729746356637542057830900380879
+4756314028565636147037500545330319143265189233753100563686689461353510356901840785161069243491300815016067752040583292254841464
+0425017333645387838654294817531355494569985613245897735076448718279104158222119913920255342054852667882224523660815046839280651
+9062897569747184612738179958208393387812077029581124581459197624411283206076395360970022007778409057996215320186949888642491834
+2577588591174250273899408593063983438617592453792302359558473005206418002455294336176016723332413815891373160708758731967049062
+3790766334026767123109787766877375184100806711868340730414046922950551256206928850545228229670325982658231736019892656930961551
+5274543406306956723055597804421123472449821052046299950205504470231963135543548703265039753201973863356153745730092781664650899
+1020617263114480064430348590768589835423732129147820366131428529210137664442462332795234431300140813802687903923031421483099298
+3305606503022918455845722586154193433226668761115620627747430416848925633688922763380741392673785175993422375485098655310345526
+2853130953848078288453311632699255400113689129756388559283548184844635112023417531659479267970268571040812683475165664822794180
+2783222167931397034746003825257822695087707764404029816076797619920932960124572983887919479900468345097640119343412470086673322
+5063459185940735886394343828328918625032505938760162817991123725871771735016474675217009872180054875341819281047070252038306775
+0743585397605286027482664572990290216960312219499687628442325704541075906118067163819053997876546874075941147761887253181403133
+6865060056069818696891296915545023370983419980885799857058396262667622091719201948407642987224698259796247084724028705854417594
+5103827826152310417357275607217586307830343393236258610369278200854730301259212109525027296782910788706655437239982908254923137
+2959652192735329005701145454769790852470342092444456431448859896236135922540005403226570654335981197446157556763871319983952696
+0906069491801564153648838254163601062811138002404571553190646376754817601328289018602749191681199089353060650264442584766903530
+3785962322135501816792718661619323345882587573641791662855806452191640690223489872037123172150522718319643946771618053874607301
+2342704599377336428681571005102144288192803466969307063516540780329331225964749753260124769353818714585772490856102378132713276
+4346236542835966635872778222659462346707942811767870117146806978169322604045750387880280187005012616459999816635343308178563646
+2604219260434304257671433967264369756269802345023491459538543248359901859356108205297353830910989444923284454022447613985397264
+1822281949178892000423296707942037651472365683251029280064728588016134363373058610506594311454908111460545368768742973357987311
+2329670499086760430314104242828210716854904379725565610986919473143807393666799098016719544449077169306161547903571473642324181
+8934928646320239275117990276319738648757543739070170895539210951333884142223117539519009532014319073300363829125825739466521964
+5363386211310899141728954217940413318460520197666536176317994465965648033515827854532405714333529319178360920611572195490491843
+6452281693971710923703852296775814957821367584399432406445144322839651572894248840082293918339020670715780310479909368596480688
+6791949317913799774656284904153563675547018432823443924016298235065082832647707880299401729868016947630432394689913082273372425
+2712968598557679357916581334926350397464524640833937031346811806334561647348253048938805411658427143226876519485429485016393766
+3501555543617126115194082213265703065410803089224710636262686284845574699295863975355551722711478618786950261560124771603773061
+4778106677024357003045486275897639115668057170330533010873096634039731123238801834051871842868704307554039712015191582514954442
+5218459195255301650149970279364690486331464065970810654696223977244841051824600951397161627678662117382548039349844217280375193
+6369806374093253248520031657537241583648618465123745039819043766572718344368140639003289414418211436811709774570097952888487167
+3212569840247911007598018387084803647762488058555511319640016886915147136497977845568137947542869347226726490373484609221240787
+8115733543956480787117884715874295702599005706164646884593210924736152784838359510894224199377258864940900115663844969555460182
+2035968818201814843503316301816877369650620471604903993852843829395302301918155158237168629501277731356144310878037185323999107
+7016895419441126229181619830275636225832821520441765441532992753638148826237793875874434736200782222141244213180375828740996801
+5879711152250078980107885067914386728437059276590755707069830533352692084569773933300266007591174281283361187767672358396078896
+2103537195144138796197574043874859185879649977538344432422677102393984939164145250471907596342652013494773096173424264207508962
+0637450827987698515011845992398093937196147180755217329303542644463406470700019971836100495535322254679390620873420862364850762
+2242509562912546291760696517385259786276250406593124098460913531494124669973775469757781521279236307631066606896102762073078153
+8737688554624301439839538446862017884613896797755819281023174101498754986747558403862071766932594675733495440363990431783540137
+3643542527592425148722339107873667468772709136145667446671572809454163340131116640859776867285040887038441378816294697995941474
+4072206008606547388536544456067257224875289444010744788037863160664893445070574937489602184055019861155649531412106370948013649
+6183624181311379076807905566573341779391313360549851142539899794930473883081910943750299100861533261211231956101452244671916467
+4790552691647255291761946345206897704211085378644313837821311423673070233392146600975258580259558879486034230540380014801626096
+8493966397430159495762611418791059378501633459275242578770822154956094389019127421733416568122031957966837378624113082091125501
+0539497663700011903785013114734351822728368447618541431249895153026462750771721023669565811790420914410370442390790070707245463
+2527965030066432300857015457970368291786471653036513592059650961230415181073725654607900007084498257528783224577191374901431098
+5466092963804647249090725375187844347347973252108137441562290526430827908072841935677879142427224945383497721669674256500195118
+9408447458584058076150017650238543964665522204847767119461148283020725314993208318241105785737923682521127890161621980525163933
+7752816476751548314213662757572297632611588857400086488089795605852388674435780461993562784936271707018785480608983595358835686
+1627393802741824989025898363620676709684659912421866285079664625171969200262501658717867654051389804050637814037774619076628490
+9122449665202107140311875578301366613855230050319765976709818479408721612162782387682958793989254712472790259401394162587792903
+9264559273820216137804057886666471549044481178190332632113699758788705141611700544482989913381964978281793867160157791927781162
+7442806842403069859300613325533104981898816922110133255013384334075830779759933886533885733793824024671542171085144755776119332
+7374346360629846250873248611855740390376331086859870274251856769041575442564535703086946429812945653348220186072122845016274001
+8100158244663714389704533217051390472696914158612218153906542802690978033894796544874039962095788720080152937661496672600961913
+8620241055478925684985952252838411836616234675852362577897905957450930653087681187667293254151875334644179085362678160756183911
+7978254875299875225763061871403474457110245655385719997304830996169804380424203018555208820048813202142753962116252594621406974
+1364681806031729655441460904058555518845771287158086951978113218142925356256811479736849256168552051145501834683683179144053582
+2064837061784377038174422796078941972546986123715738128334902017019689407784830561790843652346745495974010607663653352384636987
+9087616048769273749416367719522093035127707930211676277159029972485006678648961483209994033836189245748110099847024086616545737
+2425064383233144306141397196556964739088709046393835346029594675076399505634895487000914867003535813058158157320486332684663652
+3641097021982425901903299759975001000185954507785071466003606303822049570876073457705939373716255467071337231807741213874106729
+2074354309025181421785407070622306037112442163872375219312465679573739444271473076859615411141496918260111756219972558400237414
+9209218175245343776137887607783882100053568632353169828579551734386860768832081473967959877027533280331064368843953279403791000
+7265829914895705780556070716875430476662014009364335116363868273301526498001345684876869560767489114942311375190271613882803603
+9073891388696315073189212242611726526377243973277573301675482213008892303352424672983354043608654230919446999369674504952411077
+2313808555572186833151976371065120343070868637724954931470642187595688232146689299510744666262728998553432846824564736716304195
+3769895001051711590090397709284289543423142627611293076964116196325536683515731394758243179761144577336943990391686351744541117
+1964012423430274286597296893918822905314758106425920575603004465793377045724816176059995632780349523671266024041147016652652055
+0559141307894322726836380567121144490621939523042182901839217710526781776038951549469639294413748250130589664480237146063632821
+2784427615240187672159066907559581170138189996990499287132279332580644422377771338142338877270406145886924306247277891647319839
+2650622840124168882146785089864582520075975814107450314378337065910303739372347881027629224527453006767239445485125470798573294
+3280112665923668502905138798645913537592166171499662307256909576761808318862002890184471250591748083711310397550032446473077789
+4839123297739060737950671029462682374736375690549900393153725695518603231578972526440776594614418742798429193873047497505681792
+2160244025080490634108186799676843921536142621408043650219395075800794132235618687434126288996783749492148526728267890467762275
+1151778651927614305188542555589072273825319471951036866487051470913760762080070986450018226884129812856690672034368570260461972
+9126667808863381235489349849691246557114377306076458702232805159967351257175416964221955677360994319567614203175199799743819984
+2789442446232943685597991603590204183390799819475475321518636276804097467590827293001641282750302064255269776064371623832516088
+9048597881455099698450226466082784483581892839976853703691711348479752784919013613635237082895964344395914096977829703979539035
+8807651873851261763689740610852384724724967281185663138373836249447037268804159569417135422054907833329936731832253007919797504
+9682114913920055259992108818897312911322686928213632559659016546514207889796765657343025470035022686294498921433293889021982807
+8817906539189722113102359692407543788732651010055394962852526688290033541790486992705883840600079101359528027208567808930305163
+9801041923433800395009066327257582729179435202758752590945790035180893649947139262456916818609204478389874916889421571462394032
+7712450051093466464431798727528046026835894856944238434402423528849559439733559946888997104896406027931037956349309616326923736
+7381318701427430852131274547674285844624653982181746045743742319196948480723763005752758284784444958915729789741525394299696626
+8012218598270213765952492120607042939337977067878086380794314818747633639449994732495580724511274417714861329582888877331906442
+2523903559053376560461999356914800460953183047966595580074070441846526092785101396532452282664986312641571216344907286853277587
+1243980803716723402043316042450038929890705999070870015541470833748745344879737850504389676782666386423839519311757255510240006
+0284528532586136580475966266604417479884520212063362364900502892825693493079279816397630592037794996982087214380723458893748385
+8491272727902175551882935376152929301347887913314101691264776996119552678466629354884721510455050616404890619695271496162337915
+4545341965713318896843475698632445949069586135305533687841423447686352614650216106958803696792920165610566274323872801678178779
+8253568664915132158211550322533453124118327929548882623091786963905677622475126883200587876894319717512008420758223683547396925
+4320222323998014931144025979173468123790086139354433220062005544015035220976182446830891814234515809043692298378909223491021578
+6069959232219660879097232566121384126364624848136634056377125102029351039021829959177114631501219753707218086851316623762802248
+1243816089430429483661271140945607300465854350055161784219266668283907250544685294916674983006906835039612884905549454140955379
+2940117682598404016293743763452820571055836767681621549318648097809089905651411870200800086998457828557152804031061902717793951
+0887454608619720066585775426385076124950271424460822511049331848391671487328356192926497422819817241814088663154002962024098217
+9444111199203225196678001748854632792810817288744330344130819478809411416720197937516411714390009340089903953898652786438479523
+7598508564858904067093707855688285940754985295788676773297431147947757643127210193954685014018553421494459901761944702436530765
+5554085843289054481441810390185341385291272744398367506999297552891321596456006697431455499740285520112057597547672427356435569
+0013578994633080338189924814677511395910036898885609486453589361725442884886155382037285922038189976648035996103250646536792347
+1883418355117695192895288397176362340054382375638457044029914555409870529840507997093953867543753807297378240486101911704147190
+2990020394219301141282427939313186733000711509741075546302432127423255702951507832353089573401235669455023017949653420450062207
+8315834094959817998047438269545055161942585493293325815723771181252407447320553420868080424394122133699301368250012158017016770
+9114429395330391270070591803725103499827663830583921855069504046749255370339126443177002479229837662039928889147633055859281868
+0939693955047378469672103416236905988750384823305338476710533963327706820167318110473623797427088982971507090747733464699600155
+8097749323633489883895572126941411948413387610953411492455863784508332803867377054591645781447379503035057961144435257072818355
+9192774536491861553570480071143726445650506118482951514380572367117987602662371433431531020944047345411439555055616659122572444
+2538272673224446791161100046059076794348690288664907501420986291128393194698926073716590796828226666658940692534781574652080599
+2296719356672708630298340102476096286223198315529342168688227248665999468122934752834636542066357602969267253948955801596039200
+6907553929212877794229661239340340054507529389112502857484240836627584226292443778415389852020999685448069205241033372399261985
+6092552080660661596415004237982747843962036754844362941207857067711980933061648692291784758051313128780610506614569982941900763
+6594390851938570829005416110125258734178056235062424322731777215369780823020661620803238711218728587137816612075854867828598400
+2369696331217866566447853409278304508453286888356285386844080814982619783652943626843027594633000036437577975836948042581832383
+0948885007237584172710171695745820012612068700229335944852613395850206862454317862915465465928827325249777743488489409096560811
+5495911603990067019527969794975740716100732404562122420639048240417867412633964511077857983711654955131598842753406211465747911
+5938576990907415666730959973171116867930776870120598849297289380213982472240243585128799882672536952585668000017332908127868142
+0055033948608802263653030525631019632385167453147504582749896613855370979829552517051177850239757173815628192095505002356755838
+1575006377951552426189315697593571157901434403253801500948115475871805154047796850271348643125694619380221648554282326550822126
+5246972276283601394823321357823533983734860648197127606415601325852813899044500843947933650765212255657169653289842270182408561
+2963795283400693969427927841410518920229478373496996799858803689356286312942605835353285929732637824507016592351551689198434905
+4524116354075005325609861714463374588743076763717669989113993414649241279740839454455938573607498636902929162122468763846383424
+2179849115762842803410844590988059861418931490923531363860515702620355825744742928541840867928398829472206209785674120570623101
+1132410047750617625576007081275570045071771592714539836172004355577617397790511943990307565673693827096029990088810389666652957
+3079203667265148591706387956264742397674809071114000619637965798572137055721279282178439992636758230593462657176883252897846130
+5344900606236775949063632708480760988922321343844454792539062870953446557548709705912512202634518627191679599405320534739710674
+4862620838291477498931509821859436769537924979388766030614053473312195673928520927507333262772931790461823017698325114264269689
+0377879474949535999373402143435358728101597553950835828260875850446040578864121150552326559433858342085551900119266465442357108
+4145382952202338626169521528905963930174893641795335885386219002691641231007259917968036502863440853204735639598211642320126801
+0053580536687636415170048134719028636721663473814357492351910729926031799390889508364212752500797332425619171871273560570543315
+8050888999124989277531284920879308536986968026163965044507397321505480674446271580916011349473678101309289578265591746813517726
+9127557909914237400136577868957543371638044740008283166851799275961511059368672159330761617818453900045874047935222126146402161
+4101481561011635460925901510238481810190290058999387022386961480571796642806735909558855831574016730200955930521599776711652022
+7452149234766310409197279968867850647491580237728049077688692166936015804308350068889158066597960097627065379539367797830770392
+6879895654050303365324517468233477011666079944449521630351405739029720149442284020545119121309386081120398471736260643772075320
+5115668578180735659993042798673877885823921120201277569914715190894516855160960884928665814998466370463245773786729580361126788
+8473676321663825127148201234179810956242584805477442480418075610556509294721684997709018216961441699698479559880791844442850980
+2548233794760268816189190401306088756408880212519056730724214290704225280819394151931727397286420914387903845669497115561372625
+3358354482836700948199493625980064917823071542164808097350543961229800125334834517703864655364546055166975880935305435123088821
+4029969129548193511513014303632741396672093205336941776475040363815521979058565558783096959704099250216961508907068930707743800
+1178228259948098596059380680409565881553234195364086559565498076952409655440130991639052974945372324956190156780171629355058755
+3717169015464986627001032179838523927735142460855957466743630432390818286505306791995379349323709241837876168544133279436428880
+0351514453291951960472553858319673428002898082287147987459621016579844258976392337653325512601241626465492005157367458123795393
+9131757913676253650480410533013952331883655576543674109012844727933443442812463625615079052305206439748070329783436962037461924
+2344960044770585240104572826430912626099098553793285442582298302002106108601045902079657749391794040816491373923940544837370962
+9188063701594180602103941124399234673973525989100931802175158910488942922514429931243842291939057260146437903218286048586526737
+3095726475590315515951883606439041451987645791724176078005404488548116509110488969805623639698399122683827452715501916665020036
+3403203657780121846439527513421356719526606981096988845264774034545984754667811956286997210908649753612024363260420418331459837
+6454363503953069085653959466382547762654112282647446898596667543948487517796676159860624750118940186171824534509979950086899125
+5534857215488234005757824538224541774649888325359087056984429790126545819871211147018201409980430263764262297169187413523924493
+9520167452539794941218775260774423444492261204451489938948286717754151689428746487424118400020813014135629700319029471552190487
+7649753857278617517384047446362214242830920706961544783469693002591616096695611398984815665331683937899607935227857197308530722
+7670636468635321903676766861271780561993826318676409654225250617146887843176296360469702345236373355189175304203166464435492803
+5456942248296553684603690989598415553795292969337585462669697131930121000520692716176831920728412650435826182698878423955991084
+2896202227362420166816298936702205787111522693592087473120377589659651412246131193859654870409149102874068068052947526362484606
+6206499177988103420772046456006763763163890633653756586913836205106440292257489426046140931638490258992453397047593430476263734
+8271727426541847240045919975482895895407596972876222349935866226855009736203327632117757403576107132386631830517560425145954967
+4982163925157138555939635994371164500846077564198212229817459032427881591645290463697023178851238007473163893076170963474781460
+5340106261127351887331618946742533731988940154583287036382074049074320856289664772105865760586792346984849386692407381048942810
+8539587910802062328556477423232706345676834247983911515809748455837801552264721412722228887311117555317778442883915233779797479
+1727978384302123967727306531882414560603798977850417620003458650086712045078303090511550979287673387880893466154163854646269635
+3674694578655904749986580598395421685146833662087197374056652325798896836233778806349388223093547068287833955056912724333066803
+2847637229990901535043145484946473452323017593046078412652932709449735113175295374406245481235052704111601101677970510368326922
+2791471564967916436181421827384161108238141389611296884460017859614820709694863977807620407661790121758211278587753750388535470
+1311682212671438808292446213587823526675524926735249896308087156166254699859676499961522597030531906137578453887072208144785351
+8861987970713845651946125749765842589051394459161283498525078704659636051445265425124710568264660637581231331333166906616781773
+3433773030784699549858220921642631039795495279596839707512577767723632096893086622754554818674187555230885034907077860457028892
+0456580053379968368017945695164763479833506838952019851181545387562584359601036032261663315698690958554540494006314322814695152
+0089934480486704619783110767294727013349926542271497056296250118282426029001430520413060977864809649544418723152448749796245164
+6374218433638081986774399897692332350976246009622586461188714603950733284096247572024844313234627483374886751903785440297788166
+1964624071497448806005939877571581081852368682713329198774704389508439970356078811686024907131424792844471710419031994307710495
+0920647722499203428391025133284362175932945797352824069655533852410541721344987923656955005597638885921881748026281505225146701
+3234051414875467310335184839402728147911090604477636334326355603404083470772369446633927746336105082555084803709873030579813182
+0797776807854225896647327655002411099428092825155001834564019066984990634531216819521296497699004639732085677368728818595315930
+7917485162442064658421046487728607879599371289976088757626588362451318559683586821768061531908102225442474938214076282479553260
+3281219759953705660325535461460598775637270570011648848817233301493712654518786509665608881437564458093540417006933366539835720
+1421309961668710980725741781573712344943061720229290458895090456489735933725778071381711038599743236066437961925604705889777444
+5346018484213473348778149540609702140487404833149084935132956734625173249282732560039608351835971014828152667004296001672327334
+7640982015534543149522949001287972675835062998825649759593191032854308472369740597155188057572429051521288244481472576347709112
+9082197142126709759172581677046792938596869866773476159806997279087695007866672568094682918889951065921351285356324461616422296
+1936662836367636814393593918150500159197921407091608653457518897602784067757706017281722377124420704953813373267377728149707235
+6165532554189463034890275736530147346375384892741034329027227244542906540148716547806611470041759808947343102903725834811540237
+9921590940060069893953324679767980790622906014798953371116800849894891003273141853411016879477894602450403366892842855960933978
+7315523767557595011955152358473653019805790165086637876204849356737581570450280098237545014539966107468231674446113357850428012
+0791096311925956512226765013630421811573099687378388596324590465120594475232654312603704526616319090075205150090415360289991719
+6209585520294606187513003055352209151687938901113926217849214203137326771247519247105616300171713950372822794825746012319922943
+9070419207282434237195104895273960005868745134822958234433238365905514670266360172103212277318139495451964580465731804042546085
+0338167338157532972668177758079386489083653270128069387600686406564818006155678752863600080494279043355117187180589834925431100
+6075857929007054805987361298779916735419742025429402324367885856941288459616727309405216361897524393233989298288583563658786859
+8295608945048628864124667559446303925571884604451666719475562297491635918267804843940029802361638899118153382320671609177821037
+2582167131471095203583988388775565537112236568527071226697464466863969482609071992299656322827744545682290545625251014139439495
+6711594101773826530320065101211025715415340393938808536071030195055575879765597974028194836866850448633781263352118203830334159
+1911464166497757327229347266491166768994040887477045432967042061773419808596553435219059712816623298485611786304164577509711093
+3950559965553312195375204426888631697136007142008473612408896359608938295800221018496826509159015008898585495437881710932385623
+9874188189105976892158996129334251306053998794609627074731940358792016931428037315501950874633599120688188498035110487709165641
+4173410887164627415991784444779118017795312676797160939963018529923226506062126935003504945358174169319649592822030532548902364
+8585536437904001642599877592181317351676828771494354438414987542591562928890147892012194379909967644778402105597291718886776458
+3150820435297838229930820366686733000243384455249980345366643081949584071763731857162948259797374460060553393333323596509856155
+2746510308210106138913961915766655928022321725147254596535903741506128248245569457512888067134893515592196316478265340857967148
+6054837822399734332369250046782008884610626357811684106025662192613352002782118381922758419491552146516596733810475017566505975
+6253444244691352274570036070483313882748278795425532524034702609588633374333913295809727607310412619066512211586460777396607177
+3167935626890486882612342937895694862011472784369829386553959207681859657350791878067764914715082125859929851130735487337849909
+5973912099248621614115761320919410184939653960557823675647875630413749948258747675478750350454945866579601771984960798194388016
+9736525221109913891380740014791803647462175891768280453619965529263318350088005137408675181210618289125588737889391858187625884
+5353369021308107059796622691343010568879776199002760578714065302617216068310095438159704609241785014319825155619864292170880710
+0495180914933316707105009248960814921465681956792191416760665299694180526760284922837494706424443747428740900047510907222820027
+4261167178860446527279234457781216359164057184535569399549566971774741437839602392078186827336187328588770123788484074481402098
+3638667122645479534954458961543608733857643210245423464371257036918768143627288762652953247716922315676522443004771243444008790
+3924515546743559568892457871009003770852048769643235894176832052809028875813896140562020415910166599360845331504914716199418304
+9539930208848580218543922990732130838884473458954810662182599563214576790823089949536669626168272941913640024171496275351316441
+6014586121604715045014833563011298445249992633905973084716393755263990314978408352185626630254184110544304520462563363100889663
+1480056209827971737404379030390423810733649879094610502529510552900145205746169635070607870308190199905737823014183804945008242
+0269907341608215559877018486447313197581053179139277368261940240899846162645640750726730556726252880111678045833842135360488520
+9452683639389882051701960541518755636274003173728067144992243393027569642308110984514593826650393132965688544590683455796310124
+7380252617100440281579567534384005518334110526934315682916800234325208500512344342386934373532140277510905603770493859349394883
+1640841298979540048287075269187639921568678590871873233480612103263772909669941767642148108401983790040311768132667513845995891
+0797228841202589730512673576721011566549518209931565777081305309555092032097475454967752699515363312040210695622598933787975405
+8668051227922162902176856358741680893763627061240389531754672702747011947735221029021238076999742096989024601711374129582948446
+1940517877834907351003862153234670764674347412348064152632718218140233582465116935278604919054339813155764852687263384383689198
+1258507121750424356317899666874328759136117897322624713333775442411946490404548479399911860814088039900005338783292400154353212
+3215026566497194921100428678498475477212368831513037002482731701747625115899231609161962690257412946823057745227816040916263135
+5553936624046126710513840693074241292678003250027162357678547764315313001417556750343221645935609713903330012474781806462752509
+0087160096352464233135718030584278086059148140723626725159134239250134423251753319043440628036779710209805517160099782393064078
+9318218498563579335348341700906218700126032521018782542069807548617891695409073329049001835630809969460708500370067751685336992
+4208076385552541906663566236770990347477457147392506695455104977958316161334777343709329582406111068678972797895379263213969728
+6469519015224118923867472889765223881558607274601638396572334489644055785283085612422941306760043896876352796674858662547224493
+7581545382840053688960159322695550231110088020621219817091426507061324686155465441741816208389678694769740607167732243171488972
+4513458865704194161496940570841680853750653077515467382681747134693802486964790650970100691348806372555667204130083389487834234
+8611747863343669889389552604708894518837779002018609033906535124466043777729170830388281007572831090596749539330676454829092268
+2614980773184238784409092097541705502166871511835967598046040179529035245968990886914099394023190993075959231506769917989928255
+5078404017663690714097396036195442424905417384596337491669874839339606038090162958546298191413554764614281624619030688715839038
+2641999347004416078674706237266340276545528202969242926658631976187485588763571283416465910176657402769591804490385811120607894
+1022069138109039758566977843736614783843237277066124548095396035264485535383579339344672494958836028783883577568562124831488748
+5036220302308126851203910148295691777409108647096999242270479109438402097077523126876642469999412297820631461204592271671208573
+3765990012871705693020962224239694872611037068970786438641717866334183625110030788667653078611800346467240202316395411589819234
+3782933301188992583378339987527190128332463154672014687853873904582770103495961273158433396887983077621367280840979561172209874
+3749199929332536186794255922364823419316096604597225233951718116228041916547239168206812159635533832324993459328359641335851160
+0949078067861678051433564861906686233060038981581529250289577929864989790385982845786299381823508035058298434160670694386088772
+8589603171909191258961043702444348933790044242468360895051180975009846570524502293795875915077460542906777905339916008769533025
+4696790001285278712597004232911565273828035212555295118585512821803987256554356248161862945364958160311031123882054615472804301
+2136763839544335242427199077661794515629181187002289822787279783807001282765862055208820154228904904403489678312786030757766407
+9614871264207972090235920749815254428999808582182551807788105640461738443833466880592889986393806973211194934814261892282034345
+1053682892737737957362804191027861071649489484546703968499730625323764928679998205513025454613668271807284174919717885935584552
+0107677739834015517323287238318659939175109001778305487593186279160892671682768468572465735391214037913879126299875773890935302
+1453192783717188719965961795655288342172822178539274975297334507529484119848624649135862288188339473719284880061285948938876451
+1104549929363155396273207050870222760506597442331198500643525825130190102095717730285667006432704158844993996831311067931052472
+0828794534801481162296313627002145147495573308897739685396596733882610495059540555269595443659894160127867987587635803471525887
+9824022973580621392509031573913634949593512565298787398230994893915219176490569710003371534856099636970419816555736516423169506
+9878869772576948330900142931880528301401489012367453237909670821957956278129934157555287021598067976133621454184066239649408611
+9449658706952732276667554753119961137301412966671524990966931464264571223338509226807775956572226631814170860570478467598493299
+6650524655470467246688640367290038855618731841663664529545949374735107916410687959478366394614227095766286594581538618985047713
+6086084723895749993359399578577946854255073324766404400181960974843071723540051597517023301307855898898894953430083847202358708
+4753978848939024247917094291054930385042551054372444060172056724142258138979831515270370976027807892767076899036493276499539268
+4888375835344223898032733332908158386194226863203069893727606532739301723911436149446573440019514355993413403576684311443713663
+8296174705195869577823179373277139184472357378750746123040139737885926265459733919518384739329034183096218738593256149149459218
+8744604285228489074099091055498838353604537087151030264581202847750393201247650508352763633370859358894270796201667489608183108
+4803757550419070833057341387873914307394706611793081307683075761521436160450412298883575182283341357874191269212976379223012176
+4435149804710266828206094765772134040146772381477199506975830561360349698395986931196641173574221626045221904844792851097031410
+0140901477445628979104022134212056527853288372076077175566962012356161842830489257088195443545165486451856025672191097292162212
+0064993358872969642733510540028442337052528489493327308542431944612538748472046808937048692371405185247438306806803215040744971
+5863180250517768423942955033295423284494978569038179153339219650484893674393537942959738721683811008504606623434622402463074587
+1057835094428515977317637880823368056821605598124838652727786262421298250352722448869673429472764531868054225289565474229567344
+3983238067434669068143443350182793359210352492378691479389127933138449974060689160199725860332928925347596191014918077016053014
+9909206404814481317875154662284644158413522012241871567063512207157398398808577747347614035401411443650498361772558269985219726
+7744531085141281581884696688318667987388073192993652661160923279555067568241657394706279105517300977887168465546838484164576246
+9611748410338839797298552575152326071882814435353560145135335186607329942289657269580962404267932188572721339477733166705898691
+7946378873728294158344802516673294879896454520313415594420541327407109273815189756012820920103635963852069701484919842956064247
+4874591841062298195410390631359369161750834793590724525846541010552709961171248502344146476896644307714211419632056930049968152
+0852013636597020207693222771451991722621240083418836922565030460173149090294177983564964216327697927947088353859239269055188074
+2400549504774664967997419613371907388057256285629514767888950107220270166626488534296499500671373046737811115964349503266901011
+7846949189277918675793279134349974486913260503583373441600579959916070999842932572749268240452265295033063113981992389359199980
+1807261813286492446582855762770791231541210822077548388510880369998042947014204967053843960432445968862263380028288322991265906
+2762645433260880544005259370505499891003063278739034550726117946384596067905756389481622864019774830490639904899687312014368603
+0877598939078117695418432932115534755404639291467885726434445252435059379183430846339103652602297046524638381772417363883263654
+8359730049870608112690328069372460928467332597727838745244400830648941526818883943362511766258737811338084111308530830389543560
+2410247474136168092178004494614768123474893065682802068994067272461583528237284734448787471492174143726629957921201303786784836
+3419244084207146670255645738668183101897287707313517219103923810981141387894446864639750358126083692639837682548305250192071549
+3436195357834369331471914469743643722462664355231433520254139779344070714371148189113613561574794491575113019678653016828154505
+4439128393642435861391888228862161582205771186938296499633571218847225435482241772976029740807151825694346388408247223423817081
+4171338859609192030035030504936231948955422469935021643277709598491047020926862755743386040228384976638566676326191183360208322
+3510862362886970176404175491659583359746924395962009940383204211293131363439339555697993521569537948812781342292800263161257581
+5726969821251892647951678196842942528264097032325730950425154233756415408461741348237674984518538018983212811201588754756679009
+4778823499024627173529601893322692810338013854983738107737211008580929848242105038076828712411467725165215358148210018424891037
+1496776225022474894349628318466731097093204838845621769757160832213029122420309244726997275518899114578190401052089674878889558
+2150627813505105989559012023523240177523105542484058646465606833626398767902073791909228024464129808047176621447241995834760361
+6052017973982660323612282677894938232580284277106494794233888932365369180563831962638387127741187828046331415436706723759407894
+5180894648613337149931873741726031450761346316713499884971063033267583243155357639761188673059015634957451632776491096066497095
+7359097724129074389636668836328680896804756391700054500433769926703593431467797993796585602417512809374217324038244052246360155
+0320127339112689809171849857331267778192107524355671645529083978652864384633410979534318842451250352236642968028403645196181521
+4118883887076525329129847815663385510560303081843081502700312066224535446821931779450723308317216723461024137619749777688133771
+6860925861993428345905718490095572908986315074234835981417267582301259888782018674341030424958141289788351602467046638469818924
+0143824935249223588362256342022083873670928848969341583470612068807101099916137780686058304339569283167254333748135808339800772
+9845042645815548051061661959342234028016893229602886364367950621055704775648720419681077874002883738984453187494339471937282961
+6185757617018491828131168967624272567910874050935111978401025105754755523134728391834040088198125315748002405260114662632225537
+0001356522238346600683651153474644012974963965580249070955634679932657691126596449770936543341015260416997826513343646145044283
+4828874167962259991499503673600129164632862005208870245173240873585329607224314026307889603968799682624300985376989091014318333
+4168596789573195113960639290119776051474016854378309232971533989042184885619296187870057410925857690307120789952188315701548184
+7815816015467871136014863206025674274535612873638378381437080759117487117954420502148760971346576864484963796596882357424854163
+7278776070084196458814159988413439534481041061939764299982929635630954177993909110795537307351830954498765311432170571984412940
+4866643127910829515007652463394937334032003939291631862785106424516937511685939908344347334073225050202328398177347110978277589
+8801678473026832588217149008639268101698714830248585119117348101801713106570301483277093069752495633755950440945309944552577536
+9617526174545226424763055218268088790352736241937230497521917254797890205799826169553805927031554132395993133419267021828416925
+0588595739388380595646159745519694245103070425108579498054959496392270944865180508024017295767451162258748775694293117545535076
+8702772928743292051022384687311462236447455075709507160040356608423402093661525464261088741775321017969842598962589897299430978
+6237136476697160214138655273076686746008630927947783830802379210660809805387482347921808311217785296709410669748246476297410657
+4956721962293257951828094615247811594706401567441027963919853253912294488061757086648296894406025064932611868738979275806148213
+9236140986639524620047147846000572917224921424609362686790157846221057427556655153843449488971368941339909014048314921826442675
+5366378038534835924469785482056822213525701444985254633404597205774596447015868437597513680309327466710395924280351223623339183
+9261759487436784234076954133371789265925256106206142125748755816777807349896143234487553341181444300315188799020606387261852065
+6449231339989879656134113568400091770993505914272783860814830316499113207580889761456971111735531955653301180535329421263128180
+9593132987957417462820592468596242875901632353771559986709766159903387546786798526051530972235857175987208754226458183961092508
+7166010270941368051527588903270384190676373547534758318035208065713808112773649467017099455130795910402044915843292687098488409
+1937469715418217414858420673158652244798733546985659728265347906685952080207655697652213278741491999837300249957163250199620558
+8228542398195856592161847035652366519403982135370687548941385579105164032051119406009514327346290711302155896619001736994882959
+3637688922930586118891425546901071630399830689323382607140358997300211646909715463890915726479319114588493474688432142961034974
+3846092487931514115420051603659542019430636869539365331821500084544038227936250365288930517356505814134292254191756084661422225
+7491630641568207270697424777290522332626816338241009039782131614678232351819731901409187134000842000166738975995925878926795417
+7070750968877352578247753117115107850387026880348329157736320326010941179590211312594408978595708610843851283204781916328035469
+9579425490712849875219973084577346692279033275981940434988363957383909743141776369454560267346747976256694629456374012164182136
+5715566001611830336152118124700907641876141203182109095013901373890817946278609009427237417191831719001170380251629245333691467
+3777911831700858846402803605902436628175309291503492499557547037759922326055839219601687167716391664999501580752878380637519910
+2345655297190543682328955031766959976133728834616422943753268441547260728586436316967787919247613972239277147037959837372479832
+1264917138428370036605146743753527478105136932962495735773676134552135849746496312485051160777893753074748519890909181403083444
+1019752269689676763134331558096188560591351764633604225395078892173960817806638672836991960044167937282088675278982806967963563
+1646009447412568269213391779579827953653829284427738902923460839464242874336523939561058096952551188341759036552715805796071087
+4514073980834947668053426086988984219335479873558292410478690803080693664498437799009591988658726439726875547569087833595254435
+9375888306479510358575648650751703046541164954438171217850843228076528589259852655316343249086105052230853543970799873699798265
+0497165101239642555970983822927664186264700494353584434852254137560612395432178721562325965038387864052788810184396252265391565
+9637587742861000445296706995627451301787108835157787393998256171661400401789319408568582769562951011299994449045177879050273430
+2769638085862574311449284998834663396793439445498698446119611616703979283028314824805123683773362437290195603306996434216889157
+9746240352274295235857973544138134283682808329702423798784675201114018293748073782256043515882634590777226313897991318556273667
+4701746730536780180098002090253702648694901490740529266632381315672027202981413355374788940709298520432491519903507229198264330
+8070148149525433117389602780506057744721609297582112109576333690538110175139908485162827329907610365996630627743121137187293998
+5104791573207818901442004558359267736381147580646586301522698902268860041597652832411905302035950359208853670857974818287006889
+8341316079342584982610662915730694074266548963632208359785240542883719157226848170269734749166834340935627403531307648991671361
+0980972555646214322144321439065894684434469993258702669138171566031352957356377641038155398195278908409758982420498643103410893
+4371601001168990355540734973104369357289155288304862691393888938344400557230712070949783924178880475136899894295722616103660902
+2650480054074532640486048424756932242389804525662345983096982594522899748828272298964877383316038674083325253436014966605240140
+3856519566975050055663208955514019483009113366052382153385562181732228724721105677879336134186949728875130780075511950816508916
+8078373724394599222427487550133729616625008462045077201670397039714132392823230257154531053190372696559721189464062559107218427
+5533555275076610788085420797340154399319379967237990930040901555785674670104205199936906742420190549652702261090687000720033243
+6220111323366364001766649253557628713894497231901067623752708357435827393686138195041002675760831950319558894058730884453262921
+2672277003207147557184524907281442713352109540367339513087567600977008089227949901291846746947778742548425956666175882640922513
+1341364992092721464190832131115386139839119999152547728030982443332120739263533376607896512917871745789498861904805336640005368
+7658494769549719799407250503812834345058648333149043237321838262779633765459673785919568562329102220327192186018538985265090758
+9891469225677893167626557199385256479464450147340948798817312917938176509424351376822942297600700655298360387396846679746727135
+5585419624514115780086956162546737430419445855772977848266264876064891998070796161296726855803937113862539594644902156882096859
+9369735292641205270247208512449851304357935258980017450069350537303506725253901558161348011161752800022469320895146408450548005
+0250792460158595347750598522833094847081172052676835161342784300572879217498951077354750791561533069799550859447965317570533329
+2215924262194811929293333565918894008757945953561673129802085846175034801490539407544733104736094736753035909391436637603434211
+3003828547025999647155773214469770001753156334255534694689533941988376812539304881256890976599139258146884644045613614613975749
+6800289970404751783592624836999186310592737935219914459902710041374388930994677919752362443845898391179354567028930335795630336
+8505759963363966237797610984127231223565214326257640335015223496586184791131912377414208061741646388077399037761412502229212389
+2367769534630970786705110465175915418118488516256049569042500049966228999665875815493320452276993289094558376973109778079159470
+6740493910513290939463082366133739451516673396242163998658427933891438988618879026121788841470475041492666218138874169322768351
+0357303411110414929271994301686020384849443986791255124503432672170825267728337655437754688169388290097504447359015466216468554
+8192240142847884347063706580178899765888936207019662263339819670804657575316021484690040614562949295841542317355852873318646994
+6622263158780477778507038872483270954479088649415292887077869603719840994025710565546888311161500807362774885446004022146890733
+5176307819234962298055575706826929453118700498832781969398229886642207165799263179818071674130902753482145042794765741675062383
+2751302275326116756435072977812989216925193208517438463427139377868288067976273977283764655073728859395428187073500573181560080
+1845833119022235738677681522695682631533441089840982284202257527507809093077654733824218731845673599302802574363126193666185391
+3166900131346963127277355530406427740614776135936937104096485949875917688047955787215898240293170537866227146364747857832752126
+4669645223062976703005533676266421855057200556768903274559944244985743499257659816488004923631139517399183550005987669212203452
+6297157628559223790562907965128004350109267209905657347407682698178194211365899319173140023292544735908289515011446104226422300
+8502054721545809152280155719799579471628904200160322267901551608506906168294064129630324866997658363940456422902104004108177137
+8611455694956943077268590839116881863962149614279260195002902444128093061737269752861412765172102748566330731758569318211290162
+2118077432186424807711637317365270035214176328074110410477259086405158562676552653953649314850972984909614735542131768665131395
+9130318975369645829745860603018652270421321400871933193989890358079853776989047665775272263249474986926107253991947206182591757
+4325629926598371530112760898633445089584186304063488458578614511450976053503391266403574144006236271752461276059535144816112805
+9310962691558816998084824217608875970240851404516558899699931821439837002656912679683111747809512293159335274051955163666587739
+3902386789985655245291475443305453851903636698632422663873769701394003436882941095444088054500028643416504275287739285414766428
+6731684059779922460344447840778233714899809573570342484286950672469381242333715669289828470432847009362616600780028432025743033
+2276600041430073716292091375271727222342465787797822281415644677410001912257463959430983836963509288786612692459635796134586826
+9782224784159961526251458006646854715817922665126779115397720973464372703397941849152840323345005890646175543131277561028472366
+6526167561528291467123805366888888939086346365110568387291388627679455761130295567840390067905361907699677554800553539940686367
+5318634933920742765367288875699774586510799452591417236786364826083325845867157040527831875773026806940962750032015566117391953
+7493598975572064199793468603272146721884132503560554819191261369489899329392181449153306365084506335645635211479940033483680033
+5666857577286998209607341637144223997808492861427974015972123407497307671199006287616123632355515817115708130939568369663610192
+1205647133800994070282776117664323692713443344045889466640364601504907846992739340462456897562574412472399343745023522153250853
+3330319212199788930516095800858918371890861157149091660451404495244272634139073531985568539542425087248882661841548689414190274
+9339962909966865014181214015249254327772461905399600921043142492498857240896128334661531817157722725029302364254696461600120855
+0275915123664954327692393323944686811113159039391999178218124646929218008261416648150717574114279175738099624550954907847794987
+7571438595941848638134927452374529897917662628583906227103605014116793319790628080501185855732090732338304609688113595225239617
+9130230309512350610529542991215174872450882806867068241227281773112095423160023040208987280292016395893990306260033588936149291
+3745658203217218584383948667226718968580182712181973947156555599253392240064780457939033740602796118129681262618905670233538489
+4412418271808065273371380680584774737632471892264742468899650839254371362867805781616736426407895133489629389395846145646724319
+8489210495984684333844268191310832723383161085211929007986759567690696951893569242504292424131665261321552489038411809330750578
+6574010925786704765333558400961864682658986685222505394734228960816617397028634600968531515638569668302469579752350128387282475
+7078834237219808682337835724461339925697109440081470255808977861161896407485691000442893960515108700590859410043250399284457162
+6826005017559754965121660973424054878627050600950197534543970583792709158920574211453104472613133226055927030752116724686804441
+3714997658728942284217722016417944347609973564690519305766123183125986230197933675112901682033357194516255841107152642532141304
+1057671755594723253182271537993425618933500230542903348744403011513962182314508888904498037845069539547674219152154472098348463
+4167698979868847784276420293320039606112408368549434641654634849595716003611837153708427260322734964264330233981684490094968636
+5842205187892994596332543353231430273153910962730263311288493948447613898642287416656513718409931065308355871917064045665758537
+9483067464396684153711784947324331651250593602460374159868530726671454450164268258494437853338327466263116015842104260460184775
+9918327983152500807062535153855232542858746567492036007943220587038833257219577445237712255513226337182088357385642452970244677
+7796979178949646284046620756567408638628381588842960380640158418933607236535455721736245193350129856456748190582611676103108397
+7474868470568488770868160856619425486013084529184753412392811134951027143914884376770407337322922148422893409126222728159404831
+4025970172900887552972543571216650363430374550536726543515591505239084581125341961497432836939375430662456975979411649814396281
+1376673671354389313333179969625064091561856231653660770117134131024861451548997992193443491241771601133879416546391689721119253
+7812382563778834433247309068407407067582779720037171842393136498269365501469642413788690972515921121053433102407538535462479581
+9706575053071949026852790205126415890557321745536935615519559505631029223517371185086529237733348358256190743027438758336144576
+9006414531022472111125196202814342278375571427110180645405421603811535358205031055882679708681076022342218218061708622772715466
+7014411937404524372862470846165036293398376604107823885481595132489354330681978934995519374885800444029796119672180751145597990
+2217635875626883098820646597303117864519547801664674186453314965253480085119898512655154794357106383983041271503641895125251110
+3512252235837181461231288315033867607629725036297297118913502488196313074376766607719647753171764776345290627421411392489636355
+9367329989873888631983207743830247822211335192876356701620415814984875713241717521999471919347104942898869901044085358319426464
+3886932632919049176756333953836633255259101098478704964812325499313834184343270599669768380535271527046781188364512125103089728
+9085400532850996923140563913725057699601728324308946983801623506065312434754540522710960789580013319731801582815683477412184104
+0482120489559053393661539069411739064074531226478250805786509477678364657275374151794004014104036094940006833641747026194721664
+6223030054108461763808112515000136243498515799834948548188322786124370768805042850586372228996897524679407164853720521651414447
+2045659821087414454414430804224189873085215197748925231475200893842348103097879724089151789730563882183249354356129862099874841
+1315828776287414001746118239879779806183081196189658013775774856212674965726153082362347461854112895332344854176341904165597409
+1213515137476784596057537684608135941219538557595828609988436459029859804112595309586038750020095414785054256852539919216535980
+4484140865975650257767631970278524142097436320367062170812973468859967284286099661751054315067110058820945519136720185944895374
+7742692644036659798892433853855040190699363942257261289132684570773772398269153067661790938476854192452194252168071064023197248
+0852041937859186893599452942342756186406516322350714595377388609314520833365297395472603829432190992959559426685189491282347057
+5433185143289951693194250541689460837628217616946850778491455755537650206858581434235195035172795441448516354831307931147174885
+0450942348007827481803050062279398301950579282155758680606572572109484512358059858330484516434220157350961537316843651345720503
+4380803663067690067136823238680695720389449212682650668097530448778728543739620300359368766106338322729357455486494754904098461
+3264642960305581246967575470210497486665490038206044077023048630121578302316138939937893860519106763145890200076403810118822241
+7107639168089983991587862527040150737165433796689810859573435301169366192576251898692883826389304101824844158348543802249127582
+0669598166832510431109943775944521732861864105283325341271770704933734103372804558821648326293865298432780241079718755089452707
+3568107971104085428061715527742724933050823192969880425640410593395489624255402189258495659521212800172822796344882503818407485
+4194972547530169348356862971069263077075953903800152306693089832494384056021498593498576727061441507427007792270872575143948044
+1172788991936383893646302947517752222941032857029795292428946787677455477081292410506859204482638074930525197495818984377516119
+8708727404823062734669585099177621030117278743659596151369099005394128728746425149879168020045121622056893025422397438542352826
+5536557575335193916360622332260209029723091397745281648820143235533928946294383911963312581783465260511469849131842805230470062
+9799128949323644060685917638538635211442541566486657515013727896653746677089071768007544683389875228688476415065723679786222857
+5615573863935839938823973115950563644124889855629743447770458847381603667537087961954383608440966294356327727154342428403717584
+6135719365304945156195903748702135001035781887797234160617684449358873860897697192990886253607384422197173334101390229305548708
+7355386834242660296627412137907269283682869702323709426719706244145140528071269497974044139621935732608883353990706800769609401
+4117824188478783409286690916041542923147052848706784080198351893505523979781915688089182588499549735693880215954821551279637108
+4670168752285459430877011145545186817108898834243886734027847064654587388165854257852169040893626949216503073312235415138548138
+8311486748387427946913806861679281620866414231742557923760474181682196182819449180979395793050862114181314437692082443568986323
+8048322367949325657177291617359572925594555792044926031542356556453504106573058251613848469630469333674263842694166478603019606
+2241419420107086119951172130953831261301246015464350985640311185360710868324911647982596380951605647282292847958812174415734380
+0207875370509633314857109554449234589264638078127939118196136645009058962335018366740029205503954796978369681506112588271652726
+5224125202089733016629542238144949897132285324338195131993745529968240465385054246763922445031407439625787648928055552616882109
+2793536617404132317781661381899391556171029177272445009604125493001682989300317084296686416290208482553512764370697922889547543
+8188433691033017668731418898412943576673580084814405684350547059200277266867531820522833168888834691511550304066275553413432816
+6069781060072723977215798057681530374205235352090719032425665651313169145801463663003622748057443073337332287692516062915866474
+0991144941963456299854456491439712458220412985735998277280486665724362417204461793739331274746630407706323572187551658131522029
+1128985384630705817449509424373236680198643102398192723995214101875334517122923435752591437827690137749416921444994412824571229
+0933149859869844034267514737213635247382994476023098139584524288805316943149032915781109345152673212416893459588048333327424649
+8431499800476711779747358632413776057189971388402676768615975922425552726845845057116844980552680355154340958763735731899549226
+8999746969039035522234132566990886859367771300359825363759150761208120895977530444860283076544729935781975800213516901282765869
+8578384564148446021966192696855640744733543364607326875346561423047230035981121889907856300901288650704791837601613641976512860
+4782737185453902550739147496508870329447551421595794641391271174654998339963075546317914475664543351090858707240517793471880344
+0532832780888888968522715514533732512924561999915854959906252640056974250958067417634581049729155174966017949852499049433553005
+1013570953208696598838952288133824762193269724513979589866416713036164401176767184475902330276700096926543877198993766233942302
+1558731482683686439823710758826362624215320659618968974586082717778992330445630506757688512508423035162517304559268454636939287
+0350643207571320038261933704850349754594287810435189119965241800581118358691680807766625340717143030794170306528880710869836401
+7542021244067320014248296046012617744009265286583021536650506535157160764351137973007620114482584140630719966828687210278471738
+3972594767241483050839240086921327315906881022442251582254034730627668558044239515436332898375100074941146541911588915186647677
+0697122022586499143860386882839929813751234590790881003673047769341255221587898768035294711863803910391010620206350075218304635
+0915512582808181894140392610882201933416172227163788895549745243551406730258634514282881847090763083210060265428731131498145196
+1501512625884967191270103224021116637844888067197984181082849059840793925774486252348044423174920237439188586936474269289045183
+9546757728181045784907692074408445085975750656689918729547020741600264958315888287557582915125013916814828453001978125724956413
+3762013269830490722798916645093224443451891592652341999436840113601558507630551284115296518475712532341410529593546552381421688
+0535075660768315265313017230395001783344059304089071262026544062275821507449160749765605530180854702975356649517426392492153632
+4462229922158652059017569592409947967925255644154395071833612619360534506981545280294824268624971434641426791536487863590137885
+4122860079882835156235088149203967906043976190683635109983922591971046404170885166646247578979128875141127938069850765269247014
+1129866849265718274907637855113066201183196338524085201233097892015346569822121339489136356302467977157281536251430774161642528
+4989929495806193845801738597980701228751796772240750395477795189154079611747433960930484756810247462060407330702869333431213592
+2584408285550889731205066850550890247663800179003073740079409662955268984464235081016863796902152306425169108972643255331837648
+1846495490902027499953838660575831876113795963871581292212984733841932116361051031722680807069640515568611052917719380714508500
+4730368154761060853591867016650935034777443474265562879400822197268954342492544791524055284219250660710445080227842874954141063
+2999165237216316240588784731941187402326266210523501276042349025855852110771327522344504598981978041650966736224822421754899433
+2237345937661408885897695793709671176319094949111986436639240560063478917538944076082940836147591761497957719533329126550091001
+7598999755791735199200904311392506066249434460145555306422386713523721542555336766166589674039359217816140532997872100172694264
+6085462229902194135463330821695657542854346332891821785703935541518889566865952336969577854576497261635473651422862788436766766
+9330926718781006335569837395334762725138935227106710853342363931868717426383038886351253414292607302835343171708502682390162568
+2759725885383603903963134803626246023341697535265756560586925977858745569648871684971845885034365173610581864076735566479105747
+1316975221277998480665738247654385735782940591833339656446094875845628844928541054371377477189441032462815404076598890156931227
+5084047857098057061549088214576495134500797236087647217879151791731034614882352668503598335757353547259171118367223224526235321
+0797097525215466425082977546510079918770199122108187284931098479825643355771575695825936128687263528517399780086601002282738464
+5882108977367740469432474363253310136350409797015594231680654761034810033039280285322415385168502267113255563957206593967018787
+3765499022319437900072126982943230712423709856742749800481145115762174065774560039072882469409389283337021169962653600686979665
+4601581997618072107980461792417647044978305789885381659804666757198975786036139854382381412304035407153678163339829269303413079
+4804720639771780250811522331538529037693400650190090078194406321327819886301852415216493527923345326577327202798642624789731981
+1262413264233591997549583133381940611046336903584987787247990058376502498817637376736904140547566821566316367905947287384644751
+5776817509537024183629053964111738625804577685331848301319393405578215972673272833105126341165662081776587402862223607527237841
+3028857137505052452119497280084550108942293030946862851209526606327291674235480503744471700882929025765105260116471991605614081
+9340100683840148792620022922546803909003134351687693370396127613819896251128556322124687119185535407506368947843781106277912265
+5837860085277971472343245356960717599185735265281223333386501908378356024658012834775741482445665420888316355875215276412206400
+1493889817668204302273257693995210600140074382228307911629842034054862116792315868260039297702147104111933826341459504324514560
+4753667010660505615221578575743422389046538837003732162433830910088895626144829160559920876420293005201234062697339903600869729
+6354021869352141987691776069755076073591529011311969753213483772524805097648788519425735403544963778868397356812064242294599252
+3007002284988957442402223796792807680185699679494949671140500739304141518373349678385232543712822588498429151363366914067465545
+8768505870421737992314357883218463757749966400771061631074878673057982116800200818694276568644501192730861238043718483873582182
+2517111306024948547742611078204983908881805478217286398022649611447119014425201196572509914583877236045184752832586045682283149
+1376425079937583047628837215348969478849396716756967260659465804416943561566523910593617918317955498182529845524570831173841723
+1739036166752846450279902298627287438597800774942709861167238037011909085160508767640035085875297386568223167138576660874567993
+2749444684052418908020211162253183694144723421354516311236418763218072849726536005435788876083510665834462678112083821685346156
+4979778261313034734593447279308534789267778320343662336147199781647935359075816167778411424508493052174895307203375091235720947
+7206632108909493796814807157234843620292819404196257674170712616419318834035027854762640349933755746419728237290445935893359476
+7972523340752476063451026561953128800722191374241698295085331249527419993680680244353440653002242129183827478637542127263140061
+6106361246560664390746249407209413785337414934577733325155578012914242942249188259728108681483189855141297703781608717770284437
+2459983080689617774602481236618573771655193699359105459132425259318658958293509205828433466503731104595644550263940782605577596
+7182234637562052669040625972588934688697821675314146092726738283785184154736418695256280074985786382718815935852352072100348316
+6798709996334119952629721938215622401513286500076236957073743607147857811179119661766817565585334251822559283874472847953361475
+8077368484549177973605286548826253514295310845993496549862916394171225254015547467894554807332772219846678815481086218479850253
+1557723569466563274008492657223419903746768944164337126986375831639044695750746490501676088871281694494821017358352031765251392
+3419994305802489285895038983304368890483549511884971605938842543322203428568381657097437964153561863023468226697072309642108698
+3155924019915150179568158859379848450337436841515789553391587979303261228659176045375192003213895824215877498665997186076059865
+2999137472267175701076913261675494050812219217526275916261893447733447516002165559492227300890776947227359067981526656072673696
+8601098495166116027734424221556221472614130194797807299983947972112789211510616421380969053402247170620773625487954585201101683
+3246912051329707460282887222043348831157339566467828142441386949856139091307353393247884498427787480035549002968948796358423112
+1150576199110861158548115562719716941558388002376600504843363323295796185489468606412792484061811432762347078760084900402466948
+4752997880608034066503743367113742314926769742881109939696550927489876774818149369014784149716022391683583701555271412269098049
+4122947315189371954201913791790379829165934721428116210038908501041491200253464990161405881080768468552171131345401309484164251
+2900730978305956981781132350165898118101889333020350831669690402919195278513062935410969054110767363793161548411520509850489790
+6317140142444713262780353377445709754525526526100220931420853524029521161445026020859823577131205174501439000115119816705181410
+4499991523210057790779337069784661258008182657881453125037535965670105347302421579889956188914279278573529309721593121892469205
+5508146256593369763940336135259800659809619929794178470062048041370071430831208645554427627646035391559292722312680898801625334
+1648967526716449029810215023304697906807519889979105852637730516484206305531886474058371893246706713362439898050285759339179316
+3759482577410685684593596493926547017312369150876917333521714609230709447558843397643743851645851153700140054595127571231949538
+3562024855350127743440468170916592187245116700044293261821848456699166330596624128415577062851344089770503995251522564366175797
+8477766635255068732724822778949890633417123111391309938080502220545229819981424955190249946666498348138015162432180329219887241
+8326147305998052694691664218432203744648063166741259109591553998325744681167769329433557902221338261010505326465825260282053606
+1089081066369978288230079958586716934294819087031912657105656191281125863299636207713663767265987214971817617524167760055475985
+5956659161052521449892118359418646820302358805073751690270525811449427458601574354728795417080178749838253936083489079736869589
+4756040554221482987126925729358987605986625930694194674956898248814661136244491613548633391179640626903451535330197156879634503
+5269657254348772763363513450959859105237330221730828709908803147787150002260299247932869706456162552333441429917744946610133738
+5165094570822740809419687589443353580562603424278039485215120717937567901150913213688361129548604982677760158365547321585786532
+5721986004191270987440236388972839714531938869537328769699467486823118683325371541953906389947764104960444262942308606574783420
+0825423274999976416479179163665065444342056794814403615470874263539258759123358841581177125724615901000777617590704389294753780
+6742419699812742131364238655136167729098672287631443854160975671169256136755724718145831652290376122821890697634805848496276496
+3900848450956356316829187800619138955746586281240305331127062820418337136267131988611645101253214320267600642044789378308027813
+7768142101816225544376840102775693516634889161775441232950103285109025549587962218777853283361116377890977393111956211092720773
+8166062372469258701826599477785259752674604446062893635372304334593302933414637458058589360745838888558751703330971096452276811
+2564850420537564339701047323195837094030546459418840734199428562634836997313660393990033302759129375346102025176996197579767609
+8872870135828449673289983810960029335233706075121561262257287764860415827304140209641297619500143080704997500176861691643727930
+3523914550868909381989245660265536145050317774721868915147125702074806836551953216452075481799528663908105214114354861340552001
+1593559589951778598427586959614078571783195940556392469576085221648989891950185568932203712798348499019366215767685195049047391
+3677450698912939130282894253043150590674429032380702463421683822229640128060377145549638924052619130706857319423374607432012118
+3201722283329551818782298921051193764095244804825793425784091160773607662095205922340014721050275267634431286245410339294369403
+2407761928636596422414810603411396624762992445889584536298033386878386163466235099237586521069756385945437909851885956052776101
+4551892967264629771755662186507262378960508623998075765778878560332855343021946501189553259398537769291592769103084773248272732
+9106997275950792264693136508466046590049216555344492329753333502148103978681698340982507624277442543719542272924397318970160593
+5003643337652703728951291818235842005801228735393820041591928726474748137284662169580644065969190131576241311478203049648965040
+8986752392715741495979561841249049222033021019539768600866686767034142327899022898431650915325022449300084738502689817549514938
+9360763437700859982761849014720209991738148978736994931574590369983794309597034958260372656270656787930070334337332515206838552
+4451175037964641122624713478708404279076794770827862704532161639277525181767823672699083856308324336587319988741595847500500923
+3042463864865181170367979354550819973787820266099597727415684485159423697903917044701020373206808416942704276522208882269559354
+3048080200899219985092787175219925954199186801590258882778436766885446862979938621696230463254471930200991285622531815432909506
+4494465194385245878424876179842789271630946260267264275467756829223006003558035998437034034758226419782837401641627699056717218
+4254906820448949384513753027180628971432660348348526219339979967375196656324459448972917993637121707012531419527163028051764969
+5795056709264059459045347065077313003930925374715251843125468051992798115117609874425243624614071216341941951333443769594712905
+9786422961702175763231201440570153261798473160575498751716552119467779736203318520988291431980397558340560735449110931384906041
+4425505790631864513694023511858116075339628625002969403915799344384754821079679161200533710912237340094421570796695940926114650
+7558163384552078162151051048460153091046870543482529259775071328325205703384361917997334121827387863984861026567298429845774499
+7024151222382954834390823993921385978213128615164507102313528814208567079688499912070171914927156859122712993045849060653099070
+9429307166946990362134229731057708239430020956417601592711428461279614801214510176796114831132813782448589275144006367262952407
+6718941975166588281116323921210724119843734085559061091993083658912394337924185488399990441930203011310984521684045028699686488
+1289068200800732284238439423123562064066343303384293220311845805205731603115472146721163687728630207002750751276592100892794448
+5346713601139175262412572458619231213504622828349869740030359059521925593845499598173510818770588358689016443776827808183107359
+0509643523301353915236067697449265692352443278187907371809463832094767055096167823904552345535023947977150405485951950799761287
+0296312146861071422545805752124301678869184550494728174693762162879350214577985621448093757895707899661121270041521839117379026
+8409726864010205799722565483699810469720898682668219634727965108320651761711145638969114309423068089263623838477654883333920986
+0701982653061769206880551891091640218809670563459796391962611157072335109465122237619770084725609181414534082646884976727487576
+3526106930335563839568672131933814040405238902124634964052890265269753914225841472646860370300002991439661062411618062909298184
+5489284594499017553239845981638823575689673477128445661568350850251951827238826810782941625211567718831490113495662231409070347
+0761858518186015339779421490664354210470217380607247145985104277374945800693689645130689632481933731656998223732805590077884069
+9539065740290512427091282228814664586680546652097563995149483899551962642839270109575078586841792310434801955703204357001468021
+8203312934682104375075307914019684558657139598128081066927393125488596174624606696359883862043330061635166484866461998328167370
+0125977272761404461319903866680344397363067561278546743044165247263103505646656505183679223334371532724158953424891372755170794
+6917119468055808943262561786048361427010843965462318965409483983665658166958859076133376429071237660115286920877219457193653148
+2210582961962854397595552344204221218872408837841098089244290975638461916790216426889841183579823514753626176299268639366257142
+6938938279494808076759108059141376006848614180404742864748925105751439953802762622388768762467629341123548099684486115445621424
+8751508911757378238494838354486964489105407120238937324611137021997266296685725619021335556120419627792798600024754767811910130
+8942964732151281745754352094851080075271176779020939272053185795856508342400932987956154784656391491859464794187568016580758549
+7093803490558017110343856896961686184727738060163871518042243290379067462803909424058805017311424240997471204900355661374314140
+1566736119124005628798032033275204642554171747963659618881718232992872787295516246973812659316873285663747257448232242034285446
+6562507237663679024109994426672469847713139656813945226527911495634070212834050520202668179078431355382392103665110926728808163
+7163337093376914471075674332970801236470473885515009415164064219689152465011362048740380213961234696943727976782304542628115287
+3743855222420028553131853842508021542825305338712873483864679766747424043976484573734764155416545908654414383080932700776375519
+7834242892295013548785979422302177591758705851513681511359120504187140172485698646885346881713211672798953029529425679446990175
+4633893183134377338289855331963450809211760110920084232081216223646405738494934518180959043407239414117561447413964700328518217
+5433662660787097930154056128793373805525457327147412372094936236754711564146018693671222546348461125048100620268398154557791577
+5116486674264823893675387799935762509658389400995246436075653037631158518006706329179420693907432583221559739906432889568752110
+1646689708083793966601961846963380825939768409816872372745312253381435289673316700861369097472435861788080748455563750632269991
+2394913678196583770021969391869849166343366172108313828891776494450171319520427070741615104344197304147604907461161478146821535
+6970220265997137270733854244424832298730380713169130932100655564124041223879414671509531965328454187192449944156019761861229509
+9043786409994994408835814038392730289274231805044666470305971162880140578631950679277309655392115372566040718447348800220519568
+0260472202194716089247619131312603168906540268723365507831041804698080034582459501938467511494620080710391206340388730610940838
+7326118518322238969330571001468796819573761190336351214992854388628577544497438052708919701742914513344327189122670316147267946
+6390506784888882547755768957113718192319906860888999507544967824165514074944084153555022322181782516106164395236293833936377054
+5714641021392941796626276072711028884736425391454865594302431453743809683815572479844749782164523410744380979378894640742103628
+6367297859579910614284261237130263461592389581599593438725404642412171244089574507753692124870352648825973497683300706972608091
+6528879643690843406788232137812536357500339309765626622435903074816275044864634059559694905228929605192781404349845940406623980
+6885914653705063359510874305420852766939519431522048421204491529430787666838710231728773489324489696476746687650429532899868255
+4233440617969212981294448839630057962261459110072028596849512767604956758310477460111261843845740348872559542671712436710774055
+1508618282454022497140169566835479909506224026572100667557407598641042136865104440157420255694196211078208396396117860451776365
+1507239834904105526832362883413042406464314583874137343256081467177503191240584039921334732134114272817444512404536172921303844
+1462051089737008115697275867129401567569051007638125298802754342170903145796642346081652330045536281219892265708368809837219879
+0453685864744973901237027525243434738854537803039815016737120599127474654581496567442710142699846446910049480896669404203340348
+9346689990227089014642019407223078337725269644715473933462904642091284492249290308972584444368741981346317066840314608857364424
+3692842182371137943388889815198380579665396475153546930512504814795832691928659417816231253704717088404598973194431677726441667
+2526815319204901006066476270701860537782781626529137506566276977867530476935375522834441559090476111355166836264357254224488482
+7009126058180938597916312502300245038383750490075362057823728327394777642420436778059817272275806207554818391187127829756177915
+5110816584935888048243109800031765306763187568267294316288420157299418121619714954580527036028226556975389796598626288986624596
+4019814997533165299992337612192568036796309043358811887855691200355299547444919142751489527995336846485123932685995757878474429
+6005599839728025790953582536623365308961400544193243119538823245141014368431208016452105852057876883877763572171550179791872562
+2500356597670124887859667877622171934055903916486360738831160634956448169247221568037938498171280531058898708454833291828495747
+3109569215216409575065435532987897643346725582420896049058159554867798859087403090846590114662541568279219050551516019161353868
+6185483127396494726368946515385004646852626975268477683334752638226219119476553266373574505398051454753329418244962919295715945
+5344724458607009080560091971792387153222793929070066348570583467465266923727598378490443838259560132593811322661974372369019403
+8458407692595863178782843772482279508788218196221474525584418608306184633515880367399229446502766746947115360332883675953446527
+3121980707768424272697486172479450164639268792099956499632892432254994295106673987928794494946432347077043928557939886000171261
+0577050269924549664323393933836052936324274196559262739026908246179444460993650264121746529145829029909925451248158087279201429
+1182711132849414035693613289891027291528838438771406387710865605582990490514444755922132927296236610194750925496351082081251878
+2109102647103389955876851996958955042517697886815050668367645651505615553003883543425993431580868653965842109551601532047774323
+0249085151080461985544466651926919056622702235431604488689367549402288274733008707563604434799848038664792491456040962095929365
+7278999875589390549123015596410656975040860435505974009899756364318118677742869501641184521884257988494124371969275324199080350
+2143525889485226056728303512644071737922673006177865168448238248795782597126416756968158704999395137061079007456174899879867776
+5408947704672811574519430929617541968994408425732774912564950806181733784295540418756875998713610000715279835936333399272549796
+0046618750251923685648324487668060245166359869535034556031423916249395766390348943983259976779662337330101459084587467420377611
+6066406518226332392745642377882173038406100184159399300600456331777383902825125059202230966872433187523955621780460854740743440
+8412271363530715396852912523334867927661153444730211881314493834485030033457029175684264387115709617680689679312093978999879040
+9657869183165570826073481937962858496613310115706782423102371799566041214554100144472536538085009196821977429400245149738069576
+0816241320499554734167424446072196247447636657341202004109886635882777290094614656786148313850718338218604613751038747577375251
+9117319836426478794488912868694112364734778843674655117850629082666869083673489067903986091210347641126774671760575626609401765
+1008118532396406153376026525242599592034858556342525818569312902010080131834952260460690347206525525021427489641699256115948329
+9403478796471636735520877378951136546880804020374976748551718084257630575582778549740221982719791953968237118454633169542490322
+1286802823239946142833722240859834876694232965252258418975725767245437772637447581851118844815831626565504328510567619469003430
+8292609187732000353612944093829468343729520826414837631688769850723905562968822078612443055462285102551209743540366646373935564
+6195307285792520347832027057354006551256656817339152300843201008404344101735346974655890347210090580920518304844457209111402489
+6224596631460367862650134161563558944936031773882670339156933695467888462978309028912902276648283451994600576418116774756356786
+5472438323418087607827579818345851863545677098783823512135936630219825008658803838212318120192887213931109375285743757983871070
+3462295993623789324823077363153428519235539388072977171154971504655245868325675529422838022778549930317329461099449011610221962
+5200838592621585186795894021330350557903923860725207306860907835414568816984390887997385942459848064357524983387010427408109850
+3373256185275744974070989354450321389766066372305525693275351316959271980719451196548752519719437550201627682282540860722912254
+5801613469773755028551251430496692677302091408721986707132740326731209806971448849117149983546378567141073671063743582525928527
+3697803453226110613863663691507092125649804560354539788548901908917360870034087584677937779281144785927759366742473292064354073
+9963717672138768910209602639579145502161357030053667109664830302862052329208650435316813897369377235565986275115675225384254363
+6761344873607397157287860030945733938977023836366529156220217899463330627464716487783276767734588772780285540219618726811099276
+2472361254288850026102274317845905290678407546967989656293686796378605109224367092391377532276351514638630925654015471910946545
+6893284960359512924679289275759756168128756913637757439682764283483027618435659261867805209746618113123871290501000298928987223
+4604230631532001258913408929361874112508575772563457725381109205712576762498230243782724863115387239822706836827854691589225919
+6353180226120522335706585585655463329450214403091956830465201717296254555917557791034667593584676865134148740185250129625269812
+7681527901091326113048786722462348325784769942754780702258059604458735745233803955056030921585788629283445553041509260093245352
+7309220586489676352977698261496440058970947266199089765873965038198042811288461602506269407874212537834374031596895817266480252
+5671380781713371554805278200673327258182545730441250958579106569242653773093761570049297046722445961242199585137608405012572007
+7828486850550976212754252064205756489990487555478160661135559387233240543781534504267534308047400112433806739577979094229507603
+1735652617764383585639984486995149658650155492118012228612717608699086389981358293860866276067465797190676060353147557719908880
+5809608466540093565672420660893504333126497209645992122475383330847359820073574627113129012380682929130905963299348891171922548
+5002869804918377770158242860178234038771989441187910348213084777623351555039769099812484337067510542127104020429900993982081671
+7709207109088318832932845793851072838104821066587277352066221192004565750065851231562111055731251503571280787745188052871173891
+1300675988020851714469995143129598445432183378365444739669948446307812357058373524561004834384315759687175675721550162755500065
+2986343436898030807360652672895860427883496016032784149587776588259863806298337541233639409877580883769111783951961729854269967
+1601823981755766290542611869833989750039385604668769648848238807861573337182702195579127745245081404264493592362053024115769418
+4107102716492675980158632893016973041072334043127798725365792088221597132425309628489541173280546793641323966773146909247868755
+3819683658930608253697914654878640066261793324512623727802178114862630064529284630973855427311675132424529284212748792990550668
+0736093271588205855246000014782826243591602482151161574269309829561758900770381929089531747951679154943426373942743857678907201
+2579391599623221851200754933465381040789651168701188912204464482208095449667962715138795642341183881460864419304811104815352329
+7570162647614550188694961496075537449438462429576197619766568228578156257291119319362788331980002153009584790725962518357588642
+2867301400919047583578998934993306274019943104502333712247027666654628326692485228040996686989047207277332133939435024962426111
+2800118335388070264161106773949228910777957160444174345990380796529948251126974186339060998840435346432168006747571320370538154
+4476893884627071583698402476874552862205711529686822374264860104226019597554331616506435529408791452032863624032022777509172662
+2387360521387922188586138212711962601419570169405135474539424296757638201501368935895796012267512214174579198583111876438042196
+3207944223864976640314026742675529342045001292563111065130367748865114709153385711357232421423093197866403543774881366812947410
+3024015733350974607130082705448223007580421749047845265584744661269361681112069541859763264352543531462633691003101294808859592
+1169692162436061367720119759930066692678060291627161481443668541634202666603165593913992477700731194838349007676531720171279849
+2751165267818731079924541076614810221037738242037928099580658966017244137214097278777683446450716576425458106456674343770827281
+0396856995901845858069688500739423611458585131275613789773338642449531843526049135797567793850609374983112677866381777610197584
+1531087534395262206112602286543697479767208631357778942636385138053327121554947922895001619615466561594121066079313165604153569
+2093692637556395792176696765614996657813671032355821221008345920651772816571893227375691474134293122057079026746734194976675858
+6656377492316720744820927448196522955924434793647944766092359157144753759050894426200065451501628415477521405487862719508590906
+8342026934212011048128231645702815266555959471653323962526192450377377432253217447538860983839942343996469379287531744331673799
+6119650763732836889688973448048471041648065382987440098529987344461076331072134069257926150018448979279801859696456939951283072
+3364756734455969829310248048507921203362218977909063710162344883654504743601191459570909322659994691353369156210663856657262211
+1878353636597017372001364702577584897453891661198546393569651046602221858825228640216854117340540870937305588763063713204215566
+7246416818039080901692045886943289879346943533530756863194707455582283075691686089441132581902594229725501704594144338085541945
+8508829844172609725721048474190455937918008659794137613216237230265268215971845365542440688734702896182248548131537748110574617
+9749837159931616345230389269791318525672049015765330922830030005687071010042562156668767526231766645728311230400611546831340883
+1042438692813477410787838927504883371438184111986343392632454033632895691282059130126453347410816312739668264804223203706756562
+6361009275683200524885847104957823290376975509915625274519396770442677593644815139040216252662268629183385844801360269251220612
+2229763646114181877287927118379174699532585850694835097303121614336315830870465640665166803477820913104310061050902102789844598
+0133060603914382154852269620976632642294770629603193082836985616373167078617561223317446714275063351779922957184196466970884767
+5219496051735919324804049698971068904312201333312370591154056704186542719979874616042547422134608890139798422893654424476506469
+5309445174646633737921041425428020908437429638540244462052129439971214228921839562115695079069371301404828066341916732725724068
+1929599109824380789046935363381838679112048207357698712063450869013602851026654755608800829647182811384855047709407638244169874
+8711156655539521674331213489806723157012020673218852893220562275184063123762927470825532953422135931696172529627131694897868313
+9146092529763359061139625016856546857269473202244951373230403084240273596615596144680054956193346943461881907308435567570589732
+4427806006379233157431109769793014446131865605460452718401487086503103098553754737499082181376863362004474070049162679495304786
+9908319411586467759323529251895892937674894302534759585448543523471481019079407250526711177578259561097423457479183321229451626
+1131371780154610377491766557592293428206914537775417828678921143427727968850975607814254333398412178045797967112746828184963972
+7463947060005178881443883529993444944563705484864960478232839522887114302507061077267547873033859704180182478601068253214443547
+6363654733262110562720880713693267188885990129857236073837004378034866347649760844198517835526780984480422568814264124396245788
+7422184144089713717140409869475766686474514248637954570906655127051840364408955207306296810118720773449322716315645914875117890
+0847277505961582786741295462154437342373825998662718119420520873688904858163025326891259732777158377960920534957757187301680750
+7127332835591365255818677928303920688285753363566564622227243735455708574607542891965353908456436608550001451776173990862992161
+3829054399301597187964270168808949938169540225900414534726047012413120885338161369990845308813286961059592718025627205221770817
+8092148297686870086401035932812080011392424084497972356658952923082172309746025699168011915919281009722984056602687718337362402
+3027398748877048907651150695381083835937725004446873842854430149618594741819924214123640276762016797602129360641044263480412772
+3710143070992584709931252199044234825397803955966283897640299886246679348943101389030142066287790993761176511866201467864299707
+8525777612726675246376342834401281272453399310074719106459898269090225065025922311415205451670630902470074176854745326883762644
+8262544278833799829033118364917993352082125138925496717970983928091600634758984244372250880458595883955890831596406628913521186
+6897853799297275638235876552327431216883341950745982036695977282177864189708565950522537254131161076036929940837531981536512451
+3213748658129585636531039879081929302798794268346651462737129452506002968774313717689240477017446831448952135158407313634350442
+2055874845167569647361541785365745319937172123917988776868257061731415878495755011208403654576322652419771761741735204486134128
+1873586980474608471307789365974467503495691071252149719435658541818854563735190343177059527503193288117651496365565656653307241
+4168177432498780914163093904219938645313613562804544457122557236850377399062589146156364240794704626265205228184552480787389528
+6002548119488363978641919486071068284491204688921592270835983882131004647117906646204653024128798598225163921424999116659512574
+2157407327085931030684434640191280950835140906873052295703366686157391470840100604628128222870118102675339834080247719766902753
+9516075696286688385617312294770633537786940805769023218236327039881513937432194699645278901401806327344576080861704678059497048
+6871189362548323056223946109945917378776965980493422695153032621053464957232674797346887230723234348508681395275248458966927875
+9336780663866116286377027773514857490216582712388958421219481975628619943979311778012113187699153459212550397452631591800634557
+1884225357321516913996913776484184458840279457439252830670922733976854064570789902403772321837879511792814698370553104269506613
+4608342183802630938543364752477985342180204673563980704638103829760160093636516325877632052705116775395863314477370432360214625
+3293602222611238360052445923968119215574068058661794694301159396049393023879006675439325347420522015724464971518661959121953285
+8043528468318108109054413534510021714964009352370382732039845180887830146914560592175998791412497342760924247174793888155615218
+9953136600515251517270114445026178472065320103271749951560132315486968402879259134348096557033081980214662985678737805295776016
+2082425869735558279582276249486763021868424618618158613101945224876744522204200404218768513612549469324132911065247448884834161
+2715300790048270780472694746992029478410340286154036701148546125752257415749783382221561686531788228065371707859970836437758369
+6586934570724918966767618089617174929582836792685611937969070528242452974277966964414407164887044841543253218406757856518905749
+6701113102105341541135759678684819193668388121785636742894877294681466156143067331027856246686661690573758062813040020779144644
+8573371736029851148801112116958518768083768805313811181481300256743484459392633904102235738743377368774016975057841718194084994
+0319902874585606893329741100525933056084182554392753427931707044407179198386674603799910970919558297811591565044725137884178871
+3211448717893811033719443147078575334620516368575812396883003880411447512133976398395409888756416803178312866623025053382610669
+4561353382089346913344316837392847914820218419836561651969690056195804908190155708078402986544580149409461279682788447362287221
+6541324108089851136771616890125941444979071358059045831564141967544312392874032082755961068514362364886944531733042486972382351
+1947537457345366294923388536623305727166280503481566200274732091551547741549840732121496504900782994752246247415294786133670139
+2790662270964346469038082957923935596601670431239525874522807293008957620170868585946546458722568195100218646703049798761457890
+7207291855021167963306163201383620528292099344156171536132565162121580753163039591601562538194503052311054883261440201088776719
+7081508994123346370534091387062163390235318525916429277771533969354167555829004274478142845946719915110847480617275074050516329
+3008933084371763781228021375479207498806120584984898188493731541257384657224732160257247009445015469067201744844463068899016846
+3400853085115213814503196501389761175483359326430453738990669485692964833263969136641748087708764716019323095274097377414065683
+3262060508094820191682139681063256834961825192399541866597766579614721818676700322392895466758698832928065782064894903472978312
+9760920512587884215163543988536526156574865982745337953096380337326849623081010538502752692990846114093305595114511445577198415
+4534258782640418619628264506406504403447005968106774436451122846867047076694261073542029684272737494317052196031968617018760037
+0005723042928179923030772189645554654702738582913437716383318676665447081003973531059059732707456286646505439805283337167567513
+6867755898727425848664558154624878031288945357600827739272457697556698844756274091214882872082839937589030308224565293706216309
+3727537228724168866963116807318580861851195574160478712150379828696545006021644250770529425526279645439265900826286791538135930
+3153997389799559939607422587882124977791743840140703583207584629133167628782910497529520542920062933572958127405711490497737856
+9067474435390875739488758031979945416769209293461704806750415570467527973320692921500611307072408238071671039355350126215323195
+3397087786775809367683818985726713074834263187298828458889483102002512283284602983872325517586754239568315454503146853407356331
+1156217453455804570907455838506537271360924924818686966590633031323668379608702859282734283827376245634390166587981939981633250
+3412106433453184147582934702569648764561354607002098617356742259624760387826342970038831595863063739528564750876654025034114351
+9541719290749487737141992118412804491779799111981476193385533300689670528815189491502637221085072487226634588032661043056759668
+2892064967147629869694614423619676513067951679311770744515022309616589783655846699918308471661872732172650395986258940991120106
+5144184865919978928920815222171229181997238748998964019938552954342118630154574987629428918689878418879411760377091395290416344
+6885105521575830610256425097707534533542028808834255387318107287078639558846084308180272966744285679093270081574095013341117481
+0825712842225983699546990461215024477130525988490880256409773994103713908818390693122587907689102651005737105310805023272218302
+5661584786775396459681434880691492087318430940497979741425101788956553140338175653002561188152737818909816437963790481976018401
+2333796064755969606150287094100220527676969430567702969130345130599373183629780646448254004373148786027781444947828389799036231
+2370159800594514645060430450080996614777495906387714719376787944968432214762676658329959973122495250133837956302119421564977403
+8812738504000258149359611948440268119800977088619535948947126735318099451090706379617772423943777604512120621890539370786597632
+1363253012488373680482054568974446439190725621429231276569324135313694462859720454323916583978487818838914751980359776090418942
+5309412448985837938866251311974802939648013868273488976753659392241870912692861488024484868367836148433592247524575436350374927
+9969514974899115014452925807661936280550953879875740514792224284344537632692977097082883985126798768022555743127429841568583436
+9127480468310694537875735497900079126170848463529624094796935948030072227221587835070990509651876620138981087391650544865276910
+0663274772751898865701481848764433338510687274568588217413099134231887382122648096865873338497066278774094796953376828006000126
+2223991886894820013487780739895880221686260123953688255289857284508367990146047269272253817887508457566736245360372546074724620
+9022913659536358863270572069247332195356175380482645548420742634480093147625717187780842180713151897503373416116801897541549813
+0040126272697263557284035143648280938089213881029883862911870694532327995219687847437429389232425351493591671711796587562791256
+4017430425461987380494086228031466897556783584467938250558585791601061306591861372175583299944343371927286490389555179774602318
+7872955211264709896492762009841470583148357109101357998512705454425930076065324016499469004837167664624659717653859578461687235
+9667310959423600740682018043806968632350609113790915003388710593533872466670325086871976600837835610439552558719613595783702236
+5280944927395295859052540423240381366808883628148042644568662154130067762884915257137995873057791352572012021048384019627522811
+6995106927652578556591681036413486142384921333996800868230237202393167717311762878194321699747706337864446498735182883503516810
+4894127087101054059360113153040095596503789486674685811347198640008673703554343464924312512011781208631600506972544379180978661
+3653914862578195810106428140030210938175294156340298752901536901851573154592330206774109827394766622168822827213223926407598523
+1752287994131637967328932739154812431240663561508299992489581255396838237199970478414918524473397520840434054432691053868383392
+4475254299662836002489198880413157763837585826054191105485073144949660180125415108179810953128183235091235263489809711965370068
+5618413924400018858280428271296438533254641173714166471746748160577329614446433367969692047250196643164558060988866789634419083
+1976673569829377798715474066924169354140929130742194843186922903877261219583485904128878654906618865153383966440192899927641018
+8533161119710252096705226091491715680664590252842043928311396400578644885931777054299394359376613317844464091496561469756448904
+8685184190096699452877940339075889148354699442923532123110999704074604303853725375307368452619373244845552599196580274471194639
+9829578543429362536437207266353476212156141077734490396691958840205815483098775874456262295189398128556239354143693110486242701
+9970409655619169147931181826146996933740442172396548865369872311637351974239103479278809874040155159335694067867509786798916993
+8934739229131395268686186934227620999682967502345755750450754377980375485746895673108969778424574385778481433357869228670933712
+6403853140387575318798294898252560753364466868740386419346298915926350400035543680556378607221479519818692502368546406996064171
+1053081251212324305626596587814428006013451031378599825941680949090154726066128761151070261252589982556578267160212779194125716
+2889755089191961889036525987804900491217472837363091046321293846058934856253393138783914577483067599584740608242898988136077107
+3871240659195668412257855781781704566864660291767024614816347476774763467463583115867939922590382680508695307915014840948963808
+2822134512303137695995007841922537885648949227095598324952993245073100048846948118672641286579492473549786447729014913418849577
+7115799710686817026544023974604506965289044028358314166807497671714007777434113787389629694840769613243261303424414900494011898
+7392257640112536311638754807439431161718219269700164766558394503991923942217206220355994391249150834799995352874004008637120732
+1738169836253384974782709569139552429502554327170357536474522232448622509720551967534903770682965229229310748674655279819812001
+1013488426299593714852536878758330763717657950972685023529624029812092380027913386862035092137102088651474613519196497838916967
+2365712331332348797178741500614741133803176085015200716152828860157706088237891249512432828832383523202673780925247731837609823
+8343543339820274706718254393402391405027365642281414672601521735599554959777377014041823630157212633295524276413560148004499161
+6041268421639300061742794731401962219148955309257726102832738599350862047986714418077392903665425072627420761149419742624568473
+5903163798089327161860705456299199357142261228683379549747158444438483324626130181126533716219751215937033507622299908730009529
+0388816251038799487192843352437014500990877413652618253793690269472286848421450299377527429839922951807455986611893857644960410
+6747097789593097432933016398117542211434597285816625911203020562919342940284869769635598001370921459163969583961849156409633978
+6058253598655377264266980145151402530578841715801191174134703632064724433621375404185347776838645447066321662228541280092856110
+8706460045506764337863851824656889505997963004840404222919355019179623835893581428684583324979366713626899343900308968866457307
+7217115588869155277775561876870949020701337732105962145058144137569073157203270186719489063643062743100706189008644101702506879
+2134117466607949382162669449831544904500037626615605917490932121868589822502449721652777432598078974018800021624932345792700743
+8772537472143251033025302537735317107162425743475413816038506301465925279856675607449722802889718409431120703912286958510209941
+4868004080038983558128526716248086993854257004538122139718459319434617070817759239833696965506062568522567601751636677225399970
+5772707421791629107161650375371738241195109244751411366251362152446624847548801413381446956815082676765934768156267696685640257
+3337783332137332131442737895629161974159375156476294489620941247396447219121871778030180022268049183913926389862808328015747496
+2718665162373177306261228085712460052227574664675638031209424855973371465310593845908878207798419801473033533102851536608498988
+8594650062259102571664509669089099570629940328720500583665382040942904077679708565306833479512196713193874213822763114277561821
+7763922398020531727099680865423760176807414153322182938644853758445162559723450312367220101572741122819976006288279862925391533
+0609418074163954317311535425632639460543917210847556877142776065667429208580080239400632276304974925905306867007809952150307911
+6324798067968629831501975773028726696101515750158909358262168518496428350181893495977033603403728917956907772455104980623840611
+3585603421384321409739580272281986370246357840985885096013164036482124665391931947880815558360671475167152552411643258730493458
+6674212278514790724079384829207583320586965949581600859999150201711417012504831581096750857003895316139028753798041233239967350
+0724838602272073110730847467620546382405164306488489590470927625949743749910925230346070277479842393578994351426637786933239473
+9758486324598916254826474547605389356962763994905059896268073096288839687527478615702716618454224618511400537520151578922366430
+0912492025822760544865884599694514920137845684369437041888556762598262707248611887100015044910247510922363893211117566916277207
+4970896832680655065722060515676245073680441413700428191825160119923053062012241474629435368642857468208602093702394160800952368
+0401643954061460061469538963715677841733067884978557675498904356226239814257513498478706711931106662782912959490144875688684392
+6427801429230014330280067244320390813250002494116054667882575684276220510978170909405937360209445943389405620264406898441269151
+4513961131947927648793953864754056606418638015682203461287515973198501950396575668694970608763112445843545620657603445132209084
+5756001157040952762796856519600056686459818285012859365932754153307811718432937457957972840218047257233193928872388202493970468
+5745171294650962698731398420701143198082563097452816181021021324846599968746630383827244381072653879098831871344995918422668994
+3440697357810684087609635992103602934958412129332726402190737073092334237927797275626663021730679412659760103153021222137031354
+2561873488408007135940986273685629006346887762950502897998328704241551747655409051903344700915847431066705228403387636950645457
+6677547618819900422307650673816956131536670246263056210725538571359966918216630406962626983531012334568659195035619701341684239
+2420112802529724475156900639848021386946999992189525298915178531829794178899375316321752347503745229384277622075513609101448077
+0978966580118766906719339709431650123507257526495690738543102142511117335171869720713914484644191091368983835287599510980274549
+7253035688826486175835885694607345249760996565501754434755643707038772708239856393717371875268895624588946691881982666455004955
+1229157575767360965832607989363181678043448764770403987112238108580504462888836301106969202711436540526584606392030520555629817
+4303800215068042550679859587110369621335305905151798020996167677493237088394878180209234115765088470219122388293468346691575131
+7160108019683761926270404198160152789263213718306724711634865022789627807005870451606075994736870542860235641292939358601690892
+1281304446363067443221484815128597038007892955460785907630142069752866701460026126386319238710932447939095864553352289508365136
+0314065667002957866858488765937097697311458242916562733459459218151551894102884025238852720369894804551004088501646041028776937
+6071040163745909418176019453877965601147459065352750105116872007917183143758403418504559900007858465882670700927317278238845262
+2057864431401330101261675645065867887669270980722933655585800822914522258771084932227437807465603988558837727049424395413086192
+0838403065062402417019069366493917705353727605973078124319419683057212743574597310780151384502291168595626908520023754345467963
+5237595147390251950945857498093768496867490339391087595954081288707206848402637964670896124834883491892023218043300933428536303
+9038575918527245239784697127935511565993493329345587370301152888215360283868124687096008034911588337723498130857892917083893566
+4326309213195337889918560482484162052931169753291241688638438611871045719430309380350737659700684663483713556511824284273648934
+4109675537859830665204217999322330504340383531423575355281348688917399955785319877102842092110480808916641344634371327017518067
+5976571379562477291805315122658077767583602698526304594638663614898936945525476463455648126285604724437435096863798048639029149
+6805684460338235182637901097297785029718931952225347991353757161498388530429639352729227333463916470311358261242265252454882149
+3713554069757475756235174202220726685159145970448234073615786797869189321230621988473892723703610057245772568034893831333824268
+6384329807418457095553971699330059290079181553384702995369891469896964859336812164228972258241580918221240870171611342340166996
+4238496467737330476039022845048701321182330582443048269767680094107459509184801830653831569366411726902088279531793681281083241
+1389317145760821195180078109186551396173257466092123382087137757380977821227017398905747777928583603397479220222412134551964141
+4172433396133877482307354312025003410197620920424049031355359918529883398507939057731022302176139038905017200234464598134643926
+3776455852500808911518410528880591214453698534859661007977301367112639128608957724121376845610991533136565527742397972171004531
+2169236758277228509207094221732914621136016542832442557119974462763405873279434363734315812872035133971702886820591857401769365
+0469858184126033613406108887661308724723319896168974862654713098974773391394034562612379275030863451007736429954454094411166680
+6170337864185847270755623945219598905895923685556701346236877669819713556924060508835912462997027984549870490684576221788467996
+2684567926478205893568909529013411584469062508988939792621227026970772272619563307265559984083650571137624804538833124458965412
+1535835911469765914801129303385752847166878267150358870063623206823946840223186885612380869419340578863726545596738437580294661
+1159345796279619020659424502037780228138063084481952522217422192474814460650570150288813492963026126513178935693001157815213888
+4115255308469968312956667592729481570942886979872098274544235236610800153069537830562688683755471055934166523033112817689423559
+9188936491751459321231439471707842349428821745374698747871010980962280880750506886802895843191246598782044554283344177438872823
+8347722755763795357915434510354216096329858917788023158970394599943300789945002208151468416849121549451743359325575523192943247
+0386458822265636778073946364464754663546374429692132747455551460488109624863176490317455770854516391720009905789081791014745242
+5441057113825577288143510443291415701276478572336349873718556812697918623782132025707841689574266907977935843620901112527314879
+0138974051576176017602134330816942995720273624834286549509110307443436271222852721817459586302582019304440451903755250893098006
+8714580715983710618302573323538613568787984646210126690769977327196476888780472811559022322326994280966501214045283109750894159
+1238724204438864658817267118920298143255297575901621515081809762078906592560699017605054545611366055292052387838303773046414151
+2117880548683675747162798543936995265803158300313026522266732130084089973850929862579530307924250791678839458713648131052866542
+8688866589649054666206289287368847639201089110726068276561807440633436849032550737263946103998593920752309241137169715090564726
+7992366978913349109203408811669845313806318145335482602504586472079577960741456598112230859758567892658655917499886892820156294
+9269289344377943028314943737975747440225464454099585770665233191895455121597963497469457088101021828673050970000696324467074275
+2620213720505096912466481021388401048520027588680889621938076715558063059090115474427731634806419367474059903683493740456083416
+0419258099585668206386510983923399175364308512576355916179825772896253917529784626455469847416203745543857585138629447495124687
+4926957394763419387802807256844093371043881188012601196274750577103452141865582262123425456983325248975618318937642166941469448
+7745531482212763608085822252151342022701776876422939982991937310338710298056659311711100694774221511805463875602371671771107991
+7622297042918195524581284988624821755976081656742322232878212092814401063399047757727446586120047765852193643525978220488403806
+7694553355731009082341963145016321622315287166497298675517840848325124707270827181601834343475566034855078916693975601380159131
+5691081048224248376219969516692299552551684485812747394911625377626308622713328149116932634160209525550974738125918251287523859
+0467965216958213222976523551707473542482226303543330237484038813545187688169900375790194437313184877958505335015185533760569003
+9313388170020500404223350587859029392425277844920011385363704844190916888907282100497715918895587428711392085764058004531043856
+4805593106127448601646584342013400666164278454947086863410933724954207481882298946080783397578430480735942749099815836074939980
+5829488935963766897295398693976065473334615080031996490066697080972996155867227149556928263586779745098746381741955988476480256
+5145688238158921108920160861540066499070337742408273263858244236306539277333029376512623358171655471201632148566471544471879593
+9921214229435926996318797357630113668084683534980450540625624914828693276400997437801995497337699991160179152196384869788686202
+5452970283364847951628816855350106161884215992345914720345452469417460755112437907196741570679787585797744951997013243245883760
+5291067302501955637725509930308800308821879902449540996764882569862895237545484938003965194362900224359317192536398128214213941
+6161982577027434530385173942460521391267875161999821213546453369930955209737128453903802184733420666743600784696394324963677611
+7259796660195828763104609417030954701404550411856256961919298349416990278446333820166279192694569999689157318159650815071786127
+1409252775006780923895660512761218733793242701073753044161926851887250329246949307610371367921483913476091276544943910212219648
+2024883815854805620725646102396569531338296559295702755514936293184048845778213281077499032309766928238274933799920207837132838
+8210747670883127249029109720500900846638073842072735692712299242482036224417598293305373767651397688387681839834164347629159924
+6849912340362293051521285112884702937904971535989594393302698489020568178389718625627324020502329354706893589619173731210032692
+7043789553739208010357759707009160597258827438739048435319844873364203025319025627611147486361041079291073784131340379802864271
+5630517567000455573262321447961724157507366377593234074637396775521413915860857523966422306759381837353927621547514858375348648
+3907374620037626404876010563369584978900791842626728009855287567645993864184962785602670934980414501849977057712840353440946698
+4146385141059123870591051497280881668008298341992956096236493101498703482256305064373982480667690632647788868461225656591267014
+1968850563894509480587740368883124473858275653505054105229249423142559298770511499954927552803754424222038587228379761857441343
+3593066522032907759239532950409720855609763959255411331452747381650146615224156577229227092417969990679672022642682488460230666
+4777284684581020086703554379926122352924845140673649610422757744893763657846499512591483929572896919893136740342514388775709356
+3278001195584405224574340518455727489287475412287946187833805383833415237459010850315390550944653852931708140442412147400013062
+4193626826135963841422031213601650476649922753686929704940497664287967482680127644394472418039840709944058706759350270065888771
+0496707764123239353916969348556102234417341754509205481354601177831190831135133718891421262586922485229955848858284322651713550
+2364211115463126546765721277139380044647678205497997698025656179147544409871931320460204274120159204240964415234469912669043171
+8252385686403049790333736390573303996823129984313927885511658858105668489196273816414521496403236288238282761677474764476093781
+1249545053006377773498004690990118213356171931577992909398589918937522320753583797192061779831406344206481621920250152295078939
+3709843278222111715104072968292537550135689257500851260250849491755576197121702408117922267107801447424437466479647604658838505
+9854374828488017805142065771759506637983062326803172669751646781389776006196509659848336558123328010610366919010236885546271093
+4449279473317813512456203547757437510023295240020059908269371826627596476653671730054696042131496333128833416321765418914320719
+3406255777740484368806154865989716577772954696365667763046622581695081667791363935783289021366520297269972594689838903064379670
+3971992965532938884360604600128828768832371480402617473079458005449743185395881312301575878592825423836990732749119210579499565
+4964414428994770524920627355735483099389790803639808833122768311697123316450497548024460387672711368021069867385676748771138907
+7272947208705814863061836555172890754692453812368615959884812383294177521377885043762530023437311935454983526848574910569784985
+9715236460972266941105456775641088939352379849288420663874812734503948765928906653066695278788734445614220395365589281481052985
+2219149571492569121653088856413977750911860290899252411873082297287513781665034941515671551141663335672214686872998009233611673
+3252445083210515790502427230581525204628936179674886617751355536540130374691771589975236704266655393863956951833668294842751553
+1066643170812591610511115847160870442604844517253754311969780356590045310298592533473063715395834561034249527692096332630663031
+6094678693574789972643719059293336351890222699519292906160704354339193005774875964485745420773135852897610846364640226020416376
+0078821325017540745977661794444919031229533952549930041702337654768594140134838827623154832919375367293846998623573154781662214
+7359805369711475680734455906157477769170543397898162106347663466476684547058977605857152935135397794083854436364067424905370520
+9053319467618246985715935346228519691376765059011804822695041370567668817595587435020117179808441224160004516561911764361051760
+5279785887324494559284533174001913906340668600486179364934683183133265522486775587610826495582037876134991475823478304604306409
+3941979376926208894324337577802341103192284179207690346815460983649049917703085665853453770292030524017689837132097566609313622
+0874696648882529341619751279943169854047021416531564941329234495433297775450795376776860235960754121606226960482122943806912723
+4403142549129181418798689888112583174439363438245360666469436690361242515845002333293117928704700704567851599171947638983428803
+3086178172887575667595570158882926151846562563832038255451988723965663322118638716096644911129577785347672668155756960077259260
+7016060211620447349613366392265953857687262706207804671997611538526738050334785125634177152240160503249217159499633364839660140
+5489512175142718110444335510020717260552562939322469369407097546446468340557730058147393474938996409762845800786386613781180803
+5316893398694618358236834304108186582233111640280225864142166804368748966281116139163914774116490280764125236118841244780654205
+7528194334785274348270807743401184076977359005808989097790847628594537909545137710117536079654129720175240043680499382931315617
+9670385576675265565821666921824539041489513174876467496206200652157451658908879498586135223489695875901066307973744711118179562
+9293554881752014067237144247792025493783429506129044867060712220683356640982811741139549073541449462843252209357539966735713385
+4766042719100373229390546845449462827735583320023428894346366740071025652090167656518273656932135482003817661060458673642777968
+6301526335239349282461856549816100522037177673330915447520746670914149246304276129215650553527297720437502141660843474787824161
+8981954968443818080133345527259601739419841565729583936192031325311804839597158161812415269217752774138988523259895019553556494
+1375817110090726843596408461202879175175450080051006863993971804570798947994555625585878024069026053117840656838335462247825434
+2951238989342425774096587516368372195370856662387116086488893532196578602234813604266303300411633704142608233959411992656817117
+1078366109359744038481314864313226318060249081213275603047710120330297564750748020015170091244280923403487005151336327967793644
+2590644710984063836471814396137903631095128763841800600303330827770204519245855428525596893191150792386804495821205935562805056
+7587927489845850917488079723623306056569190541982982580007185500509384196528055437763768159799054085157690272308144066104571631
+2716691447638059359782976991714931875589838509515317643963169052633209626064370311932621633892908726622398410656122098501462508
+2187341550744516068766043103052788709422923668066123030675357066234501008353745371362353282261896383609682551818558419836467474
+6386821883063127753430057004971408049021180273353275003607608462963509731380707112452702494852068512020333193164120541304971821
+6414619855917522699462290111082170337250489881403447602549155371621815281167692543542521085921503446688385053019234090686216914
+1514251753750908058132963706101498627247758343884090328099690893144318542740931341743091728225255850843917610568152776796003007
+0586747600603620622562637108763020672642036425806055677095355709416205188154703219135342081900691181922293308472380603914641966
+6943882703466448671671347942866066071729197097929636191832480851465967168936588557508460013143074231989501890259153468168582090
+5106944931177904690443492972535629421878279108027478056702348421231814228319595001969285380236108675594104178148223368821682505
+1013423077468134180344202453328649263556597230333389978398486618230751510288831048067335293062077986298410020248356624260186784
+9609742549854821633067526470397698241682366743287992123678759953855431672859515457048320102063982700799641338555460645670603233
+7227510683690963888209842085118318517866633639207568611885740247627869030070367221673493120062595703412511430540635725690733531
+4166904720216643652362019185541125336279973971095473810174484610634739482031555699998920445667293351815342116856019765913024721
+0204685598907595748165591866024787377707833163733227729761204199756529370097242687722444149797918578951904826714174399654373078
+0029695243252514591043935308120948291772608227171634548103690625246068887952914933102467669452782090604646361027594958463008648
+0606043910237689889945195721316745105694059044358961433889516172023390307325162841023925000976730946622777686367139699337140288
+6532770425227279669614506342121365572660042996371513972011473090716295756052824631404973053818570282987235859556502147507091296
+5784383703297394066201455976072965897350946662861440804630035111722516300582625065762906422553404492330383168345359661866546635
+7755352359361297136322168309187217709956128684689901207140385336402261861792474715981622821266358097679527860080999492143093132
+1766368206837633471921145548103904997241216165904015409300725066451342178028580494490424756975699571333186681161146526160888637
+6435676017243653308531673583521916536301571057843651379516536378840317706213255198563089909258098489728121633860286779010828363
+4431604721944445862183599288814310892377084499055111017374193726585680550914726436314439993180521094601524845475777232173548652
+8838913044786662722923315829866963645973025803566829523066407753524509752981118743428995908031509623037684132020735808440759714
+6831533201518779101708294838185079163952906812726056828622166710833228863087344104415454342957894082410432960146722394394312810
+0026750412265305432804678135281250107474394107101163961158631241381326874456825116424953228542574854725058161235809819422717951
+0530095666016377728309821374273950714947770494099333703734720428753672558560341529622248519497385032763976784920070775745998492
+9988103492323582802831123529566020729884479858348071107686123450154590877464099472518837056085048970237891379355375854402767816
+5730632914573233372640655739395224654373166501801926999740491530052469701082483441902155873112176686047852502749353152358488650
+2570177044053910045946498496953083595646140791798652856797075918041625426521730745013108556438270557756261535076617672897082024
+8070822196216776547306746987791806776779912117872036753101249436897151550298686891155685227497724326515850755173992122017730073
+8834834453446142095731369167693716173639921382555584546233080228430284169771661090869805523170856183199180807458939980812347666
+3374034628848110181967055896853894757362330956181597331342944383294532319770922905892283292682026888125967189041997170645906930
+2816796708896328193169753615809284330192400628212014852560752820595983573685822703155361815716715825780349446395688288981323009
+7068534005360767613192042797492589713014221879034298952445175191916602695770589539510033643533276163270684273301159972772079846
+0851847960381648176955810985408204753982844887706344041815181406997985867444440863020286602964269777581948956459433973575818007
+7244153065545137632239977736639101263396745129055793110973443976621943425823784182900120559207556057714294191011934647831514642
+6220112071917364308442903062123692544853904143920646475613405698807838684964691297033599042267911174717943845099876701146499041
+1997737579617455507368079950355247973464185824287192636611840482334933626092039322468638416062106707636638684831343949569888001
+9056473674062962705649948566947590595122246493016055906506275120659977645801864949778640366697230510631836906881678697914437413
+9851293934933351435860731679561845700615460829332071112719063019501427379839759911846192375852475742108532990355637732868083608
+1981670764831163220456625777162284911174669042984422665330847096514572430663915704539930674009046717718308791910081803605092076
+1436167228645743999726495063433059497403336540806399989879727825522625780324646087140141119024144101040594738802339934675234494
+4511331339256646611464785947970006064997210981736418145964184001849876673693526718038480153571548117761471182638795979792615062
+1795579829237064976093578272496505322533909223281608272636931019121795380635442871500788593701642237770643966129586714071750006
+2259558543726883196265093171148297545202455060457641437680621020678468079454735539167389894892674876922877875836968284903103240
+5190322659532635977759442475453937445078305277952610411039017125942798503797185204729242079034555967093953206391753749025286545
+3346586896166410527904055884469771043579999692960199777847808583456813215611676699557144873569764821207184084966272170201919310
+8492812746065013433267691323002027533207826063607337577540310499920611687417123621076705455447051576454279273880574231655581484
+7963980271743134112154087260650334248257065896933807620141668762775373128572470229135441642876072741306062133796013873900656717
+7155588355012012778870617504567123068873574015355543463865010611682540901252618661459039457810933495173848721472502301449759789
+6250342428228956319030041026630301654869718238658413832351916020529083012909954188736775565330222063260635143292678318707172682
+6306362489099506339243174369018743275045301435603437084640257826344578993743886263071878533536813315686531934206065891475930962
+7256078764576049009416184871748648772794832357694303718710674780587401830972226331756569564368514137449167545781329158975242668
+5137011302637382277771122596368810380574982751431852882121643844964841634725254405565914232138014950212916177841984286676442765
+0130766950573613943351861223297588274240988343477886895038747758639966388317215304568124673651393253970716618528199527580176531
+6359126988671940758748887099156058290162393017636744749307547677028026325587696225823070273928497980385751428178855356190336058
+1262747164602205208071416052898259778064629199619315166088744120423992672210748461774575909144208599043872184758764391922991513
+1637777143251220955861291729128344859755814246044289400356284088474702731048933137147907743901585132956196475715784684303014662
+2779656199507816022148661387875419531355613321583333187996164541556836852609250800638246651009398874732599973734012124894691052
+7354320128684821812105410562348993616339745664287363950112497961551242247169256027249678322546929448755022227225938009677843721
+8972855810687812606653074585753478301824708270260970161604946179349054120962204468271996990113102973342165999101606421899608935
+2427496334389700886512192278170872300796174251105207296701976843139085003204747190192754643836301630137058164840301068688355227
+3959418860712955101125551436177454788270598656333682307048221492143694319890230219738438292220497263359673419823698673057872078
+3013408623490314068776627587135426768753482653895410991590323095157887499728772798489129923069618646593123822639438579269538635
+1908216328408109211109195709992731650405613610224189255235529994289098765621895894667201782074632616819297670322225038809119550
+0817943537763128333901984566290468707429051150902489063403888015248830107015875323502758058360302496764604163625874755344905059
+7334562477121670573355518606105354751505482715112941146764597746549856497547302376364513456936736713783904762299121613461158516
+5283407076162674672773440443861453333470684691925760891504089347363035836279580135355221825821573398468104182485287843330909617
+7205284306122028970211792875328746564733992888131805747056055043004240391649557442465694153748887961289838987106491544764907052
+2500872325568857502281229098611844366313487869502518915819858430987626410127129066096878146872919622682973073559229804271266907
+8295782206872660046903141337058447164373782585028140797785111578071196136068281762757693333793450310851105370333208052458896958
+1725889330426145518489875923548346134621897254499345669060138933732620752098808224545684009099318550221718273960774029508377011
+6086360263760539829227685105382480409473035021789956560069988221518928563686053953426925951987832850158619577369793062706768043
+4352919017742582830329403068368693550555003865896903349651288061511525716234272382256062983241592888339539171693959034050993111
+7316775446918119981332285689855871890517757525471516688406003916733927585058269512316355228173253797483394637476145877140830653
+4449523419101039158408708904430347733804700552814623747680680614331040890499889250979677397459532347731846180044631683772954511
+8775927277284478472403620186389038850970249719140155845452372844321949705137084066166954690611328982193781479003940799798395822
+7036309001309751772232372080817838422988947200353430157955341599997125428100524596360021893214442902724490483771053395386266905
+2526553722458751882973801186174660169500936459737553375965211051557068305755252365586897544315025598670454207459745656417390706
+2637149880243542713228217652476736046313897745886197441813742086881967480415661410956495847064049122729695529600136287474175290
+1793795271658672504903869428016853432949018555098626397052181786382888682206907544219009649133780351002110388824693692103301828
+1084255129975610497399774428514444229695501619744314654316691842636967058501657387850037557822192693461604997872810120193484078
+1690635325513958119210187262311486075808664902577687177132226261921963946973671413085629761815694454894584772804358916692902290
+8584983060051303667121308176671074873807110361225378981139031261855126176018462516372607208578426174357538994152717337719252523
+4278036428830763724403099207458044021754910574858908048715320547117712294990028756794510860977637952837840922253254728458600984
+7883825345262132475931206135018623229949112586397174487649066363051114417355320278795734783658869193239014023523778761960029033
+8695026444117478979408146585926902316341504795145288358653821833800650855569985787340203101735816503203866669795526287437002033
+0245051742430260486282155254132179648064481192529358125651323989892545661828432074084630060930677773108561342125212783387281955
+1156534912244337917835348237158665382209292463641851049571853921423174805869049378131731211644957860891749912005458383867541676
+5778772564492822262562399502030821202632651082331648596186198421567114506013473886361019711381249854838415342169443696628858178
+4018937636066081000726527827443126701548588875106206226537909295887328559668190334839725133746234608966652449462868965060152769
+8173777546154775498367210355738304841393638757271541666703324260466614672029573295838066643359099243819511379078208545782984277
+3894531584135582441443997552974471433572355979512626259310899921004753808626563585592085956971397408889173848312206978387162122
+4249778224435541775834672279093907849532605623442929414275448734738794025759189569362602709330104719867391830325898742293638318
+5618458472230917207115381643121156657396683440299320861523898119230249426608095966989749077626813445096806473183743262392826169
+5141443017081978141752639960290174384446691905687453519079674615609648441987212131402698830771368709970102768419122745998384912
+2946562140012561122001343127839838295167741172616748608003211961781629115805578417306196780198449660660896672943032048541196007
+3488478058250138575080356458275864826075120035949332139371412714212223138848322951784969631050003335580101622399775487873990978
+4317860282593236100733831872685638869277432762005042347567404549772458118340256499688632865717895145858533810557576307974444603
+1928173630042126038543686101259940626688530747112695018229893249219604395612728537717051374474126617790845613836004135628746556
+6994181584676204860202674587876078621483635083475446039294576324194007589602377577833162510613729896861820149258590200450670657
+9591153201889299370958865743889668888080847094554165557463441635078117012681280739489741681606506751718013927402701136203548044
+1780167360508315641369667116901861812842526826720765686979668702075706357523197794146674984683061754983908320058757429657215020
+4621260027453785113729584439569855185620374311773708057945213037359358758689719104605870656508325190409944963614795797144191442
+6611412529823091494357371703456481103154272600004279607488151916951301067639113190114505272247774489140541745738078452548556834
+8106748866753253878302577929999224844368660368702977874939897082451513356653811013795048262545973632043664542271741351318143337
+0778069182951962287178555694626059563658908945272131830094793792647180018850962827338479100883010796179956428416377824203799082
+9473023880877077477396337686061036427727779399244945597262198872743579391652952681609513942805826872165303709494805916573728492
+6294092277154179951451094865452721844277717466377028709711650186357899779470166784063622634966195721705046717157464710442807466
+5804785796886616339545161571917895816310538794711393196665470438339980915686578699904466139950097093535760550147855823745768311
+4727439998296384114816286463820007469707513836075275400610242782096499770391027100262738743742494025582717951675320717526395925
+5770688225429387772370873623458820190254941682623110262393319797303540835367273621810830554446149103975368995431078077876936297
+2405529175616664747550451981407708416427503988134127731468009719622521436517602196339409678849267725633683568413854707742239684
+1747116986005191343502956460687122356601160408668274191052227378815062922961362392926820216609198684542476134407735883221896780
+2662260497987146574078784874203657867733135048405416920171958838688884627100473968981627006284094098910015991752992842055879818
+7034398681569535649106832499610645350629642323049347631261095876814181084980886779188444300173631359422796869708950194760718387
+6836733703618557086120703365229061728453720426186389529699692510071571231710123347703658534972106524417884249218380254553097325
+9819799847270574690752534052463450597318916271469886310284525865231260264874522733678980911253701800076986898602579299994595517
+9135488779985085378045629972341159746040904128068784460666062698063117787215014912137720162075250475265414449002077183911431414
+9809851736195297213683107966811862847637535801414773082875296684360754325074703853487298740359726050853338447561139214515571992
+1029599022890794387902179784268370369360935567144903247409435981421651841889958031240517172069175107596477581973881408689860362
+7400367259185579353010164869469689488102231791643828135531761198096403804156803391787688285965553218505121457658933398225058406
+5220283029470788325194233641742163486977117357701064964101876499830666046451739488161844284719262317454589282938926798508893597
+4856368375624850629404156042966360434746200563963426632219247842217835149470275034357811087591708435161482657165228727592100816
+6253772836778061529203496032750827006398455227451857109564867169437129073006140463432201664058302222335982176666409479667581160
+2936456922664809261586171438046311878472513284135606095783748274074803411461233988794425470611010249655925624921046206975885663
+7903340067868061097623144373319704434575514501755821812557204930865063397777392798291309341112700415633886191910088310537801960
+5573481392684970852911664492959855735295070104374454536083712417507044706607037494482191236686504544140731669546789850452790174
+0904993356742978486159542255719565213826027717277534463338027027906360296595539148861118855418724089346480767402189286985762676
+1005223076106599446960454896515318564456413560395537757983458843931854126284677517864393826744115625918435152244510791809692478
+2164405990650873094086602365842140190819719314893955030230888932507331906676191911961689961891255808931785984896260979975690681
+3253727014960636085246150995307788585817654532411113862158610700251523142672098671368947509829930523262641611496136611155754050
+5927873322526687970315921879739844277763573086829985560339421326548635360045717801382027508629836290928584431149151932663653210
+4760858192547745555268997678117732829237567270192822266668837972286266876280740550930386549524048812443132805094528566843643923
+0552200604353097511107833851418517885398565041104987050582967853637644070929822812409158588536557876274185029987107810161351297
+8488557995995493390642962339468082402922946581115285486581085810242830297673687274512734725802547502660334048415579446341045330
+5709356062023991965872528242196958896198910586431524813751700975464715731688842846588438403790663597080684309160359805580967928
+1809180118084899386382440090650505696513340627765123157216132637785703218992306349927445013022757227491085193637218705876572392
+0750092974015461540416097560544979024242793468547428554110331500932107320102022511854661891492261408877458706999860502548130498
+6089719190070430700600786193146021409101280174362984471307624705342744373049193769815102419864609660529369826990237068799451547
+9880823550824400406858764215681272127616403736552454898294728046365136835488231881807123019108941139138735003722461424915329488
+7529037321181887616470646776506017170053425836736636947752180676382271801340633168596956291990586642144447067879824547939050775
+0702265125795249993652978449111254341598591409462513412644706330823597010310419837016366205284525093508925291114478065520543206
+2486005489914656200352331842636430195667576175939710807407359823751196926836356542172998603833007594132689750457318477364742581
+7540614426291493245957654051180243018629278083258315716499682711339148507426602166172200768552170520220563426401305349960660512
+2404338617929580850851496148983728094122155851959629735499313721174625488662780908166750428714979229469660586277142190041914098
+2734970584167413642829413555542927092036718157943315563661250374551603827984602155759774285156429894221533968500275418633637182
+6560220052859607041833971976550951076186294969188109531953615241005064465315852535875503380591519469842863315620903120851882868
+4362109461838990069490474891539380133820330011017862518437725479693309451782697543824505868730424985500423739583859994419014638
+5084805381905175100929792755321577290419383142651436157340596535511027236705949268189435276570853108955493181266234603455114274
+8408563281709145363110504396918026400160693545535873614031123523353385515760396989543124701606521301192906747319853776998158894
+2312458699599599230972023213413420672303278131983854442962403875724144311681960596932014490316204359247402654596736629024793653
+9839221740989926513947745565345687824749236841443758276831531279631822480088615812410461505184335496692743570654981097859767887
+0148513962240941032376953093608164659349988907238073209903158402845914764726830224719377417036845150993399330628686012123441747
+5919614485617148484720530134538022911021657584302803306902527053421247675384565988567910916387370777305148589468626006026739483
+7159664152823325316769176118475149162428707398939203649766531576459678350978394525441052205823105345184421463902500121849981000
+8288659993085551546441461743163304405139009826361143974328223331967419739647241073571212327801960556484524118468883764120169524
+2246338306775029095975369446186770386599660011384020498379465046982275031718873753405808637548601707969197710675661519594764281
+9599700671171430778834023658375047244787074487357323294015535711745803913257607799601446000833932736200689998469969708376723008
+5081943791810860552689101511523648202214658112058332928346393590013555144813066914194030280115978731407804149764646197662984115
+8801177359464553557557965020150275317953374369713023241680758235462889780964894972416089799047047809594791811478533742030190073
+0665429844750818754679057503636454736605371676903157540119156106676570191787583727649819947468340786574584101743147082806534991
+3657977605543416424987117022654696293608374996078959363230667155054631271871981115488592293902083994811357408917297410729122498
+1862650934481731910956432936712254764601612734362801048040108459535230079759939514256093409449391542317896091270323008227781776
+6653398313274972684240408723778161592189390653041468423088421653090661249171357282254451145484842067919237970412388771640682294
+4059821256052393643115972017853583376641290368154419793622859038067932722073228138326697082834080833163668963795873824307443161
+4885945116785653293180979216652517189039102100870721593874386070396567484340764036310998065513336640289679790609291581823883333
+3428604720660372157112193405611757297738411485553283296939642822708738180393410023516446689646065368009275111140421244624003704
+5562960052258931350563961074454414104687746794788022658055770332756970270739126216170694306943534685894930524814764997593650416
+3008384543733504706776478261526614225467564069116098586935957253917385357687398588155803265872788670839186222042335779464643037
+3618994828725096012458832876031499829184389279845891008599618731986280732307102787004526300770299430819579608003697211024173693
+9217086377524454012913218100708405723232921242597498783314818967648121936298190307693812351239182876627690699979858904402641018
+6156985750875948360548164905855940506817600324843389599811157633619677210306664432514278405659673075559217581592839918628085400
+4764772987507938088705673246656764726283775492007659316410580014942504090614797117731679264296150069410102991752421283871178501
+9088021494611622294962362961658529846402973311983387998125910749644155422299932240783260368601058914444067830424352644504379196
+7142168355025888186137900382975205885091374237093915396552747486547739152007548268368634296637427030850473757422944218387854757
+7616183325502874293153395715965826837360328123096242771948215374071981140320994435687149135694129364024023152186261051421982087
+2832792230789485819847349814552874874835409931161612591863141976920380812857719621635320076324767599038119716738981834869773741
+2754959867605262800904073710237512445047870616662855713005574347858126481109562377143573312098011061313182520482126994274243272
+5944572495216446034342198294744331850728989442478427239279385418283344155306850003896073771784045248648249808863649089110085745
+4935039678346741118281854023639235666178336524231495974905785711915838245296715638301791203620715851604930385744033263165263809
+7601373980902035512868636064609722029939023536705525076519976556652492714730630698715244783359777077548960439099573621098774644
+6788103237769355632318040401274560065924878241545893694505228598734431875252964572555463844283713282670737691866931493869606535
+0416187164312031460323292595651046052380878338516759425813027437945468646970166296000101963391062426079829338723963248745406623
+0923089990664161924027191610177696764629811421643542437939862866986835556859764272302075103487218202328441244550298063164681875
+2019867260237068480077811032787819165579411546914115220954604696377168121100888419574969311251245311564544879246746582842436916
+6868613732260412990938531237301911324073055318005385120355972354500615925738636280898984348888758911483752216818128353784893125
+4877207978980281193491650735689287510067435635758992016711009033554062927257985428856499572775171602494384045603122508003854191
+5729531014485818371423575856151555802439384687195667542811436864469460636476071341511650757925855405897036006697261458329928553
+5460991959983883494783035364470651652782232918135295761659407906592669701830570881217510435070790362298581095301898060905173789
+7646351028988526172675924552809872541181626761125500157109077472362508995981523449708391893239705562284235588614429905027555758
+1619134181392874715654091932556140391724453901036282239744719175838602787922700433547863998561669814541630538374359332841359124
+0642132589359772875036014752032306706353508991088875094683831897858049315214902256977825841683325136398731544129046064024590934
+8005838235188541103906355513876550842936138467720245485620712847710339766152168792765762537490548824247757795430623230546063661
+1739498737086961685166983125262113774813358028871712079307291894391835363168962025939984050181882718770421839433587670806624476
+4755044069459609604971745446900378189205860081010611662569670882836262612421135453240273781870602310532514360568130085933991129
+7924290416111768289187834903766663006016528601174525638099383915633909474617753311810491476284105443999724682875652267118724896
+5850681695306617855936614324554272763867627188224507120915540200480120428647332751636414058742508052557803594703673781795569627
+5161939368398633733681924028671740682293310854421624725144685852406527972897380355105818239535806432392343196805358469063293155
+8819559114109771559602841216196553885494830284200973490048941610619985614867118986891106961906280843338752508763555675909702206
+6241566490588598271025864796744098875607062200785043619624462705052447512034382219094774621478633751781359662848610200184361678
+8704633729839925740538038689681271982506814499991016892558765319948519205733093865854380442216165127136281006009985719211033451
+5874590475603382790640233559612673482775953839089864470737210616394894296028059828241641608622138456309335058488482647911816483
+8528577480552717173959823507749229677977069134280953275629509898562844929982109573639706635205828305920402590508711781395835713
+0089930344552012906619817966789113931607542416094931145768127062728799915073397115668423507229674038044945322045301649766598530
+0236619236986319774758924493517372212562285619369190213778360087721105343106507409406716723533090029620699768530871602210981580
+4900295631035231554608058112293217835929574133906243363911069130644679986177379278388410792340109628431007635443781281483062060
+4988368133324357435318270787600078029431686121284484541827394881261897104701243599451161363480613963194743733844807088688115634
+5178871803932196297861340370803170767481272576611956494376594793113965439245117335478620700378039639755713637510132362926267306
+1973846871626730910248052978143950536530975380151232887509932339881071793647054810578672393058114957563604971882394961817835491
+8978209292630747251522017252062343300917165930874691119490642832557026684811610939173618238354559097444010525631775837097840951
+8326182506155413337881369137900095820346248710691175947937982923048432643166491650906416257503450243786283464120124419550826667
+6090914463028322098876359782808759824243499333411218847428154348072847658504046701534863522297418259623151406625685618209367317
+4253745664431692653592530190665547218310374995530293912340336697232683775175851639464892393461388136647485464789810252552522056
+9182156878387604674503124667923684369744370052287701241975705851689429509464670883347575783846313229293967680582071694204051095
+3321006971958449910630372247668837211034782309154572655303854890011708581736868651280877351904031869989741999700057554577154390
+1273067298313752548096207203603148138418750927315375729523637857281549085842436944573932481003443446922848528006413314412427332
+1441821872672191871420138772481289303458305298682170739045298765824678050356023853590500427850176428627107627730008396343350473
+1052326101498218606100898713263447573551827490516947668567656571319040829379674136592743558516074455124317265474909140902458087
+7834541971992916704455016525869622512851276565353916338983507230882585013003793323808346566693345857527479053033593116284574877
+6838252895614149905894777313466208709968773989472894570857815422084908815232548928189324969136065895039808122393702760781384523
+2929303794620328740393974372454877708805842222813897741603177439187185228877406834374147233014054610369299556729412885884560745
+4370856078387921623155622787671852014805409807299060561419288539719819906697663945124473843579383816264514077377269614977581685
+3394601383138607507974293429184042736065549935759370359893007688911547744095191909676349245026886870781533913476330551278360831
+5351259816322765307961191402595778339300322026355376338266384698585109900534462235764152505801492032987502080039176402011160649
+6015860540766825761905783450339596728965747988413885573654798343784315606643443103943694670901175274103478596479365688106195479
+9733596316022892971509096088392032363480840038385290255713310540683102401152243848292964926264212842555582110823197263253672828
+1062515708221923559386659794495097841198809034454364525085442636233669203446069926961726048176600711294973993391741061849180079
+9806127623797585819585111237146636415904332057123217989550966977692535517011996512651123910136604576120833852264076101548649068
+0894752723723477938861483316019471992063859736335516787664755140329957520633060255798252299793172160680450787189861312439796670
+3913142052442456614486902320774033281367626065329089488796925098543116615817296515061149179999137691128957532263158924327442783
+4918858536678070436088759702284980929577025191565900433342638171236644159755504144947154030057873677997786393398810399270491800
+8872734106335380929798217774610094691386997739307412068494969134661496618521118209935954632189343140189392135323738890270473225
+1245647673515237131109490917571703008777281273557596852732435015863930630266628924061119974383584899927931767742330245961719796
+6852379757973100072309834676038484260260899346508201154263890305770366822928200041404900931901074539015449894481478124870846606
+5288592940348602075775045536917167753748198797428454287343716300518081003013742004598309648467119358078992444950790157070897622
+6178224434793312241397484872165819485491096197408141733026367177440768594738187232231600889719889461459739097869779145699996070
+2192775687835295828387187709692569714086691619295450894879843196267448458847228413092057333128571855124524447189613776196209305
+6242914540023653075456224110675459930237745861318742551814072907467664681202170417286866153184100097311858010110265935844444511
+5209497239417620919469741474768380931492201661270471587341653498268177621359803201248700031595849957309397980724999380306103922
+0556894331856087053327675958304000445533946185075415894264871473185811965493131424842414390488954096468377128994425485984798739
+0196159676818515225003292466076872625799134390488404188280002687542570342770954127173812843410476595231005479765885421327808255
+2605242865388848411850848235973559236245406311003883744452617685164124063273300160172061005325886640047067612731170493761853684
+3723865217540793835273126631505051186346898929963194134815240955269409964826180214819749886514216356192979128714223656587784030
+1612652380049586827710856241890765244152817303616193799144244842589626119110544403111366867458976947676427002814778923808924618
+3631721504060950588384351554676808360758437911729833313655406741373502411393332262640744499827573245395519111703225362606878417
+1363409383247041202382518900846037480203513170344097014906470642027432914804792692599759592956926861572014354287205548305433650
+9938363167455625445680112095072694438021204263665499289036436205115409602435745285690360330318532747799997172095972559600945294
+3849224957526742255789376070484796163223388025899309472042686406132560940455845848040737742829859477224469824421878404438255777
+9153640594267832855398773722288983227094747426234571630063269545219291207342356377829705537624593717193629488670483397161337722
+4742683466675948276596206085950351177248268507712030644980189541847011659976997997291786802803131893537147312873666734632318013
+0962031832358588577470495716330583413563622072795533159442347186921867618325791765612531566938977664106322136330634216330706485
+3562792846227123177501866289549655646263423972314841727623087546398961182987448990222751356418413165373556965561892665216006475
+0506481362115739578595809306613922949438046074388531145186498774188751322860892046433870735773039483261252104554347599292426213
+6629076659887419139215806756640799939588104500582964705062365481405718348479866775939471858338157222844571173771380330117254323
+9427611277124624517129218643055712610406848999072749557192128496185603527876575966140152280783898310639896801498077008734557576
+4949349263979842274642964286301282439502057095606102606822710846752651420038445554041921101778203644249576817202379962365236644
+9000537778793090403522534841735088671708809700351632320108127651758914457761194719832533167517277944390073544087779452376879039
+2179620974987315833763764525622394287879156162214632089232065378247731638836108414730685627306496030775755582279275263164338314
+9850178620109230660864047257606734366763600031327072575073099542439779650618140023637464021494877439885488556217335419454669846
+7274436451730146692806124202594474275423757115268107978580315116832524063995327727093500514697813597360878942124695394787220781
+8077050800020141873083229149343719418506939350096709806686454834234546620350690053797423042331890117409969910833834635664137578
+4222569085314829230694422189066171115029353200770994620763730497186499678980036529016196644500138184587387164123266827728301061
+9140763168998745887384781477877234025340780171338591152461030018239430263211801503428946233869503372300942372235304400820946852
+8437399467538616927457301639250511729312614497619431195080809960619969552298634956256648869707957943168309430154835637684617202
+9927888920815679261894236713565064562156846670872463967287481642034739020192858148286147625951137420641797396365115772980951219
+3655403238951645285818609634851118279549531888817205406539748497770277166060720853420241694457643803188820531391415953932633187
+8096429698574955422724412934129163958768439154851606366794537099440778504483170647334793461803467077456150095540043989710581777
+2365201968161103470136827409580883843970089911974172408580391996075540014445987053836291636308746569551411995558157351658739831
+6950345059892537018933018077820506883809089865363951638996552650340293111131388149509355326175519823347067351884531383182623006
+9729692983578755541105852708900437725294440871971817004794137742625651321002377622365955498287088740364399525852759257372235252
+4593851734614428386795483124618557640086184414899615960895693770722697765927766996280493365204591488466719654529288305662919475
+0122479598904859751605583470001521191650223688479671370454989314043303051942287523649808609527628133476925823025842389422672084
+3056608819600468295745423499468437706122458751753728982506585826980159252966514250379765257256312249132321573973154317443215255
+1261003464887189939919598811711885508553376196973665253914113359871227784508364309872766800569364687529405313394507842277777341
+3335595614255964343357224505993110214988297629416503148121404268247459966936550735839779347369294370575468296662036041463516505
+7279136021331762991558929156754763672783232261635376259854674650491435829901582103560659803340084857348232939069746185793481086
+7001312755863777334623418958360382433258119385097977803059882470820602915102809159265450380632894446941317444541503087066649605
+8796169740654134032665098260784549928283316353597416172219489498769356834724310846396610790766934291348253075369200618334478026
+8802831163686839169667839421840117736653893219551959966388948111069365662007487678001136916755953605936920644573768537311349838
+9739545132806507773311726139940569054566559814706558048797461242055138311352937387308888484537481230253759123043684421386096698
+0953084370435253065135920609321712138864781756707944630525539032264477854921495176982483322151742604869890730064964430072465893
+8563889642871990807691809483723365775240608384031148556634799934500723149755352447233079304887498827996963939978814660785015524
+4422068594927829463105462477608520539620307156466022889708603842952278355035865136962605151617935839688034493508879959012432457
+1797597440197984699879058451944014171742351115567915351330880426124733117964473476818687526048324044778050824433512831279314278
+3544880014006914530017330247894174199038635755809673971423695196336512713364189925640866570283506889971990951009729565756092473
+7989020444450139152190142450813270776908916050703362005761467814560672206433992898775383186508883181569920382329721780736328572
+5963607248916565843748383716251646836534350100847190837736559193434644723784998135363197913246364668420334826697708573880522965
+3263484959293045146013061177283236124170085863131765193651484251463844732711431227375764646336930721004123585223994485289918901
+0583029668150873954157367992526151571563606918837234329358185868795166989340614129979830550547132857672143145949742222265113600
+7440572366306644814358767338023644569585694763643144805041668167574800647065193962831865616870056333413559981420227280146948103
+7295355536699420073390947523011459995035076225978883439577116325646324872851036992256964558891639573786018094493982547872559135
+7129457262838894246866292831053823350947068553550051302734533231301531811721807950765452389323781067242015285235015915373253500
+7003661686534989695171145431734885832337556123063280208162395256598378269110597151277334587048349487450140097618803853206266757
+9082217774055830430004211027285925285344275476747121049534781396260863522010542259349559050699781590339007899734612452403479287
+3191667292995301649109040619271406402727834137378627737752393244791408796163577067403946973388491815614922007647090321324522320
+2949712664738909367012483650928320008049914477514031653686312257788502415066119921871956279807885221949190218605724017500310920
+3169525625766817202209440542641629818384859195018848363928308881901815336912072399651202491194626625193357131514851165636605801
+7255316665553834762495164950088245569336300767957000036188227515262775800565384194139225891768802813443198621045801692291233140
+2574872647913296219947966169138393924496399035916640976364671914696565353222749621284958305509352891507065537978150518314618840
+1953749417768878991833661315137426428652077503145679920658786397955780176167247358992933014357557538701378753423037285649046608
+4668877807427263578702242652781568611601647436182495270690516771196062145719412914253392449657363828299691513193636571040444936
+6886803557429783411232920271165325523458164084362409904470754437138270784982746722601116409545759719688367256037780110379647023
+2300356518881462544550334413932731049376257074071686920169237332025867743966470152553906187385400688773328478685498436856277618
+3440412356699057087611095963196908710039931495043446625996426055839433344899946522222609944936452224313579344290272586318016202
+8993953982184479368753437594218699447584551919428710623167603425460525558734552005471227418138809891695708393142992004433396157
+1641364290874900167201473644758505077028954784718448987507776152112958786620272578580374033281627136838108776465262593788494546
+7335791534524477898748563122556395894974284747735359153516999217809354333772921832279669823385048414976444462237355621384907691
+2772845418405555209223672772048928810050444241654554863085813477997024445507615114437302354148041362541497074784257678291599777
+7178588655224708624898385615582303156928858845044700179599109039474166324676359828675085010955238472718587302252391630153958817
+7714350463980300266933000010667914572625520828229727411680133017980270989103849220980928606661613727680746076907445089175447948
+8959804988970943750240542329725780454835670277149205665534383835852603494258686925800889072070906952377561912949333090450610435
+9127584427822125708186685340454898072189100248623017561567872674357247419856515640720894591586135918230623264124957308938825903
+8565660274882658423962595807578322116479785809616786494557353542161430392650520437776730973491703217016387298185714704526578560
+9055899627055835280579204790473134990779700561942294557075688923514759353053304752653692669704340622777026507467115119994712711
+6401990429555126633982558874714554382951718476795179895512968275571839503381782370343773457772170386412634133151122279458473043
+0293309378136412704813380987793756861154395548470319616928895806731980671468030021029452883570696897386186564749939824907170573
+1417717547255789991707004411151265689787923836241613415526707758612724058279277154586299713815047231145490533591839466123670638
+8468716387126244026336620863493031193083664955579994896168486675960587844522828676215258682659462698160621004514607084416783102
+1449640886898263771104309544234611139764719954279503593908340282487665393419611852384397377672021450701130079538845214864162053
+8048887383017701836654298226594900075026630240187365178333016065699848058831083230977644940244574444820285738121188435273257549
+7734838976170306869973081121181660448148530318134255364556117593964696552501147168845028313551613495459270535042160362667658266
+1546639029308273692114824601121738207436726090786353640928151613146720401120659236951025944213817893334993036938357931276755092
+3794363877794105698247622335925064622343924657500773158672876932260234127197098205417204884907008074223982761704004122962430390
+2332227732674259579606138447783556533770663844706548255581644643545209413054398521429945056259218551425238380035190336407512204
+2377559578117061565563176922758264522313042429970112963159461355099505172026291216364090521544160711259708331105724128544891227
+6832428920554567726830569490691102432470549042227057932067103955101428247157515420358182404777567376342028775513115385366928419
+4241634693879583625259038169292585038330173637743744110426172931636984875802849325805759410994995655688205543970012859415471525
+4435409455307673255925091284402380740900794676435449835586381572908519616958395334196299914509777009013685912584824599000928046
+3987500940366892833785739644668889848240740024168650731790637517228616861342434915208852629849188021280517196274460956387434019
+9025408507685643206458885320228075047871187183125968258455419735129168110055303698970042275578099161589116560991845557669784646
+3366934559408606275260397226783303207383085083713447307195484607017198247596814686470103165356557218941037264416211493596219700
+9986983198296827970312097410216841561044999906047830934706495494099795173682393665158233220314878778675703926172446242051213291
+7327936388263057744394340969867975674336916032235104437222484250956772949755115175068343392125983148796915268153189466560134516
+4505129238068974615562203042384229709458199180125982048735704933556566236123385106774238252165050271569657572461570289000767894
+3255121682739504137653843468184029546420570010142268916658213975683507187608005044348538495082520951103601067607492368878206287
+4806852545996927533787451480123813559737763425204966730971472301392243492249231539770928832609537982396509758149828504617903683
+3852759316339548366895421554002413138488562983328873969801625973328318967409411308340716647240522981188392227872470754156065273
+9712297766053304902554018245083167928441148337025924749085910105658941917341095233228980927774840543348243226033787592995988515
+5229452832882947701986160360761878773430032426431930521890318903440689202842760168592576826646125537090631410703061420763990796
+9492775501530308620829606600311339640855706549659904872171618766544922435708097161505981598338090549562866490651446857290681656
+1678808597459616937537502211249586561665053229525645425138896011542471614595178170509581277828163045626690556829964393718215591
+7053324203154477437019031580603162546890080238913915157646559489429803976541625693989468806549155901365763128179885048681463067
+8903137465669354155616857417689085085205927330249024040964205952230818210265737328326102255377329508350857922236822007786665553
+2734904576394968648887628638128862963608976988414917192020797115239688653336018428937106985737003652208275177709699892675605393
+2387808386702882349280874532643852585858561738093225119093657885192947905905747402618285721157837466909047447734685099503267111
+4222155360968520550560237616569205752212233789555461181069785768415048417477169723562149137809030351670058489971512620085540222
+4298243051299268952240909211177826836030583513734437502197104884602882464340255753900393068054947046141922743129752936688868680
+1061375462364377985228292590232948700810225069864185759076897910654198361668411325978825417457852278989472721657536588031658991
+3940469338205826791620626804680412258933163753767218044848985297248760060861868407223928680948167632232230076213403901155993516
+4300489987649264460199719443525675282990880539122997731272161031062934060033770185574543151609533413639501738216215062848675971
+2177118188977585453528133388279985990921229278769939253605657684059131396416486258985713207176129279519783451725740599907936598
+5468202247459866994978249422059052436184697608003427416719037990135361500297493876720017894883453685240892163318994013086288251
+0775391987748089844439257445352687468561143051750745275017026626096588861151466861293340177217020485953364933966278607508804835
+1628141832107584076506487704333155316297016420320945282094351104594402285535278391969212402643994113779520387919087141691462578
+4568389047366302665905669107740203378971862242851210284195394536420153604497510004787197852478898999690840962496286253318550921
+5915870003274717803413556085627698745281531034825477926175968946204463905051355885851004345422507537344854894128229093755738123
+3106488353902440267975241920861283331388536648597182081274348906670754514090626662608509624737135193693712779860188833406087992
+7845555194352577902505815561879589158643398041086893321684441920278495085775044919835855368307051779503838399479822915036806084
+1432352323824143885623247262050454612927281487774810795510104248803405617391180050263987964438216016361064912733157137057008420
+8930414578064185485247400714821333921221435324501439994244285682760117301820424406392510602828280562393052749013520039103061655
+3173670884438194788166911165081056822054430147218290866655074231005149200684080014396687574505239932587314443974144267617007284
+1527450743968461168931869720925121234258369083166801029927251949358618661922498099466741377608784560458426370545741910023312926
+3234042028371733121222497619662259149254047701278276017559926645765011785573767542697475259020390524937117767929011666715323342
+4704564242794556338739787095791826301668604024597313082723259898622680965079684337190731792129157208207454560161440807617595099
+0586578102694447320030978034126807967366576180034644346378206991116172450484663474175770472979363179024738326934451423318607575
+6711140559239053730606360957739329179929007703740765446432207582934464258439308670322228705839599858462219965901802441668368441
+8135099406701400995240439771871466473527799329781080913941715241663698683730014850012873125772974693072458542177139084387995864
+6568179602365017697198231075678811557245910639538778108917663715366214082022315024791477373317009595760696873073681125441512291
+7907116539452577187506381898980888332568593365733396512784485641208492339371509014105839017197673863709466309379039960962534849
+4750829188061091962181509528044851805549096285740983094887975885868844208625379458016822827359147295255429793714493083753502809
+7458122759750053134279494636824383187336514214679539541415555708799139748870593845560799552363619897719534116667792275265497323
+5164505983084622666859401822913429103147582979952129213026773147211467590148787858747588041796556975884830210299871356341343674
+3017622046748766474496658478936400050960631692047289817971683454103138868538745678486924385845403439475522996310311537377432294
+4414433427221551082351019813726625491301604743637648323980649889708459225496111765515476857080238229389480546313915805440388154
+7128048414711368158025433805098117535633079017719775105234085215317610434688668866637527464933292899758107458405969861125706230
+3650863400245738680980130673926472854780296246906056457846071189797804208159343552552140320987399388241880735463419185645329289
+3725491818789741913366698889863185159632846810598378698135320769928269090296785595628838126516727088490704926873118733305049981
+1156989564178115063843077403158558596361694573121010738084003904783088187504126348616809589260761446819325657369704310082822306
+3039078554378698516122693013852039986103065748081512292985255853944982748397274910996825923066426171066912792454508578589756672
+1894849971820554276778681262205130604407309897326530536792905116831412406644096303796353324894146354102174288891383230945427806
+6519430441043631674771677332934701069341868125297788424647970576482950339536231483156528606063230103167532910086072700422834732
+5003294909621810744051481544451641763277370208048653102677095428677725528287642449117886584959778219864346164599848968697364087
+6751096317004399279893854072583230132666460132819591435600170059086840170914605351655306551416965997517899522960511150518237562
+5960953398400790636904166620422410033200069198453455057858306095484024517953196610901762809189095112424175853725058162186086849
+2378590573214575182954920757796313474094094261522041549359071498710995391605164191319908953433331128043052410209542459403183882
+6967512166626834760387377091334566417667045028443096775043889705526174743033818006933449908412813794430186357687977532151972724
+6459437209781961727829502811704779207375810741393525593812033931653583330049048561114949732748301604240502210577065589268424394
+5485945220569893838677587873427380906709988368671130490257845675526326075411511740051320570135507392241324306058959038656611327
+9867804575762976412063217986099462524791020332282964702449941371619543236717809914141667173375719858685004628965511347280443141
+2110798992334306839358051076527899985588107686694616660268331099137978416904137377280100977825535315137051402200610861241845328
+0363449860601942956031660094586702469467050513998615147930502263169980700379643465968570908871332692146680759419252634341789329
+4178175171299653546801324512595807182660716928201014996433033979566075147588628538125142107342090640143892070802843256418010103
+0456138779092213905930697158012877976499848878257289818896704580464918962127445564050766970246810568260512090191166877529968532
+5482828669997339487166576516726609979104834674845622909875424783106655102257236764736990686408975204793086071837965911886835119
+0267535380044835507754251971519271244598217325940244403179333727723642934577686643739339224195755654907218801997476469074206459
+0065138464529181013506268966674037435955704351830301533242369638335168171139259359713958529701206344946001165594755646272160394
+9247709545287060822576712084519151900147438436096859182537437687606226004692040127414633767616557761740535046385163645108196795
+3057714321815816843173779617852754091940306380163712243160807705160943819438940855547343479788687898931661575785126108832716960
+9533193667848378687611829528479562728893899352573352696025950207316753012731502558223567081292045437196069989946207141541601008
+2746003049129497733856902406986044430147897422219852413496236136281848127325893646312380454532608491203709112537348345922832907
+5956088319437370932773128721138395583820924421370173711672367829016504396575639303752597289231640106298414733655039838766441635
+6180360982212734271044173784836239476693843516863507994881855803639383910953492384867775507310386199169825014966152355545690080
+3474612962133776522839849256217894365224998226219581308883384099107152737580490415337430321380267679764659802341675603080689884
+8385214883553973286697705130178868327520836907858212929553123995458539418552809580075802670275820221517432874193060009661810485
+7635870550202301972338809565930908660230248958179738819097744222123891965883613360999839391218647211336772299291193850385713932
+0223196991899819000674224598203238140866873922543961390070945675722542943959098310960399662895718004978803705167927661114684329
+1353039351866220611077365279049149758286033094828313328435837478853295648033377121231092341833142961745552118705722131187887027
+0630837254454720024736805497864487627874608261900388501662821043624883721807437900259240409899471051510920617085099514167842832
+1988240186121860008928979530309334258534723646976027619874403865209331775508112215956780097468860667994721263707215073620406836
+6148969112241707992551262221756342003961909547272415999992255159101022681539848421608837594935060720460495066842999521680449846
+3457737254497423194650056810264127963010085423288394333781451846227050135758357730754076741230565869445804248143832527389323252
+9790762908682747953438433738621860423268309500095630988326150834401786630708761812852217486714179905608190957461442085387864531
+1522476382145618120242675473759696978079648715587754580423057134915914494338656294472760447616089310947302406703031809581038470
+0171535968526973835184507085581755238300981407341777890096801351412273999921818828858705625413157216884807494772810429053662454
+8619996360469711195123911341155232797961140155492488752604043466908848244534955186766472286479836154777737654804742176595782417
+0442287907416054215425872961111123258314536732740500399960690027024024360050777203631279476105577959878524421999307563248792796
+5348313098484066077132466864776966488466415145151104355092278471837179740560502130988667962911672913331290100002597980514807384
+6973148695771873711809347394667364106588642004523762177909283034839940053425839430616152779752491636974036365528618662576277264
+7738896628379276240988497456223829719984420682404133841162697625994660783140799400756439398245883415372300490612168611754778835
+2968155785628016494964773780830380372616577140688533547628672148913272007307142811840952334174750520152544790354169079912774158
+6160810488767205184519228782587106677087830138711937806611950216229418417002136640356986986424817853470899640679854298647927259
+7389645808720792658628388654675620007991152874617887911936239398213102595897949513877377839509375811277492184373982237380291082
+1922598786894089615133138929724905768857077536113336665514173213408958842847812824030198485744051056380839435865339196791176969
+2136038443877769241444454895223211664298720250012371885167260344691881420934862218782035849576910341176642258076960704001222187
+3619101830106431706477720342582912973276053324213930842322321478885278765764844239473581443510550046154371836075105045519367692
+6632620878175338782391713943229145276164648915620343082760668528508249819030769842115080099804055533615175586509178038716739002
+6375633941128896351976814553047937414266141967344986676911841486068926852092747499580940682140408121435982416523093436110154753
+3222139045759943847229548540511800241253979460730316619733573541964096618975921352811299052448712030457862855059140594007137487
+5542934473211875603591035637674955693033630753758706551752052733350020451305012112157194134893565133530552290159364523539238466
+9616750069420348886409611437053219761816707838644591613686536212537661191394262393089971240329521480448880783267163369576343597
+7663178436164222857814082876400941903973450706396969842174499622842764650335956819817450043712545807776915977745377365681672284
+2935635454175721831517097628434415466056776136240049950596242823574086540015840252558304179235526092054789562977490616481745276
+2672225222323108279006574534254983148801337991382313626787322270855974712894468368216489102586460739019744587910470428744488347
+4456074219727400675373619105257416175699861456100136151468602175897841754789156021282927447724373220233266891662271346817093855
+1945491471112632720796456775261728821202881302996527116048267476118823402662922873934255261349533307722895013671219044843545536
+3793064262773487395195026532854447589979023796935998929027789654646824047287035198327952786992674028615601422606183219879793442
+1630579923384492024946757118026605898057464509351571155868933384841116903091820066294965297665314366667361460313869589402652652
+5439801899827848778232404947415524928188533947410081530624338414230329436826968163987544645598294181482211511249572440955572589
+9020302797433585342712570197932059030880158484733343798115491391574065623327717092645488738835390428206014044345059915068656197
+6778633319862050630189473515487955936852231827578947650626369925629640725543661083890077620427798703103241551925751730707081567
+2865799458475868282589650599779702798567688820803000453419899694057649460056145012638522245118862822941880894081107383763766480
+9848357801406244621888791600769552120182014301160477310095737436308083268418063998275870777119923015945538580745005505737103338
+7945415897343252007659617183211493332054610541474762203740026194193724624943127621999433384183901217893204226254420212426063638
+7076158492133875552332779907935346207685056687613427451355599366014714317865416656614209291512293922523145859007589727797381122
+9946333250403836274494116934757202951674758307883028448572093526467181950556672615580772027423711017988838817957391185266051907
+2671612744740733351071730789204383122286756475831821553120581637533315869945628262846596800538216358815764391197830622296989405
+6992508792590965425974849365498446258624365117468171476061738700582645427331625361075430086525639161565604855405377972628830548
+1767000101633223839049666007882398066097691088797110243675124836228262533287561681535331091157763899063838214576189418367103407
+6457110670443987985620843280548984156731527065461755656723700576735027138342545097213504695717743645364185206786138748271882473
+1596890724976137980689991632152444686110535638170408866300049744279882252913535065665891060859035882361321345023887058337830307
+3373623078064203672049256820541947607511438489025503639693977760706696248117065715718091918113311545970967574977708709494235026
+3986923221612406956343410179388036231285096894778891156497956823154793926342464675477516471934158222112337889492119504249964378
+8383359661494890362436075780531143970408529612575647080037096675346333712031003814298042719987791032534165077846901212886629083
+1031714454907840175775311491859630739967098843327841882994334085317927475102526174618259645090436553276509976956833748682136561
+9064443423702201811261101290439334315411997283217810869669829733471939988609585312109817796812433049198581074521140984709783531
+1643172980645376942250431938106354165389537074459078140489244293256765030797030616074547245248075610258161012282504441637098927
+1963449744475973480042625489273145165780544076999525577661332442838969621507452441516783367746336168024894911875794707697541031
+7478540879501049129571343735300770536436533927260315165717247241849652331693508424305277324109605811185754598081962423629189840
+6683599827684293037220931133813347833193703737280727037200969748489983084498274135581120006138983726589125846483814619896382039
+1059986341689241962791022654106008362005402932907446471177268388894146241093638783546170660638544503679877547754823916693779241
+6066567318288101759879455792419222471083652734422111018558539534478864130071102091839803023165372816119391124984955696131849946
+6509143418752724874347225367749147359005862337831645120532349014908613153135844609402649987007336422813208143055617331460906483
+3354213199998376189921305928077126664201462525396049040175801721488556837349266500704234038852235700461088952452452884233498199
+4256488814582093977539133655050527294580364706253926894156976648375809383013472871520377935537449640402956782630405195205364082
+4477841383190587477839953144802218475017581377483593956131465077901385252056389226406917609350544701283827958845981175691165035
+9675317500791142255855936241556896374576355116352110763482014692288089584642987642868701466081788634493767773533747361856594926
+1789275548140948127853887574961649444778475578058016075475638253177323030087374164983465707068923303558558151943477905316462894
+6521653020185636533316557444077296865023590390333185648729621716717902230175881569862122737390334951189041533339830180227274093
+2241738740799072036341573074248811436322223477169424669409308388622966605065590062245566692647119962939155999944641570918974529
+1928105019305194521974392400885274260434232105024551451106931113484210411868649822559924165796213171984543031754090678126105970
+7223691850432923916423525460668413682740557862272946646859452084367199412001020057846809103738751744440123325432522452656213927
+3644451389904659220831784890291126628998096321970481352017638587386823902603865110497499248782547323024785254006989249949637036
+2368125490914853885015667449603549765164883918157991257417554348691174190395500642639268158971914968315411160008374937535704060
+2009275459811984599922767470947284560232970282990047819179940733002227635796160576632463265974978503386125557611307429312063703
+5284668210801338637743489600143584813073507148578726973558859500688227447435508050513188287747750741584385175252456997688110085
+3073679804770516059033436419747376347125944073396261678398209865762812539120718854779696622769273119321506920635555831381282691
+7090364017219499874566644997354338979508197792775841533060988865177458368657219876491035282278982441665265219245626731000939486
+0475155794230569303711742143247875808031690475413279208626652350784369479556492756708347931041817323940692567675398118277710202
+5987347394026084150071478790424131834854554229261815024383846088465079695373324503305612702444122591068763896541604539174335033
+4436269510455092220918525983424623113381645210225340601560482106077382634781965165780342556554085651205866195116920957396275838
+3995168889104032757269451494854524514321628575817645123299310077893411388042092201792884422861886303896708749182469953549119697
+4535001242830034769362884028681925364864771844433940737375296944979919237869503095436572944940055711115231301447509402025904715
+1800925216578304292056694261819970660613390371844516635237968892926502845404165792819051199273212724458326926182758338001776015
+5370775490948607047730587515100674887605918594533934598837391246334643161422435117919064366778561014958058716726561922586618810
+4628995498127197780734498354535034114170874670064085395510892816542000534421254922356138052258209965701576585535292854686090278
+3177671938008077658853731628156335766651218454783739782004804667103681002183460703859644141290605438413899770795832449230476552
+3025608055188815266778993615750176656164484757488579062995887277096944086284232725973634996318024169760316516668522315338538984
+6602875499695059755336245084768806035216324561236127708770615233130804510875618781547430556541215471796577953669434492812681721
+7882550875891690926234268000498082339514970368440072348061964280285302475222074394484586936518612822244399239424272459493452968
+5181563270479719492880854609815755784042683606603220498202601700410969538595041484423412424024708099469125521786037119075251369
+1248580037503075406711823500465872772309344548541150892813671393177549861436277865197182621221456420646870403987260426109411933
+8643731351640151069976036541617610531794845092323107755413601880551863223421905943669090586959614825141812500194544006658912658
+9742463384500880801343550699245637258131793581488832729126778269174701627529245091838528797596704702724365423027345604418154777
+1491976930735419986039574314558277854162840810698202905470921161004472351694186257157283632042119485754805929863758038770286999
+8776957710513013252382046879914405882388509080000643024892306629178763000752942096488188622280178608686752194263930907107345039
+7700223390484500013939160057722983340948636861897585123716556883603506625380447610584051517968188462287828774879778811063488262
+2795184513732482674790613434841545867779716565739406351364662664736206685645328526381352909903916053024580749353932896630696063
+4740510819037498201511535054658680017511924766740460699058893969064394902765714052038187304179100787141754044221407272788215435
+0593548885409678785621622325583756109305462458590848222639139506641697602853829884986982801690179238753218240401694408881886033
+7410128478642788707381845999570686789659413433178313527394929430353749262597920022866973734073910557598880611659693295671936482
+4050137980096982959463694663632299864309583041246448456720658864445243964035849113054975666938514766051492807225377478267946248
+9230953430893702870077668677812927912187053690817849571057339797969486866950088035191626753948056471063994773880460982770051756
+3412034824969056166032815703553100561028200933063775986905919463873509475321843375830242381162225467967586471609115452917543492
+2276619135566337663226716925555717587888015126203959605452287702197704113342129180746061351411545746680564903503675372305630554
+0286134594910134037086879568380122070111392862199290853114304309332761209262076794099989915249949904726721530928297666077629849
+4661032688517145326760870540723245614758880946406315180541283633369882854109153204199703802230512566561461752474068428161370873
+9985206963338598229560272298952476210547736996017303976951734650959079279082066159408637306110242916656383381032701493580216738
+5913923322753424774114001206375448829014685918194637698592895629614872898525330558761701771138709572823367430917528581806962699
+9424883011486160624035588850742276732199499002202807230209412116053419259700106808447590894864084149744926170960405759460241951
+0111713605391910548623870259046900302961074850779853822097709685279966809633918351283533571183917553534326378996150978977861347
+1050239621857569309671883851470643478606629045329299864518009651449122046063366124913574153087650803586812245327770871382994089
+7338464051366649209011968493386794592783056535912533194525947811637756396164788969037121048254365052840678648300844862166030403
+8244368111563457237764184604100489524090599993135317160344204589670504422777317128963386304474615794833181756194674508984426359
+6271679168658661069189900053139794326069244916803991726466041535821018909664293827288937825025439753702650278433431356713529954
+5346852690092871593686894605405997962260976572140748476453131018042391268683407218753909113662935434807662980531252367452071209
+0705634605741863631683627483540085543041836023190103343436641588904884705166081263630037435630150915106908441737355700766586129
+2154922713467232816471312647563953292047715226865590918846184574044421063130666383320555928376617359704955430293171097080231031
+6735370005980738361139146789749484206639522950848455336267649778629028940168072161013843975973729190308856690607301961044761977
+9897723534911105404785432577277586147477026587182509778621368216939584671433875920453602299697242616307976245807249371547062253
+3864808728722705732544842322660134226278752025136368637744919793216576700939583871247088670783610602247097814787263304145508390
+6389663947104499816842871432275844541634180937582381422116532840275365272420061136044394514594368541860114545782560162829849217
+6461508204689611076377900958964324912439197085219708917353896453831247651446957118893020342996847989755084869372230374673491989
+8433851389135866749479827490565035784654953912616746305746664585754447284795963325019971006496729330088735987747297399102902166
+1771497470275815103247219843409878702558703790756432271114114625912471360708464566558219993340028146304118900320024587821960404
+5976617030473732204037553918438169303047012033263099608437162902327180494837554619833899125897762143660304278719895133912883606
+7761343244919347585259429796353568917054332343654064758967248953925035366120514799510920191615767532119958355777106600079597516
+3095394058128591553990850297147880385815415033833458376807751479083131186229720635268920776120415936997418185983635572280182597
+6753076258298533536576760943150454522971260918131318703703785217592559654671733288977408306810194844570204346184368392179063403
+6769837756043399718259982003405678775173052005969429887545845745194588303371446514765027612890020128811539282517812340583382742
+1145447512453860943574015365970108349103036202936884373965378227317332374230149559079576915215507294569467043944303098203606050
+8331961563901986606916925958427127071602998579210529763507751756811409645017688889813292902535048662887095342609935463489041490
+9736668802244229960622339427799905563413901438749725163782080129777353814116461004513305940715905434522181472880934497720795747
+8089231465924779558459413345521275018800849869822143818873965081853887737597561843190118386215028657051186337416427295963183576
+5419828194392698210106536176184087551774670922454148544855468554475299499312061306599825835773673050247207685913286844665654322
+2029050617375681673334265164512497368276347055093268045529145666800867914194334235145959975127160210970603920222624846997715913
+3338289728310358326423356618856438897910927180875153967318427145237491006914876971227986916804404786999082347353908985698677388
+7003592673799641258705037230618030712653838166741113566125031462959628644295056269826492276245790120809269461415827782914919523
+7933808111352753578305022191116925704616734794703884497922451694274860316351759525772713769181944674741861315056661705956786856
+8984597543198443392303548683602615735750098545443867287028649374064105213301110278127297110019939173598045760404284726471910865
+7750264118815211285409646722851047280505065647360902845736489925465867330208651476223128001763893620074546763783343802324668030
+7948487261322735741590287466404743224701011374099821413313798593806289098955840277566381979282309078179393391191764372912784048
+2031963937573607333606298955675833689352959686316425308916957187087489102352532079680910868716368077096336327451835608150057007
+8744303746009770077282182559273953960324245388355803375849588763883535017206175431068707914836359928021715134879810455899706000
+5908433402194706392948327209167569206279605516036898586828659659699407482487006764800996251885333845684403771593097852947347762
+3484375963559500648211146100726353736952008101895174614070329067925003079219669004928157370633196400836866091467437872364498774
+2081484205640426298611707106538905461885148824043568864528394387116332857339440668358439402474410629912663441714724196706517933
+3644343088909312558175950443352757850056547896271926536743829402725583986356025290388997593791573353364649376090870755738159871
+3017618967565343354488657372318982952747583634309941675726567297969538505603943497976312767045820564276791044673865996984930840
+6755211147212352533715490737391598930938409102322563339784308800982635726297552669891177376792489264858203303571448544969284885
+7207413969560628720009738274631537646543552986672220301640499255496422838738773705028096119936179105477192211718065255929107570
+3952347918324244189239309810051132796520311457058379135751168560732193370931728585607246787585935133034431471433154073599431184
+5948122133173804973271249039138486246462418117000640467153032385374427588683813496957187641107568040808210363510174360369854945
+6331834561201934486343354906308493614367011264274134644391474781936706762560771237417922164625963715633624786284367782142544668
+7058988605827353891060874777352863740110376065711990117582066617633614262447752203022541270469488891576938820572417323582324874
+7650494373012942929901692837674976301695625545739424778268284160337186164992467580080040539595408395037645199431241659430435207
+8656919176134694488026966726643058582704520649434961668466021566505602068958240292321141423966866142697100141650705135865554164
+6074242737126300341900975693876422564450176547153341379638414445501488034596312318816964962988094532520846350286682968373824742
+4534503855120241805255426868718961329975641710164649957599487128347011734954984504486944932371682996864451326051197976215900771
+6630007989276431575068445405328391722701879448701430734576747641331918162377214794008905979133776103351215776077151862759310804
+6329412106193202180915032816114091690804553056071102324935636935651606678882718350090015499101515918794964067433252126478982521
+1507488089191785086302341745012119227252927110062837567351191646939013086128950794430586208439605756178768284242079693463131834
+5134585587442274519690540303774472196006421738851673713532054649167344075465437753885506375501473079004259777595528824429150142
+0167920777588082886922742091652852786107461336681294679615598036369318540905949328746327769828031291675250740935570893774610363
+0038129096989223899832722064059115068115632289006675498997130267266081648211647293457692956590546845542631469315045748487379716
+2520900382745986244596184110700770194581607346454171538723932383294827821673322365898338493511029865949821494463508742106545267
+0565722884026288308442559359348206336146522003909225136977382087745807490609842307769964489536237904153503877870475885643050177
+2879720936866676112852941496983745298612873646677215750883429056007867869583163799946103524454641087004812983861736126233920563
+2682472400392268500328620582825275316785330033129835929951831594780666869418979561874633816166907302039950903765570878767521214
+6000673278648346135978034734234778737168645117288730828023574501322757674622590092065551189918194137651428146720102471591456653
+5327338501961495043879408610895757013526179026139024561532644668711391863557108491473051168562266679950416482721536337117909482
+5138678303997976985493577927432562758408369467781462054517017307284536794110651849922852301352432225552398279721808418546811336
+5942090618633537593070786933293193872947689557210874049534803895058142797994756021217906395785182382696435144831868446840701054
+0805866230785777399683174946303367253262058687100298157860323746012789121984620953083069679370163347105957163924550067110548159
+4041789012854867563385153833627178486269852350526357948901776390770563029842109776450416321004402898078350462398525384367774030
+2665510818821145216742821558285899523213916502258403631925403804385199376750878427488901928524046342897043307449003184422505729
+2048478041171475190266068119919204384149581828382571880806118238802367751477551342088588974943077841775978105590373879036044712
+2582550167003327483543334770578776146465326561660371559249486818965320307377862762238777770099168908851119806663382875070424505
+5444680706893164832113072218288281376031594555136022935125966599054561592735752631698479935094668438169179747421550309847079353
+7876386229779167984882703960774028877296085268097204654180082218579776041301150186998163564389835397054336008319799363495236122
+3595623959964323543031266473552625582982574960453793645874949571464306599166850005238654688725079784506108930071723727021644099
+9904805562100105780931661247162991156577135587825115134266116050943890998432158388576995701892214120245792294717827415173723116
+3198902109416772023345787207073949684308452839612518670096056433197360112721221131290963458888501686457236376124484894557704239
+1439923839664744053843985184599889045003833780920311682293838839176055898856807867213644378338290067096258257324765963896543835
+5700918940980369141639579109635400284102047501766736959067637462699617150713985354772825179670276479720622682613542577452843978
+5832673606644924997743952540484980626339060224968813632527031664879549813855034184500405400404100621140495713672255224298990414
+7192889419886464319914820529555240869091567523179106161721958129392253172606561099507740238957725006168387598704764060094854671
+3309479510962185342022955705280901753250343720767822070179996628541199963151640899372621594086084748660799272108092321615608962
+4880909425016446720046143938905942262706584339160340379312192206890240470343647456683169242925461208146677458242299921836024115
+9112782389287307875231265914118831295892615090298799256818943475243201711378213965480178556028607894090008691361256922857338305
+7878997196220126636517126620736341433150726102479409458917297307599211520723041036260833938983460239182766740060701211352201191
+8683094774314359941970056128495804368612258860699432526379799515947600345795062224586289908023772808639146020665057226162935485
+9660235891943541046373003698737146580202165968722595524291168751596799140752064994627768069683240083731174671310320210501136516
+3952299801633659008575843631974719807086212606583728034228268635353770341290150958327244666611228164923899770204672751927925499
+1681865396625682674685451758504759903079794185779114689381923935911799262023419094458049787998569136087163049641052695527707434
+7051981372339577512946597699315700689964039969082898958542940125278978182609047860935808672479205043611404976983579300374284797
+9494276685604001130980581987978951663125638076896908522150813094023439651488500315910058707670482621722763754582892271598798239
+2297480620143752383199993430862475021936852109466853279971476608874530008450195147642064323768140191491557557914372058492369456
+3210874548598055876505562103390094444210433165591830328725710043504607452200463576289609058990598342445857989436858490154233543
+8132507672542987199374049904308113523835831443354290371614453927015873910762212637250354565826616538395197156337073925141693484
+6828640682510305462478950222772217556425645114511993512248969567524785308290443499084010706135805334321921588360262285590883409
+2594395457778771868965633838538089838472114546447151674569430202509411063873470113459762471547280714167783037132473173267526307
+1601839698883476534179701757004074668031433379390884724016658551011492507080285489891017007383477491584644025888213433125759305
+7523532561560703539946099285117454732843364985652611667389407913314960693543811095755855340427962780551780192610470189512825524
+0348247544916136977309530119407469259627024645454634138436438519986158560867875479423449700625816301245511994796229708771223160
+3917296084877555076938742844381232454610347414176454495292235478841999037736204668770470759408859717947445502249268193464913498
+9942815514474689741504492308012003642347161752400872994567873248383495234578303317585084447735662421098893789187005435875125952
+7400181919019490047282686705057224403673442901199627215721287263528829739748034312624985655044437343710362758307470148179539661
+8008829134593470730958751998114225068506458584106597781009501241738039124829892755451932663527484529522803117480503191650035801
+3220127286757997144992978308357689318213671314902934383221575508818519767526663815112777913873690474000419949051472231014820267
+1399894109901863236068753449286869832068943284626949416147238270002784106062189067937811371979896380361397172738949505933506481
+4254902873234171699063619785819122642732788292824537159169433666069361612397840595910726633660384383938078177403483650975568259
+2209368179438159444309719519784098123505334554409147220881995692904711982790135929098654648473758048308424437091906340638974131
+8784927854050511928452505266509077489186830632833630361379070849447072741785156478899585449175370978549268898176795868437582718
+3231975833056135924558298656515294400028803078329218944207863428380011023399283981167261222531969361122301223500410734344217228
+0958925958615134583645559459986109673563012970906230471133763988818583110841341249599399387466204289301186261815920165156578985
+1991110694748693828675086932988793084291818416422390423728768580762059411945640551530823790024178761601499474873560699371792162
+5361696020245404957765470178767621215479647553935020898244576640893571391546565492142211775010405579641149396961911772636411704
+5933641384834122776049822258585947581244135364908556513226296636775905866481756079367435635748095205281573764949264635941006411
+5041011491795017405240846374877784042033437774313006536528316953327476960247723830386371163515353865121506304361011426783525735
+5488997063517475914229301557438267886673740763412117613628897204796477231021684048588313466034859903879245472327441120566103502
+8530760385580859337137628786690355170400764087907594224462686544107056072485919968752489909254263413225447887894153248109175652
+6157903578937685041336967794345564722166007100607239958562466608483279980200607600350161886932405833906442195659498278360919430
+9828873150674702059652960737024831945705458855872859591267757719944168191278626072224244567244295799804168245158850647976515767
+6733614592966966657616990010769041211313964384427177615958783894640954404002730067938048093833284287697173874637222402450231077
+0815239310564450548270963278380227549898803833625140660969258768879529883774142739151346026790443492061196604908528916004363340
+4528891650268490704421594911777184311417838640306057034638291330148034732863406008674812263692977851302665645685305101437279625
+3233475352967519524983898638596372885741145463145393518228460271054338502613983364910024616107499752355701791207046590492672193
+1607766030654760272868975035371747266369258074306005268123601506826295532939956628851683606599198929232644016608548496393286833
+0164998823596400554560038697981327950512161089142533974519294883428101099674224630562022297926592367086936345609705271926077768
+7913025882622995728679690258052758137385077334095212932668418477051379462440145509778953697224292738907994604706710137743620276
+5951558921066718365814901585239666946472249768608440652585316569506390348051275814890810652375791805564478189249435436637972574
+9602716095164159166038408316037910403855288603710934148506742938423062837375851102966449162297207365844156933403348477083451353
+4627498098319599205600533412615626896664838788638148524473652142820739172777284703948483540298530565794965460580139030303425684
+1565284739336025065162908150482205331120001945515224141600855715524039864305366369748820024483450351626491054274468986093516231
+5340418952181086209554963565801571626818882174630725995663438985529129315572417340527118943747399687973820656682726051844769221
+4320926831481382140838060220194555123790396897025705923345941235597539508677805522059012930976097312217637965288298799051778479
+0908830534451543414307140854781014820685341080782566962124152921948070095677549807088847640541631088209567823713325266131951427
+6110373879023562027503964302970937405830359276112650695138428936697834271328145752116000081078410010751317037848623862138058557
+8822703971093401247422493922044598594234342733457558225718617586744418222085876701060696882821515543129744401944915912235798465
+6594559520819849307838207390295967732653907650649027886332594421647601798566341345946992510422578734064164433073111139225071621
+6354737391657731503659719583497860062575481051328877369003533126272128322177145084735337788672157007937391387995919117571678161
+6945608633872227095639320829071216249131553642307083427955811490415705093929385003029105106248578633207939138356220965510578956
+8875904572434922005652897358604531384916362396100014485333372047722658292461442588088931849935109173016445065149146280103138497
+6344250852997852406467930596512109372720069308708153172074632971208643949842907827125891877283714403480777088075917332714430078
+2141088112696908575603884902935424862191062652660730968192553423838776572288261313561512545353202622522229101786236940604077536
+5420581455921312988453042096323962394005097705232943223301112814607176607418563604729931333417412031473023307632699354685035657
+4904931609893963364651740622632458671635349731291306084872673976452365611310080979515796567705432384020374827307261624382593308
+4292701172515433578998040448234672894273087795215109333668233787741983605782088266764474905796649724673659270602807201042559641
+0405892711593975173584006410022813365106426354541842020523033260675160988528765885253376470412464249071597201808795790920249321
+2969506372363457771265917606965665281965775472879910780113511573805868748553670687571273946389007257215130433994049155446244186
+9422294818781445710760638755747391659377594672815933259737267891227254986222671631563563954141355946614955207418080860505944166
+0087286626782644309557643177400304492693387991339358406695023215774476540471075851900070969889709559625262772196723374356067617
+5897279697608188221125456894430238474410213921346239465846675042270793388259552491229704041982502727376305057500585797419096572
+9629126678093091084216993559586337141715599917690951379809444249525710962700663884823083705316885810747054287541385125785199583
+7595346119985543253389563272070967517963948640714499895302628870263490256644647992172402145011433583359949875045014139097383990
+7523156213061115787711878716816595972617134587220608008483487762219572353605120083032766155082751752855610567994430397014253895
+3701919959515768374982789437891830642750960645657994589236832995980797844253496076657711645006752860088626834982056251575040225
+0979950855271929320767873941275718754278787090305240807928650242101643623835476811933436063479233606315724201732634520101994785
+8113983065740845934933526321338302277547952641828910682131706421618856976337728051411744765715349602385454916896966865817502458
+3541043147303624444017398708391616664010004834339935228226187248791543655458437287589626370079460316930365464946671005586907844
+6467142906481062672351612846421358624595986748030105764102127849419935691001942740215832120384833855662335231988116688960608695
+2788530799703761722379561161257911074841314957231380008835616333860526518888348729384930186986891972631716493196919384541563044
+9960151488910951179842583784111062968107086150565586865326760613018375413860020781154310137687104793480739369654379775885629180
+5757125618091793590015555342485911625792045336449768530669665131967481618933921507464033442861020327590807013639300157233850794
+0108561117599044904729443235325450727345789731582292014742872599813512719247096059598721914318005872025916402947088829272312140
+0248866797650825595958204057508507830807476195084664283762933417519142347075582529326241506715718869000199121666869916905668032
+8723343677864688450245361288384636252992454056026441166941292835836423200070814147349431308408145782824860695919605646719597656
+4679974361161727145100641660878503281476844268161393833161261969965276371391589006952925603728082872969549646978882403423923010
+1471039994683623569789873331804012722815466719684852070254837711074357511238693361592620597284807521864906755820794891745584020
+0746324287724173135220206601559184495263174825463472438325932765982783597938536871848298666533763661034332204209283999095134727
+8847622479138729829083277482843135313544249094572861179333595590622772221061675396437819003622647477864448706978670376179646671
+2102601933270120920559135994545418775337484717153198432612404295706149728016561442479718981277683958181059597372600330224769132
+1259053282379608711992970881977405077810774056106800273103144031624467658496517236458989974966732962924668833215016485379965273
+8337096778081104941132624055977594869352911917306275484469902456879306916808789684303864335821138065913931420528939044385046271
+4299368276599609244497481316123376963837008957992736164808101728168540138407838646916364855310221850303575133697274394091619868
+2713682765289699129061431150379322274699877403663503040025037596762253721290401208216082436415144118858632156119324419976312546
+2881609371673910343032291044465003849815028985591391451188131927898325558643746240832264615980161723347980750483187867525894824
+1267916226042826987257806754004440337824069605413162886825139485042850988829975658205470396562194892003670768255291562747373670
+9234220033570807048609309912547070817083287541492891357818324994480536846132188820055694019487542207004276192292369053562016777
+0261127578143197454905032632100124793899615216318941692486325853609952184783830755458121912666549923939667928989436426770649961
+5323045993412285553048451071174802746049476412795340271320920389475261483664749025686760199917517732942380222819936015551403774
+9891352074356975839408670998973900071675970495889358565662068888386887973659152279951010618083877084169404988201568384833942255
+3238050166229051707803832286590198074734858215255713288528844554284335600396367554775218985201346513397387400209397068796825742
+5728107211476180762511967972657147473012924183544027968479506893336809289253531374220504641466496667214723927677602095165464315
+9011192930379184487659969643233786997863887173759888022579642343995986799605176120033884333316312893660726740709366636155465721
+8537171701432226276253255188614622965933151059377811653184802609155191205285178705789524447418786231655055288040171432169049130
+2707936970837574068569629371931407362409248401030806380356720552870356587923391333211272591561747393382939386843280495661244314
+1175509422804438381892148322240590701277543376729396595323849510597370466005945680426336918977914561211300792916203174309654171
+4042805192423544654158411198004453353597731647696727421911837745446359133507547657475484034048732290037678198364742205283336338
+9337695707833044354501853716373623356235483326284612569311911355595616206369186001725088755459930335959640295675396477063274478
+5056639209721879485672408789757891131387617511313947970994081160678454602320697412448491839531065552976208944273555314142041880
+4822378866853898824086257862623541730929040197220702007762078231078349736989651940081080724932828161588263934616036801731107678
+7042616549110273896023934480613769270956663187245804271172698934235574549161064775406631472230169390486643998381840493803484843
+4432695989367708020512810012276065008453086786966931783819054126557051679306430656639833606398733688366162720200084451796967553
+5350105131227057106985599834342048762794186401151883770272342638155104883645396726235498798575148882718582404327490926780130044
+5764192533929612390344710894456047465905143834205988681215996081613514814903908502795919703880401811242594826105306055481784823
+3081736917550671392293064759141270028494719167332097201455667940386826052104961288882027240309372922868375595753000121957263246
+4989894866974583276238356566258521642610551259726323252743986766553600472233437943119765905133915493843897768279428421555764861
+6801273161353076961494549671635819940275013580673219344227796480147357333556424794612960445706828140206119824948840749240399787
+1573785648039077385334262023034272384935398204989144292167011651539471971703585283557377107933951650497678725581455181207346698
+4874698339219730333194095651462069186623435369684882832433815952523247766685863473588031370751632910706819521148264821690235129
+1745856207579350369947762735836875634021204626000569901414064309006844235664625468595115296405455194740314530759379861609679354
+1263339035301388606388533163722497011371588322482095769750979879436887231718408664779720990691297703089437248834586600555339842
+6251850491772376275294393458209471528965471290147918965218220499155230361216164967212789860144972751525815583122397986208096706
+3484214175754929920259118693783510869997218078047468018854269713219002531566539459352397848678904622285083238008575450746485192
+5035485477939887603964624838580376893177633857009639663967781579876337080786152281286836780643711497334038142643551235377859312
+5770990490009748551131841465407612077195558195928231585911499648608018583508169531801015305515399706824738442071885239921251502
+5505962701249607762425096231287734763141665342862391398728642501706701840207749211087529147723821274132607543767155647569233366
+9531752996646776228330405381959650186056935054844849148234315573131250892996644098435195362019426286916985576819912113865830014
+1606555436659451432978242703284043412347220692073799660822918397493666695089541486316957331014765996271479614514099842437809535
+0289392478723841946498232349165923942701150815142311799644394965419544149980499852640646717021478951519649059011872310248139100
+5511032978947425845575588456445816057377640214105339473284188761415785249565799756251192934762389301520020016150949209737931857
+8405804800314504366659749363367231268121943183966514746661384830649579675620136873178912503421474419998605051121952540207826204
+7505457456876976664571641545260379929258562329503538400546169325488895767917670975295980264182906923671943997046060564087753548
+1274387949977098682446892314563863257816052408410571422114222854885606494860672338931736657657635104187063013087549529686451859
+5042755850832972022663213277248439000831269961224227718932272498745376713860758630276016079020855254056636945995345396441383249
+6344700532270890968181465829707309620564725384105716449055864407328703719779390283415257182087348958918979888739066384714906447
+2478502268884223599964876320836160710993832544375139942095572555604343446400261859797019349052899588226956407340248510969084412
+2858479499626608853379284122587510516464864248784114135053508629608620108109543831989223100900685873301894882329747241764687394
+3516073975240799285196283516667224035786957693305024409405170967493899593072209653378675045399225752043351688237909816464332488
+7045960591955279992811051225021192695063962021956994060992139199430008815112575669363055918094781304106258599283195179624447775
+8303548637737456436395221856298882133107004338700669993457647426042442520873552718504789607522324772936205923889075833787877983
+4528959091848677214793256254827374251508317477836642431769535470979890535339665561280184226951752824749258073794415152803073480
+1459998553825438645486213601892946519503789985188491129629213533576249295139024141113828276369687768834808863007813942900737363
+7827507025285847290454033855290419493832906414032145098230761761828468254431382777807611448800062745765313713732689219610038574
+3538625159483449646940178756166257692080479081424585343862543469052182432934925669284445293824171233112956439604122644220734705
+8884093066755275809492142335471176239144329953772128474695403479470145379846983260079920680227191033324315471442379828977213518
+8161874018859891048210600302227335518426279312266158906257386817733776024570411483770025016852705510503728654494429243801612182
+6746947553453295308964010256393213729923189009745905892535754926116629620973613924884980514744338995975237628963272677038960017
+2316979912101253225038374374358240155041996499533280966926264100171569427093110935120513047386276224147665309331079377719563345
+5252039218101191323619349210669314090591183299132043388783600602372822313158646436097466384432429894279310347011205483804258365
+8849078102378497326534646727789474466302897639756078400720546541976326397706257168948381071970398216623030217390426497155999023
+3271457271229858454657827770335612567349224212240695221407152662225083082143775459834013524692150107287815992741275927112028076
+6697268153473360409230969649314429281006253608637773637800129431557004336600687209561833649108523766841818697796052616713524406
+1264023927267188505910887476294511895228887727108862538027310305679469919872644028196540981088809214448552558389500274219570341
+2341820289505149961074855375132511787200836031120337305514546465652487797619606591322268017233923749079200060539286691098575276
+7095345917502068750136490067362248249806291619173145831611517423916491683475780750592775740226681145459237438975249038494918255
+5854207316691383141245954956380735287065353365324788816174156724268585661703068556010195412645633774843480772404581791184447848
+5983572806554767884384691619553163176913927916522767085440008009887977162986441335924089064521714048589756802500400756006764546
+8749074908864079527865640561432569820363365495585933467014689209329639785755338623694144042638210864919006966920756182400308068
+1488418928276481402385931315882264463640479342727038934158474806015143604448429971536086762337574137961555181782018130291223711
+7647631250366260770657650732694263292505761395977741171841175592881623563088242488954360090722844918014816525013438918815206919
+1155451667283610662459850201212152183408308503418856279359708202057227744768180593554527508439246428232801124311275672977637096
+3703563826897681685685127020250312031591544945988953353941140195645214477592978106315927871524898358121653801020581142274555566
+0502532594831295067422782714984502485832073390165137849670240378837997996971720348493993863606290066187249274244662460276318689
+0152755194697776938435286119441290637386200629628199446127743622173851669645911455169432495002024405765718643210153464143701889
+2562249212763374000591086405147643148598332714850654045728093130807693494090674026473297812238167578278207216049055667059931109
+1802942091998951751764726262310843905210614073350123667768202638105831131108058708767584753018377136585264570210097378501497188
+9619747156993809984322106521027559385156110152742577368251988283361064503255508785410345421538190771023025825991060075397692057
+7975279398046115700291300736456549463218759811012712333893946746580558137896237287869240420636891089058025806023431754219781359
+4988421426405962855719392598321200928497349040850013918965781094541442225330283536616202634976088463128589329235150833173556905
+8706200507172140856416642848813849966143817717503023224834106896623433469273328907429832511563972309658830234487588093651045739
+1804318877742597644565913208808319750885352430439083436497378247283858616368363127977363367800390625897013789449450637875537399
+6640589174553589654051256599633381120024749952650719727219130629373315456037578535279963334633963259335915488696463449646684320
+8032272830450718870582856393550555068150335019058461099968557096935808325051772579016403379075019846185741776197086257884683319
+9863845517847573376326098832507232200317675290516210661300649571154879306959674077908278504743343209243187243262639791806186829
+8260961262731301702271912238265956345814430445731867024044874570864287595912998480366912356847572447005441275362156399624494941
+9393142035376317879394642824057024278760474627041377093083443136837548371844421180440200277690935722486852916560800667873141543
+2707649253179074679795746660619684282278565191941032558500021642302377918384225264159606437430918854686420568233535916210590247
+3653446714468860199818770176822269463628134871277975181151133360475139855607198727163601307481114241837610243765527921963130342
+7740886414228885927181817969815506430494309276878003524396743847692333838266397442280441863182363662933711077420022986422070281
+1048387053761801939044385077721021658809540040018134673396554017098633248966461113346771441179046101247543088625644697892282167
+8354720955462557218106068480057094392968433715936618376234382444557134795213907950353329761280756136821666440990155365084581402
+3688937719186699342108738462217437423679733279917547383863629404136782590007047571508080094271518356483515978166149181632884691
+9910698753207335191315666777695731726998145344199523600464027456153460564479006998462380767579651598842317204792886070420998182
+9896983218119310999564732404427002821382477892511011450905458994448002735795600011464506066851494867367124445888153203962666112
+0874480478255387464724872537442210377291532518746867402289144019512477208223281547993390653821697806118478800205575150577662857
+4918888004811316598554705337363884151483714153627256672377291874950758530975380513235648385297027498654040181963476939202925535
+2944953053399838723025577285199841577289179795119166022276762443360574684698180143394617215098184693212410119796009072687729739
+9732016373361334253176297777291060712041712200359193577310902701783613655008446771602140682798342306314527926659629849329119883
+6451043591004466592393679872228794008130850294984708968342075888842891418002758594861642712850414025146690654543853793479725972
+3268929657246764345075224814644064768187234583627518324258659649632755014931180023989253455291331973610627056888949488127145955
+4261926089033087120812284628614836440477048559583788705295941729615760122728002946792084729956587080892613331345225489314812847
+1986796721026437522158295162217239471552249715846680613750709615232262912940447904521346670150883469709041492285328187488804299
+6628012528405245613161440847234508491425287943434287101928325272535635664307751412665147263964282878231211570769131706300759265
+7377088066364420743764402212273540338705138073396342307947494852950818207406971919647576428347904811456431944019834650692515506
+4705138654618320095006319217530505261916581737627651424491878629844356338877632449493703212698711863106207638016952512058495841
+3297864919576913522726817303334406976314952205292550373391722910736512885151802773872849953849211298237482028668331950499038336
+8974669281536290012748118151506739167431258730634523888446083432703773451432089051580445107667501300580071396777438663916505890
+6676388335245038478835892287014370527286751599266433016127479958260673956274510190770236842963946164980795747343439314929899367
+9777763357901635768971296015139054097237772494695148781717193551641896481882800982585569826367439263979611639005318235314749057
+2006174408272512048656262525906502452313110102817338015892638328650570498699472308145823254807565718645774486952361348150134146
+8820513608849516349458467726176340280776183307750894733331062785346417632047203675211923303269854905166452369376623717371465515
+0487090344893360730368974812186113379856699749061983876927406730979994152222167896194935782650684486995334925005887216364226178
+4428212757677682587368912604936275746129828292671231661463255473216528603314371364809318568990891647756504476074694167225494387
+6438298664776502895176225722692218937876815974395529173364685280466577427859435428997212680686584089016477667080112002827762955
+5372837358048305432426520203755641518748461432567909426155727245524828496289926253694681592910381964428484012886894327170000564
+0966786693488185832806410657062413915673905612790978639242251067404941406079608751238017548545457392976940768385484687626020964
+7081334569477079676309855956739406608641536536529136201573794386634730088085065014162237881535086131012737674806790302926845508
+3849506256608406770319555639552727023819412680964197246748248202159679944624779483651489821124252171233790787024388338169387126
+1220350189747959004534763654451835109235619957413590127042747161319131890755258681890420398880573552502186079819673130304226319
+7793578559294710797103985830517016163667215076322029333261233893714376644214340079810529332625249572639110330515277641165833848
+3375779071080037456833323971305312807921291040172365572121296035080033198190386403786992644365488916964829938879099337521148544
+2151885079681150752124200634430960212055491111062153428630936693865872096334814997531820067268121582290646921550422149642030109
+8613181778258533141158145972750085504588401393903967265445772834337987637418600396630528732934239316047591685154760079805548066
+6810794208813864500809678470319323448087878028803605043954670396669190693495990898866714597544374154361810960387728955757997027
+3780694542345726440651447280692129044592214402723296549397501233597057657590741164054767713089063618201384926245188297986421050
+8252358803202927045538322743598848427122577241918805031148056119515867274399187693181758263084888023518690338982779085780404769
+2424326538477152923084594002081423911440158206786241827087394911592939363042513317947630468078474296989628062484584400644343448
+6293560419015354447114147053377323271370974957505862615433195073799026219744354293045028357502721448147460831465672262899873109
+7387532795839583928982541818961799651808690944192536299119649406867938059084796080728700163640618737891537102681397327040310310
+8646371766907348023824656340748360066056892200614557523317897955392332090329097835097131487719957799594533173582638863081864212
+4986100049536290446290958993632891990045407747006838784207732735249166707023914891375926737812449203630774188546578985599909811
+1084402346707970131458723746814930784514195757804466199671002857316090262762516878154322011683754629425143857675752082486603247
+8761838577711280264766083372187992430863964477324546898292032760669740251929185543394862067810777754782525582117312630882437464
+0771509220114585291617227270613376384799093204219724418023916278133523270037263368542243169870229505561283586085433377009674011
+9820385787390786107677870809083528732710164474423943477332838364565199183957564959608617849089060421328797474250989472544417321
+7919326323563029775076417955118634250595776343877190502902725431786697484594693383405493496141691115991728752796848704617855725
+2558255581109821405634179872876958166347174474348761073684217931689004048682704410888017280103004988712033725528911209075578017
+9160863221896162516421424469589930231499714756713528296148018288586763465400454214603217797926981201646940396481239125062147650
+9840316514604720267572846195066141632646978531870664811024154364403354983561787177052598257504070314131100093324913554509718449
+9311775701841172266095504345180054522901312438857477399185382790126084433098439433269362739881218978298243657480689874068996355
+3022781945908762278768811002699224365141074026805076790548873962428543441756247033480754889441799694147133688175673557083134054
+5661203741867036406194178717036861247199166773801082533375613708479585773697108277538910907988050442661518792070910621436071059
+0690138478379736786396005725249615711997663990048585261495921831819669914145515073403200894318211855461357229650824823305525133
+1751585791160648049215935161043755494836647727651069321059714784747155745680573976254930604344088093264307898664770655705644210
+7624145261014687805152488774841289678583856425221410365164555890159519557132962343799732888357700797774204345288024762788982261
+7890710552868121263477187455194185399264846143513087916598365744278210315488246993448630198352186843484020444533061474327432896
+8206909625120146564482691781469049022430111838502858582644125909195387775957182358764356323550045553074686821737193044914677910
+8204337650424296695493149708468179951960014630538528111508141341188662936175939750414398867506644825258652647525390439239752201
+1219359010151342200692679606063626284788399861632782010310804100495631217242235430375489322644648855854345633079496117764048987
+6653697464408607985860924202927606340854610960203650555980002938739009437996650927711204711526682854187368829518663287620378635
+9615765538591556297112167827891749863300345638363300995749126057833117511099109253123549891887992882557489784541036449471882403
+5919028352049694001658038819829671235731815415745829048231249060308117257367536285634944658365311943856716917740139982945041953
+5779687741861700152585779009366027675558545586949850924189709461217199740749305528005166461978008407813915390937008493360553115
+5834977903061566139099870190655547716966444068581774636647968617674813198281268006404303675453751976888820043577600761967333881
+6972326585063978838443446520453713997506879344217941897803906052743968972254016142258731934881056702957790715642228115030783951
+1362425902796546798395679404782769752464205460307818179674687205006891103510168328363308032810297518997174255427908231022445396
+1509825900031470252867573280977984303757520410764668672441796612789584482854046983756780462029600563288455226754517497700564660
+7759844224301976256343546717305935453950775711909213261546888518009701479912670689049983757648821113680742909226880646315005569
+8295567234561669944338275143058695909726066802894545455268764288094686590468443329734647916141835949923568889966174907115365925
+8847804451408263609187211738763773284048172606546780028907522556324927271519705281526806470352840988271648499699486513703844773
+6679160425612818347335886820513491773906491628651444000288856405322740614920289642723221399498209432232637228104522990852837747
+4111012689294616788593607591102956684483592350971102538317426326909441395344097833084048144520705500574792401000355907792380226
+8347617047251388711302856164567942061715329050448779661635598992241168749527006373179435024773116055832951174916423963970112173
+9055087726497472517559694026453105136312139238988721622285684818285622456138820844308772825216777711338810456475617988242424162
+4197863232696784218000746661193362219301917851338032677667264033511098062281872897803087758355321546501532794013889570222549856
+6115749894285255554690322957000949336927917916709996337643587065466062558943015944180187981070089004992789679317730749848395116
+4787717685054333694149897473720745326568218218182852236278365043324649884567032268831086174748464582606382556519285049880278120
+3971535819215057024510844131306800637142690099398881617684362973207491682213220003762765264571054110883901103595485168757504333
+3733461701846483183011223494998710865469936261566419212369452729547931045469934427223536598514620405179798084202385746863975487
+6787515125117652836269017536232648894348703796120091034388135038967463209181552965632410604353037772756879239864709539921500366
+6197228209653401639582453147092770443022867307115583008238408014093437109999520308757528533277994723967340185717046004119026260
+0327403058251198538854684801262565688227840370906858688450070334229654311591524491257725374686504434311374381373826709761897189
+6320800720313217016667089641041343357180293991403820786439200978809209918586099663595021544518755767970175732723433500537775215
+8586605557740559261081287090127076957830333678084994220662406403052293892606977228772765289631860524156764537528844813070064403
+8457029064238615286786107279460798384585105993306593540395560420933072225512825677840166549704827482169925869109982598418898944
+0346460363516674840943211123653705144516811133167773396076974206411386351987012791478690845256647926914987854519697980693850902
+4071039292859550793054081697582930309815712485519665021072773643984757349601035844973218854642152867868823320985485836576692696
+3566944195916064023455915853671413519744116499257428302391059795726588226281448949481887857567458305547585518788070366283222643
+4475630384874509141748841479483575783195093285020751153893790442309506156006253308563119939383816229293457633418322795791651798
+2534236711768923060748330398823973796625511107263972895904532310389295669901143468746002992855700338033513519817927059960082258
+3266833442506157497412341209730995861476441931081314990884968759007025722755350805078872002993770048685210269397083340942969079
+3325013293836474893127556216824859727670678446693115589979109778870903809827936806876988266059842178470200459657153466761585276
+9339215768239697841992780261560272323641382940735693971437349481277136632058838727826902049882698280374121176916226254815769890
+0579266322319718076679029381516879866920214093645961826097287139995438556892638562807533592029177968784950961959651824138364712
+6905593271581094882293836027956049322801541013654133342099776388830151131142904625837046121178740403372359293970069573073460036
+1334657560229091661514767192486484034874814804158436588838115645203542626667263606421481459341052191296393864355597357106139612
+8983996484498008491962652081920903788269022697096829121085293173454864230335343930546161539206227982332409686050424799265682960
+5979943191308039044837616371196377606973368879788064283861010090419804092295381096855027541458106648574572073809903498794247525
+5748223869403535883463902896159174890497470441638233019825678773597770107171367867175754297335334571074534607008535043181405194
+8795353535341345876592035589428503364517129250540037247550521782811791666374510791517112671288737422099652323046937343991337828
+1845836116381331085732349956975527066319503790930145646064646988078457512408200058689118375881261700543344729871472397774510391
+9908840174753246368222566017712326787176851291551010131314349894185604484963390215007002796394968662213178018411586445058609354
+3648708782366479438386590662421575557958786432758515733410030956830742717789884410593667200352894830011183921069426063462365103
+0863636445701114598272155058937842933641739192649108654968863927721554489981493578009581287965498827240184001075889430327826948
+4493294744917241293353606762738125798775389304371272784848161045309965481110981617696456977856845295663146310544856961560395701
+5828350063875380289041787243953420472517640405923728557572182762701021146981223831971084235740009591348792854248246191617472390
+8142911427486019533916938360973756294199899650632305767565787069658787674361642673323286198646595884519076147156672045347769575
+6919034458315451231488534732525157456948587079445950850088410378838535977516348080551775162637211781455681436512037018188409356
+4896222628077283599302550538329307529265839416312577475209070966536398530653252477467412899117369638571925172776374288534229909
+2854126939661606237890723618332733028245947026454912620083338662672080884075389624244778233027185136679702658181696482687520771
+5486768970237811447646114465006645965128132304833174901323446834886512598955526763233636026886751282286763353050412483339880879
+9146149867375327619762240148102487012789152939324347118132416925423213349620444217738724989375651879154078406666532230695010261
+6432289704281535683765846177747137478857199113830933135896448323481180075359182281747819927805855289891296771338965010648932514
+3498778884149977137993362603088225708342761654666600988476000304267323094698652989046529561743798096047380169014973930605911712
+1555513950736376520645091335370846495268353191373549111643901821633347913274787967705297774512956543219272395543943905097818713
+9824515005207942672277682844175672734608049189360837751069564229080983682875340351162730595292836110710458156809584248318311829
+8644392801319979903321539224060850887494189887888933968978507838319574610389051812420770840579282228222004146980291262806411960
+7170669714045362254284955377287230002812263383500586848752066007279901210618595185664394253569437180949208007446172620486446640
+1197418824383226696240145317846075038217263309407432715400718235690780656588433075117078422196797078588171900080472556706089444
+6058081175983404316870378185108517992309376387807189465675421456144616633676191879370638648087281836756096354696164358804958793
+7175300097350528879964995120589418404250514397730435804307880003642423238815219743208925752113332762492815676234753855313749687
+2216821005143022212418811965038884804162533171952178272981773050431225972337066809470007006624527746167477143326209744916009321
+2874879795494394023670916234680048368860577149936343642623399857065876920729230526286990908222249218870734087284012928821855198
+4892669237695278094261059350844729450055740052868656916863083244548039117228735586420221099748057054754127348342899320517500476
+4913533064284953905878883623486045020791418669162484614426142342087782118817607434327885376004285685360966673400518425200903095
+5236853047264130432207807874987854720636307899392809936830966680235406253508899133299685304059306299982669510153104336419138281
+2635729217127660380760950574877790788724558832203965184259818062945607402185371541729168619518031385767332811305256686570812707
+2508693777459660048221434065348386546516873503781056818039736884680690592725066422073878336659156014383855199604525567079024098
+2527847075125720859307217125972603526269724367871881994978039745425984811500976939283305909268477371136914408464862183620857832
+0690848798245605847434249059051242459537031098176625887386313497201621005955291382938621297556760277294613833001841927601417783
+7028637829951952641999762601338035213911204478792655772152455046625599760300329777350980475951284319951538433620056110253564781
+6305383937871208842219397097772665248616270756493102017303010524320362272253687689906320569651514870191751716750048983549016387
+2503753802832702119325330648883246982515086513140942076923304514033686102637700160768687271319427097046984664384031053585769263
+8859227992404387206024381418823288245956367455432601449940099288001162654396819305512052575309088805570615034227083337938687529
+4650804026596773751781171691707686499798853858855531297662807643678150070418762900082986264876734988853277036828880591174772676
+9388499761915323706082278918760363181675840316081077581226482199990184463308418161663917171550066696858396843063924348798640785
+1339519437101345180144205804260788988338143185013195486237509665528555982435461459049630103016492555659996037806521222234571639
+4775406178328515482958996000719481194780201067828314313954411507309766697327602402398592936844052573242705274081653994583193860
+3528381321380368083594961454997422094241837847317957074543832643804670074418168234251527826193469648447514505161752970468032251
+5644398364843284455563221983222109730803753471463129763873997470655511240512635865533704491564823907699160432034740568090163512
+2019394829622861074339274739867648100223183661088275367604560854273519173101761322314118755022999112270121442893766921444175618
+1024961245677370458394203192048216519899540056189972652416007572725591801341729111029393594712226889998156435621046992279746041
+0271013842729391960551828591764938026380238772791709945105208575380084459912538928688891874547881085895537996185248760341022722
+6443644163751965239785936903668129878996022934136734635016147841655906985263150160687560568016130320940069489352717984945617017
+3980979401244807308375088961101007696165282732048547089807678715095196311609438432458589671418362252711116197050123998645160718
+5029882228039159089170628100687054725011048437854579104323727026278151658455314659996721845525056734089399419451901797673293081
+6285409273407838783004808714400055644398911907669583936293776767386307697838130877184976183405711337976463042849151509723365986
+3789116449777854153143327216807443418065067164460291516731014023725079965308205893342647719238044202553135045734641879985943779
+8298817649314977181973643591691453651364965447794449764965615478663842601481733390271221156996231579991946480360911957202482419
+9923477919534528913583979154285960230181626227828624997322864558028580882337999440750509388244247586570466385544276236851986673
+6266991152224272268084343794242067444247144028060688211987908624847699372423422643841707689624467016900013832905272766427426840
+1355067343839251713050029297274635544953158759007585898844352763675665452680269506694090597773786276467200134181329183129591894
+1203185079814519449730972616794089846681228932967991544425024262788862162483806670387321965112895932667954720701857303315356633
+3010223406691406448732071777784917670640450961064883921707223591238303897553076936064137492313930301276184114003498965768546700
+5055662053584872171686392213754554115803665951484341184481678793730256377197108916198950525496472627926989148952673813222574403
+9135301836957832126464142557708338619444651703425091454666943559384577035607172295502116858050756179608799326777436914985064677
+7849895476822416074994849352092796372963487124157171056152173017480389097568380804863683908585558640345480249639539155208814003
+9261731284405809837137712563712141454654064296465941789875748814378776568326711784539691121352690345339673695586510989770974288
+9504548640513288992288616894826847158596027709105403654435535528958145029279713253496007210603612311147571118952157286120765811
+3172019293671644099810154685400878900781863310226630973663196219151877477083273521217193649999031944551410361083160211498456657
+4584835039206895266033291139088493090671186991332152100943013968139485825629047583367832339953098893263224674847060194281239454
+0086703131238762939716791409510475698044261061184491246815071586146930458568320808697308895974335329174951890370629879266697586
+4531479959438670471013925537723663881523195629756820131576957595320119441034946472734403049979337927590688920672812290238838992
+4555784600301091463114748695085394421438230893318590726172334093673394223159678897396878630225087240466235943323892469006400425
+3181295825258212728965331361945064921751996326740368121061708410146864334211196041567878993280564094949434554682791503673171658
+0842856419453623298809261289857239402872945556557159985688775020115214582384781860334689651493902766220136835999359515682473907
+9925790212755349035787540271290598847673187935010889467948737594198142964082798741209190025028872359505393133888993203341623719
+6881035084279659821037463368291359288972809796102439700962259394869871767171237148065599497261891353342041591198086826562479936
+3071229176011336182119446125694433597177517266017496957596892485297788477134388949109492032269677674633006492819820954408939636
+2158505696670981583492100994722239785061126885782859457540392078035784726890160616966602169759722004423370966068470851220475055
+1608442432121043588281125489656099832629914426535320512741673998725277196703980523715247319219104260826637474643734228192860916
+4370675331345005605018147797477139808981239675873728794694700612511771169428567641131258023552337644203474230406734637422278712
+0072859216860622480346667080043679784914202926542586524758456470894276035984569755855670540260788837234221463158700441389231519
+5908942320852274627106540557811105888610228644494103402263750822407154871367868699882023311506835501899157241704189414346964284
+1936077419723541310264634055462791796583876957815065743467706393867078774982042343936087382789908364464848533080889495741496533
+7254584486083999860932338903788745031776193198150907253247533783144266741445178920158676792459480942978555519260352341102863868
+2324388659990555102109355727630603564463003730580206681960957998377155433799099008210231393030776738444219722412702108302468947
+9926613338642730749665937063588945780266089547872794933113744630542358661411190558266352099886620858549171525338223571617167711
+8986318093141580580876428982707764579287478469073583981696234648037808185140269756651566921560785874161230201920488349770275568
+1902800771331526181562098287158829944843731017880219524960324079005886150803168559590390474829249427791824941894802034999528722
+3088584384403360990907891602519470935005839028378253171884990772710302832296914348751708792698002306050160936562533914379396209
+1408310312115069530150233048818331378284637723150482392301602795737916335332815872089409379843010863320155338585218615794879180
+9677693345069319403701934383954872660888681515065440356051840106884171038792426226463129841417745680354406721408968771559961954
+4557539513449236642758101806291205473048350296831633561735117237579593752211878576489139742035316348287283326781007355249045447
+0883189604094854361797387824593448971971447378881204753543909216846733915206018358578418844775503490330084862478510316277108659
+4392550432502243314906975265564518025479113098902169136391369512817565837562370156090165943691065253900876426946219189578736203
+8435865573452195078786548417341611434423772217538030617156223901185493595765324312422048299670372764076523094427788078350076588
+8758192779916285126332006796232045283091922027709795938540004604312898200544114013208612412744965934919541932903174519980041254
+1905758872835083202758499042134848212716811095613617523820839042848090697442064092232729193928479222578050789364469898951584433
+2042272602260087723772848808702134767220173723358646135775389214656797340171301999623954978758165595263461874252751080813852370
+6274949154731112794816216220066048303875986872572001517499070940234617966182507743418989487331756345308613913050407521686762445
+6252730979488500452149052167583298496816203113490366754560247487872848255355376484138619549701240217905711665471993273764649239
+2281622687072260169420599936083131206454896277499378500769391609676460024680767553958496006032193910593446808391535507538458599
+2191010913898494379461759294973512837440625801801770581499807998348601134363013493664904191350527640096566620000395093356134597
+1660938804470213933500623938584649317535645503810385086838104030744441292813013981381095457570526776722828297499568794267530527
+0049591878181449823254506571309609592366697654558586847111232650386057621118329999460228856081046031697258812551653592183584022
+6258688415014551491572224840400910043380364244249549379338382107530054462860121947719561782286604468083436850199239844591653106
+2286199429292183729722721966817924988059655688863458946473056847154314312282407066615331874808857982581754086039286737461422747
+9602373046472185399409121350660074121130363291629972502459350277036971026440212505022927430609191673069989761094096992091670991
+7527879946650183351260678785085159093046180958175365176059942440628342275638429735328061936632746613485734744234236065653841137
+0853905941635849403951594887838110573652181835969202362039487221504242797299698627659839204874816529447544114385531980406666739
+8062623009337523311886378539061039298966733017052114071143987228104904834551295397466673191503750551657795489921304516776700376
+9007862096833941572335165844081198462047136819292917564132567522715598859947138927117299956642745110763969251319858190814717852
+8138958664951405431541453825461330550794221363483549976099721937150607149588852431715285804748382531904426919820630714135461983
+2082397885435139903190314072146037819079478576247984221600827812796545457214101194496220097049368103574832514769701472385466387
+6896832416290927778053721602166743175733725992261187904101998561355457754417056692268681305083190893002118259512241765998122185
+2636968504609327449982531058224266443456972154252698660084884189652857349507395676672582020179531698016039374573532855093674020
+1136026577034357822803043248989730467073666295507784903395493121839773911132783532427651934810756742564183961335402101819870313
+4917099632663820977131969667158301701831087873930909603855469814730542409624643679930249460380846245995843352815176947927777445
+7319944731827475004706218777611396753968431393783636860295774463198452128755272715443101250558014321901313052738593050746571261
+1707391395815003284391913583753339859531852184651610466904418403752429242924142601415582143805388089376849781779454300111958363
+9869108151029888337540428241180238714963181644033868424652184814249832670934245802862990793758097055499023243559198701686575666
+0187337650771748598070996214382876748717075026419386245187486192182726086987036097255846930650043060886509574171932845313409481
+6310275245723435456702127325230222604362757109683102954203602714184216564293906952316506569915992137104170152492029578927512300
+2305363922251604346990506838961419388192179030700159072409204210540634525740072656419492493606787180195424067534096459265589672
+9014680664163948601215499948895470475969838465633327315676059364457476028555130517706511356929094761498786703750352514595140558
+9277484889618105650227338993928615130344847104186489285414725102606461111639517477747291575877009412511989063198428666104065406
+5967555124952181729420151522869271680843682059283488086279627160865021360567069797183031645357984651583784813809428355166017913
+3607122306789653495447270140672966362274565501229973599229667563911606772081598572491953192767189192005766778789005815828610262
+2082222249317420567583150769393704141643717042001944511315146960110297197944325284159980684280693676403148609684883994123930097
+8731372124960991940185405379357412214932260280623846110357067671501251533776628907031655983387403452673941318358548346602760124
+1976021347697640428375581819297827333264016242688348297392388997119461967525771833238891591593742490277240125530759579876491077
+6072466888350935400785328899402008544459154165636826625026958037650740601926412225205263947146298128779293383020953022202454362
+8044034560774166401511114766914479073842481064943729623980836043134237110449322364783254518711575480004977127696613076710220521
+0564017571074921724777748862479718313010297525498781712387929033234996773668361156592993020275412793744070740135811199115493778
+8419964042103133610587792208097044601548949029168486670192222439144702607241592021192461521821947279760550828661220709620486303
+1088814982734131440185884327578226836944316287501836068430921447613687229952034388566585290882851495307655765844223170274340586
+9005799435401477659962899657617685769970912656575731463413483835844226203192655446200112583102919467583122082891247399200176783
+1851901588702515045318382295536798092875597244431065042731697266394552848998020859370638943554279437980607960337319274852691748
+4157648096188098267490705839256314766006302678665206847589272557754575914579199683296869793220703658904894112352768597742132369
+8723572441033421822131850984144065793127526826673880856427241209325971643349588168485181604003549286943794523645867631822180512
+9961788999122788832400015923298335447164102572685865228181427272076170219015236471640964326542574283167180040163937092128142732
+4937228274511747775697611764578391450794749466871545726021901964860582325608076362650424934625277209649989981489750831225970741
+5984541310271980053712817247539372152339967892775462123252335196274653874061592183413734875908267266920758029830479031847869228
+3871371830143074933411065987051697909188835376373962685096571028998970101211924718499411402849248202339306457377199877126871389
+0586547099952007576979285722825771295071780721616176263387445055392095793671230602073249233658371312728279604207471382798903479
+8923577166944872998618492077791653391106848257807366227129544881151900203904339062941439729248722161475876280041042987870134297
+6237224656556330445619379055992474217471454724969182529987949872722998015945413515067495314489889032179791415649686011073157477
+3003735334796840694489912665109880649358659073702150516968523096869480344821929684468744926264579118587187974938771984262183130
+9005753590334142936036827167253181517255166676962390793299722321456204920350620126047032582007457817410580787154332130609567063
+6768747081081207028623866855036005032042045118427663709885224327750939144410815093506371403873404919815687844934325487062884410
+9939375834444884922802271908890569123942112471025359287053666892829043053920922878243233005965596366467035614279935114942794959
+4228677728256796231027207112191813165638914358249269082781564785198933238543379292199026489661901488181239514397059686005148486
+9858539705692720243176916548886314393535919032096542151105543882501065636878211469917818253828853172821658378951042353768012326
+4422150194025015880156761058170304509425792379790006321176948407538912546088068547813798000277530779888405928477531694464231990
+9405650213736879289008838391184069127301195712710013925801226563743554996233482554161918019454022970208565224871459380574639835
+9130794172100568378934252595907690555743933712658951585006391044055921485334952756122241280828770097902109351842319381201019204
+5387985013440379266230518099534711152536460959269911655397255034626367231069408969413762813968064236154692333107664286960252886
+0837118680763800551465069959598175835527467398611671504215567143391659195926190188250898459493898805547983688580472819756799921
+3903220661160023222988830014776994424185300024466935537043911148899196047568212527843430862631973366330579525805431481011727438
+6908486037368642919233388174527626955887348839535505480142124695672332446751550909649591921180619995217291566458925431968029596
+5922782959375057616516378703156580986104482212435661177276107010237081047649806919032851751263569965116169589560831643100864715
+9530369870366296156375956282332841862206458152569867266578623568655520592049072587837930649946891321926334502571392866551701600
+2244120737959672078726164762991283327806243441107419508409939471693616693409630730506528517088302223393878360169050233927904848
+1173648771365582895309968552846929556758030253414605906336548466169612035971381029462786542081116525705113252983939162686385109
+3234155840835288921699357747660762996672264982174457829675917923339715647526557875639742064383339589189545825487931401530995501
+6887665436803180794927923177816956708553785264323074693008344374916559316617894764427215802134641031792988573701240438184249750
+3839539179042881405914564139952865952209303008409731497507386952470654995467985010268759732897359668659271914262252626200604099
+3901076984640950131960333781644223983532267536121313347358475229440208418673453842347657506344090138736051557656821297434982077
+1623302641135870181311409682200177224901019997404700215147219379739297672524540935209651730504196225871915072497095486880839456
+8525315354478812852093356397223120386907828133392270722811606375757983394361481913342296750609970915686272616757634461450159831
+1758237483830901977324883248068822612744747099358422855339260889327800667524049577373525949059825015390160043063670312221072626
+0817646239152869131112173902854770980862701701464607169211772950069653293230684510278012053087035337608494974396015461535406222
+8646346589715796030816122730522353992998487085588488148264344066530587174128544229529685414458831257128748560990578804587360715
+4892783957104711928531643465336739867007712821809759300577073458900066680389265377353301997705565938884080611069388312576416304
+2814927389151100129042633757615682635990656949553591616128856450443418496471442467646240189440950521511107482659253501599167684
+6135116334119022986012296077975055833220297155080260438551907096128989879928867449175546615606752828933549694825257606317586967
+7016532424149169529714586507287588315821039767281860867212525388739062009398857291177966375322314074508942295009826535646980545
+1130704846522761465358987904002837038112315864342341500267273512280490182439691698104185495677754466174462509539951393350430049
+6239545452060864474289817540605900770875649791603624701849860428246844860967392240963173839859434643202570338001444647069601535
+2892256768296868079082781775690843873409200886346998104928582896183217369070621962623861890767458984640863725872163427837396161
+1015987233236680540127175130575507867333440719260832000405122222181144252353002520085749044160442813319007733231316952017735844
+9207122991749764391450668652103974356514593013095625877412964336676292277200308352297929615022995501002585354045748416214004090
+5010570807508645991981283973843421015013551379801238469792061968346208698033924105198332080219826873915414042770997813678587105
+7079764317445013461353198084076807018884451655619023138435629015461147032511308684817994462582990789356614515379970417351047112
+9725881506883451817378068264565401988152381111185798791532824098438029254469346518084626414715068349480830207550031462251028658
+1504691090829009028694497048664643697386279163491642380984787314683252474807267403308118309227599112336474348292331546087385709
+8374045238326514850352601439525770150385106432876360117179641265901618172845807500617241643296725102357385086749024223414320695
+8751924711372854963768655608131773099674117966941670496696797649406607434691461307943445287152706412809962107879642575743136123
+0303974873561466480968743445273196900705427451656962370162651211903195479518829395352847623644931113876694882674530035776397562
+7062275706646629882491960277069009716984996924439240397590784333436313250958554553224460478301293892351431447612983420608299779
+4021998564670601304459878729468539224393130081394097452696802435298562203672631426231047502881058781296871522825905804208338252
+6603870763394362689777694406864771464497251023441752146535341971346977029094361489321326128197028616266687437237475295317363781
+9156020188117437220553660891624641158468448699614504995148457693527457205903178159270764484168386506020072977552224361333700137
+6800793585132251294965485406539737210356860431874461572263005112556102550605119443415354337340356018964066943951864924412299915
+9176918467253843792621229869758475550809947953676328982327607776920014653501974832672677357939313552991103607402118582223524673
+9686597280549256712036750220654564584483912204263497709158167656617008449221355316543489486938189978195357412962551710086697028
+0388429487175354035020158054103632924527177834523214082900849111108930893956355794346651605160826522047668675831813135358949190
+4345101694469873179969332042811556018423606297108948984557961826035019597070396285751114257989897953296299318364378614357933290
+4949793892609892089229851776026934561460317731511255552266868980253783700717106802153694611663582999276204920297363252094371934
+3674663375108601609896202396621130718019413744942494222052103933540452779973933501106619925311069127219850907767043719608829470
+2702622493254040904859153876396184987380395898007693621320399251663876437827374821903867019473977298529862021085159803043642262
+7628804430192406674682789691745692230306369379190920544277057351743344722619473702262372514469670378356778783948762245486971339
+0209360041654178829792127599208780855624409037374530019447406585398770659754872987726192651460619482209256452092276066423476738
+4709783672042319775995641852494077105915433063897114034300326610462577068371066683331006070063551265931785531029670403665686700
+4587667003896460717120912220270889981167563292172474600789871114756272885374551741764032376074283701965139574996577462686971467
+3848976224442081690472022609003207496720929495444016043645809920259850317579964113261377231461428538754038582648249855596427337
+6172335672098748490848298205075949543310509985651798361629655073050078700179132155025462638010290501496311312192593367695422649
+5726384573393389957861087954363684393648224844030047057212547523809090733733447320925926719918185564312722906061784825834541657
+4665490918503684461998203394016725914244105391374685986007968106627529172068516391306150797382538751326421691707344779240051404
+2641961236056444783029513171308212582932163735856854734301365261361011265730957017358847540597925397759304056715637265630175924
+3143119314616534179607705689766936638499515116711864605104806787742064610741185862931157231900890917045797092416341390041404007
+3447931172643093407899075956016941324761309449689246711224867235309324518097331543836073039264012951510199018054862544697302228
+1563566785164424421738528286186718541346261171578886688118979569809183215506908080307606078120020216388497864724764057557754295
+8570889786931244194585660557574434060147391448332058484468219132867607862446662006468299620134301595151046310252336800694251427
+0217713452224504960721091364387786965013258053103569599886166960333008816549340813042469646283329089138949995982273574974215868
+5241363057936964400802812697301682184281492778601196784957952838829973528993067785327299171845639921011068758599950934223980914
+3238619506166339720940794008445086813283016112070588367871958447351766426343723002443074101469688320695818179265745434758910694
+6296789680362763149161376071869217199662771928863547592423030630832336241218625794010606091635986342053359908043568336874619758
+5796450483018638379674081988788071939094611782491186354599577562913830254367966241420426194905385522339051453836242132016154075
+7739106134294761084702741107955615651072406250165155261201936784282832131480551569227393410480076418655073059966098939360374229
+2971567365547701845803783070635993312664824380381023912535236337973918393748125160984639017693662692774791712740599492208482304
+2270720904622266004044552929046382853488397030569658054130832432158967100326401536494483965188041727224259066348964879067583812
+3443273270836744114169351145812281297836105568675664537098362750380900035541986757124762712416133474277811013584828903165701857
+5742987445704693742780012691654778768416076035850059897986267208927114643299349752186944079949266040605774961616317552910045136
+1240573283641630694358812830029096031820509750547875205950719721469746524236951030334909216603563649107173637973757255912252238
+1182181309135378156725140117731218230316055150298076621940456444204177883491865113883523054776801063888819486505485385264913416
+5069068146388574137237425212952037225400371744975152454660711335647864580574001943714998326035983681508282903233341771279568745
+8467943310622656536228892538026964919357667642832630682651110048817452858559725652837991052187308635773654812551494387013316194
+6440134083862480163392226300450457593962112666903507568451147153007397865298280740371802995538252604177619078977124651051346524
+0537206772933648445348418297957633068071300723364120286017796847418742109018037795201017609886014503958468715621463005263787770
+3432430202920291906940764640954727327787760258258401409130943189103009317398784374181000619017547537895364515789076658241461815
+5914935373373404632064261928025631881068410722283620043865276873695737002786518062855969064577740316535280772509182462064465423
+4663807875203623784262624547123565729447932492414543360035449489544264792983057557527120665531457725601958452570287012086637115
+0847474551270439717567791117916716520890209772268515126243374020404961236068669964591032312120458856151122774707229179093256702
+2728583785414355071386563956562688209782901746373262288816864290881579324219562028197868974414398025024344306680144426091625030
+0910829767068265611067617086376443471268114912189289789288578161296371552096260414590275441364898692653660772972831143055685254
+6907552020126899986435407709381912657932246467804972165765350364308400598137400904853881086873855469475626923756560878726730206
+9692227748520363042215131444256441345425607520902904049752565589636006403442938604002826527897011684910364030121356648587505405
+4764025506989776287250936345001157192241256998927684892678268726606209680040843191546472014984020704327316352200558172668843000
+0564503985848436331698791790813182963520559967441699554268886929254925633860614440306175833628563304317763920599751129071094309
+0175566287557279025857970584297243285600759435104151831150200001725607992873593941524916608511725999483859291253760003734973775
+3039168535120967789573627753936889933310390638519872912077737282540474993630496322839461848810678646381314301370434612679202453
+5290955424609618789728513231303753525180260090737043547498273247450093929519045624882089783253628274100484171694237532423254859
+8186844862044986653314802892230697717326617551815053423012041608272398516591496440428962043914698069230013270892802838135287280
+2942112717174269473287862314996229628874313075502005461595688743732840097634991389852224318945641142059923309434297254976695326
+2444525231843962298275031069381314438305678331941237253189959661616931936428403908777740475422459580996785256969423138340880864
+3680179310627154010609137293613898326769365871171324366981855057912989303388559760676270131578093527806064422528032847530674921
+9355461118722504639190973677696806900807813249020915988601326357024391608006515894656601520223498473406143763133984605551760635
+2692839783034034225135191314183486878688437669767719161941937422862653760924569831725084821460846216076710658987697058689127356
+3364076178555288032798058397361297765867389733546080821420688209714329880465424718281983378741966307965647446727248970877582835
+5097154920011309551648620026419749934729546113147672841385317729841476832905993191729886098778334663461209723905553676387326787
+7544038203057755483948118938898802083672133837458011190981229303171157034238018580240354203030584798053880317332961525265980136
+1511152526450600575245224610801100379737911240153008627074626764499468695975779959724757934622234502314480579416277867481722879
+9208761275469748679977983637248710137550354113725122267268928582906191386758550109656015747293931779066403562806751200098816649
+2774371960428126935364571996703554555526862912399267217503390978028481995519553561409174881144281743002477593997449474113614320
+3283118387697337618913008345214573134792212133551845640272542182183565756097005950085429574121104212579366752791246087630740431
+2251626647794796903046417171601708089033102353726791435541243544024082843362831636356376144988414260766152555993385246920667885
+4120430579803988192186052185336786436260523534744839109920724061087523726726856003315563861271636470368332064799342319979701963
+1178460847308168095740461067148790390275190816124283621727277092177096823111400887004927669450338704196432823728793780107282726
+6147466566392578561700534815888328209861843963585876273190658740165656380640111544922854734365367040797352367883442096872576161
+0655254149992445465845820920429897376775083347655359252308973271695549200271712623988532809944592500421544522541040542744651771
+8895306524774577797925949127567789976094837338117657136712633080384090456221881872243825996086082147423517476054977573177854050
+4943011385246149882784947556915542478920754812582717541224558316858308474902436139789610336015128572291595765038163819815572793
+0059519490142292292642467486355644357871443222407272677363258010549846343690410511589487255437861629574221414317395258487976995
+6701428890977392343133134256358135045673673123158832116303929634062094950503008501398110339118434776130231986975400156621462276
+4809112204042804726404274446015570840535663272343219408139885535879522105193162064034829419212674983141334515042809663864776730
+3339872236842534294842100648778519220364381792736266281427277880995347117460315427394400908444602067720779504370559025897150525
+0666515892628240976196163023835072227181720931267205367481763695114784962335391370607825220441784558120081030826294430035145825
+5990171621923618467399400881105334235398291318764791324436841208478784739274728174080402657482105706012062680090302017358495564
+5800215155555227538662802534678916888507797284554941341847639680300462071370712985768701847640442454877861723356457893345549450
+0044372835991682943791367236860846326267985956993372513320157207230356385776345982286545530591945027191940491720657627496371424
+3896431871159669144163572836324937737933585239956934241358540063356296466656555165061326841756648545874963895216091891197215432
+1150436121846416639357239779525130732656046114770001886098939931426129354428928259723637803567803101198938817466591948073654097
+3680333838160206864509221215320873122528703603282455751545397796927467717336094169326962640299653768153008615924472102530867643
+6770050643269265320774249712789524649226429216132578192388680218997460246361157967129125548877818859824163987287642561738796200
+5254046150685030619784205850259746232647288005274167276588953501245671262327906633892459399349248665683674586756619925085832749
+8138659441098017401153449742392984232024716079021347321627336986000612605589176674195767657558188526805373912850372987580206973
+8191739475819996816485468724355025309335206345790673864079265551398839303546015301031614690697079405116794058344817857751170058
+5907733664187032783992586304169841870946162957846844623230375351751398150941213221188521406317499729525031329275753209552972135
+9176007624492506072188440485436086995355405038611315169617103420795642254487038087275622057368505174049950711687063028236514019
+2054382102455304130470152360854926810408620809647732343016107388521668970316223874173994646760209951211428665814705542349614124
+6010507266966547829863386841978029050310064720150129583679215294838434102788460967870976228374996605588773396271433676057289822
+7051841412308687295953020826737760628903413518500966433370038504670238126933304749517485860557144247313921158680957030845329616
+2360033770199629503223807832521648961131842719239878810835014788911969787608442436353630358920568228223028658040834409931217202
+8400997693934004696590555410764211165674028575041130093079293183383749718414250933932351869983505392135593326730456694681893830
+9601966479081797142729057700273038016579775812303462568369987589932810195102540708796028133906200420900692102185183676170434137
+3162497370959471401670744764602103343725945241209609871641803759642428128312023652491828868062451307296471228615569464816843941
+8764436487815154921343571706294950245330020417561336192910050884197950522678946771691143370350696790098631293864395203215663546
+2103973531056753606278933160819590888661208989653023859755262642075600795082475977389553769715231157147229187302967554388198370
+5511263147464601148510010944839861149087736327442223343582633059022202904665113422199247896714934045390179111585670544907398745
+6503691628140930095878935309503466424485388886339832328600458315631288162890181616057639363435222140281269282576385033650710680
+8454254370393439429040009560609022779619788056284224520991161927353411842168395626223590494290282053470410540843450407987926472
+1336825679355920509182270187363852809609898538144457557442453481966013998014732868105005901821373796606751500831791325616529203
+5075118330341336536977717509239821947081842843667207368538939749602952519028901304254002381236022047524790390418089280097834547
+7087002693940685994858725839374363930880942852293359924965925052590869503751762743229260822706873201650092697209849276502693145
+7306083000612674447155484200177291509744727003567573915026132438684216504412932709214471251820240604475149792423248249870477794
+1828750345492089414352178700274996717656637631789061874232476374372589026121784200003799632748786969419729627555600483655428983
+1419038605582900945308948756881180557106644399148478031842482768934058982366460243721966998715761966320233275607842960609086807
+8995674775072395937621113944922442969450956475559169579744736615353848691595206952225921509080923588771792361528472949801095259
+8071164393093218807836177998870397618178243287174730595843254576188688725044187468313573761652235487642008727514328298453902298
+0249472421551084408818726321837167660068433212182140863918498142778473568559604363644028430498972834010437189971676814372359835
+6326215711122626023900879284642848379045342532983675870120785391214889560676166670449442675798343547201651587376372310330260972
+7721128349367234491190961548434288775058240627555576639847795303346657927088312538298685663289068965153779510427872075661840307
+6404054826004851129562529146035965093659305313594131922007840749997852785915480413483418179403471734301385082608331943522033365
+9733723661694274986939415998932370600151791965983225598026282848806043753357041009447678948117256393500635321688798336983220809
+3023589135170563869561312040343087996767334919517638058142422305672311345678035221436322642357974773060658747505711133889241231
+1715152441111565992971519735514891973779991073609482568950260394204089469526267416519043590653468197703445241031998318436540928
+2571161687670398639649025206286059219618343667065497532146361041751088315806996390315937024865023472982359206847895714744923905
+5104856285757044366877940768642231044057490201353054349716001939164041109356173546969025877651803874584635636362767779008126317
+3656921864783698643075571406752016536758441120671704957195627803118074461526120679475816346733176098378409722349965248254591396
+1131443502066788861338718815939549028179403039813213172777877033453234020243883715396074872970863142546452822669185069959899184
+3828769910844736669658151259692028871696603091005326667495981150974845310134146991259645265882236097619326183020932698293809389
+4299190605742357746915386971343055529972124390299804481008342198376182446383261925929177219506772125075974364335839610948010146
+1147666764087177430198110110312435274731031579695008275499991697667495238558041459480531076474591001063866865437151222907417625
+3118583599222787818632900781019308738830040805599161996484071877144944130661026998282751748208682924005109173737574254051272267
+7248376535827628635806240316333585049198937287552863170331727642858039762809709721675292461634836370227092107000659180675306750
+5306506627623780068062337884640840561088552876565604494700675337745509144650468822636638698294453362040534422173031206225551013
+4252579308534696009946359817557643262143167696605231236359117810698816646524895198187607892477097108960784373761400944824549798
+6045449932335488814802338206074710052382801251742328755176048705595171441928353779134497634248965450262069632636038949744898591
+5048702418591439721957110373280102402968469372594873031440576890966279374555142674908990757259647232567240212811527932452059539
+6445116473158402926922663638150560761537491240522157144544441504700466911488897981059188305240921784775901100861995605851341634
+6426302952753103378949324692632848243080208624864503932730319385221633332864218296337728836033257029589381148577572779689079838
+8323351033213327371073881110283228611521471023685177945561596153462821296338506612181495253533007296541471850977144060198153791
+8612240193336900124220751825865213792796718254928148410457543169565765686381156512821242185857562689521331372459681870446271120
+2190046770619246800670427384048126037985607253433475697587520496744179478706647309818755439429545326720329201172200607765064227
+3736184856673482672738889087427014657874110745468152414492168023597661163943017362999706603380493625843592458433287608755926735
+4182865681401614720438201427164757077032257161772988732629306857669039790289782177374506368443513627759379215518499475202046737
+0697566863573366009839193988358046426820897141853585923998497091914817356341676241151406963597520055377063092845547594101697448
+9770510287164808256026738019695567751276805483623280478598925336381177794945569958800804342768914035606587017994256909693642474
+7259755154611086941695255874435534803016372667978524879504844920733928636400671846029963027849546724083520281554956394251995619
+1834558695670914755649864898844629047200426021450454765139131674876570357846943407935142270035129746721137853801869970041785717
+1163596604514706992103337640896730977362836499853948987124318776421720842943109071494096297915872890046802390417171851693498985
+6696873506860390067654571204036998680608912603658516851469732917336706912396900863519518863153116679969409193499475151912748965
+5772630153097284117632752487886616553301227224710840592032831301443809681968538716385350119500103381352429438906070006049324510
+7255320449590155185339594353774382542901912346562333365165993746566717810379624006716063017965110258762932735063223456498216112
+6248309487192090873881009634314790029246770378814629258114526635202683322798948006269443152846896870196478753064865917440440787
+1079237303256511529274839846470858035223497145513826461412560940325017754834231423361883666751693338383865225187216612119160015
+4861549012935871901840283860561328549067295489644918336638431557892707608901138017599623121810750153111482390969696067122547247
+2439131148441383234199376711842415663942174805857098114579871600691759196917341291603802573327405138562282722593414751206457843
+1973359935209045256671529911507316084304214657632392500349841226204006608244837820483129185333807659672251730206136609040933140
+8184943256874541309753395121370721662620513066937352652876771594490437810449353276322830929392380590748672786848276069239565457
+3348707026381104836690412750227080237859968000391150025633563394577801401905026748085615086352851413067595432050498561008571529
+1877075667972855586652155165911443897166143801340467259805712033287524340520335275436517702758812944056177253493418193171478211
+3774854369590560985587771159245595691913575127970445498501177157738494672527414527162836050852813684096791146417973149365483037
+6704552131555310027219368793280881514598163193897955852905718685913917573430057096937340959824715120372466589909944315684960960
+1012314375846207604646749185426484171598374093369935297204972798525329648052886568477644707532784462941904877487489747098535818
+7985674284714583813663198777955800874049562438949351977791559431711873042288148908962573859023348239888106006645129281470473018
+9254850687404139400561382825175974131012329412859199274634520950110017567085977669352012785318630525841745235957179742713982397
+5097303689162257167085390435448404263178199429357071875772715774544733708487138600770119134943129539543347602041901144161660698
+6953181183113203630678272715731094392489433607360104735402092320971396494926265205286840279679199637087859730680473846380532205
+7565033230336604389926974822292700950491849340699150720775179860790531037997637976970549940150909535407513425455328335706561853
+5335368312471755733760541805372968424193070274491865313428788002453279122401760512494622819480016105587606929438634932015824839
+5559016338160351661853688320039654018084969722536423822579994200012801736919709694310831609907486201946501673508356764142877308
+7309191546539260723637253628477957548575327772499530308454034050815650925443083418507106015799454347735223841084017225944595226
+4885590707691548323545253419048477650698836445425272829459034786263150039138385336170173040262385017882023012446601786508537725
+3159300795992899648874466508404624507417341674483549750138299511054547355595935184376005929821246479521411349307469101710751249
+2708412392547375974662585574062716099744667256888486220537125770970468132844596575936704205294434437646542619212125911160088350
+7671842861670510559275736664436986661209239228900436842961873275642777838933287515196746049787877411927981310119576400549956135
+8080578380146388148902757671260230173280743467984486835312292349158474503715607238743382799824745964056080082925917323860644616
+2120225379169780135148292573265658608927358543522142151484031366388491618786494744941370627406622031907792989518445311039563243
+6616422310981362438162790258221845503573731451992162868203601740290116853659138924079987226446597241351646843845278977024986205
+3662517640661488061073964114703410205367685498808240378692251201166863090113025726146269622096930731719426952075506480919216671
+4823643457908716999726557603223790753609939423361772712423018042932577115436095139459068730410826645568806300379584835433450946
+7837676208477360145796134097352072195957133041368812408314333472555459775670645841696822521516557015970698046160780950308863139
+5015658403765286649459660652152764801017680991103667912937430519322186712931073677796456215078436603241360959178629806771058487
+9139921128024002577938454673706047243620589115000240242563021016654786832806633509254081676514023612790990852595917560180876986
+9308821204883025320496874045455981233709125160954382611635568126874562312377547977111739040746530325193651004237373402504537024
+1600821697316131396065115975797494969376263815891380490449703227459763844691726208596151555303610430036532384862800860173068687
+1677749011530966588655330008218462556189908006964342216676682876215290543872066380630113889263010720992320394875173725292986311
+6989579261987669045792589013853182107944124182584456537044269091571439065320682853599165887592383283334586801282099984394392022
+9970108676029913047954776468886108937529661369633484559390003673582932372797656385704195055160295258401674267521236080828952316
+3273802761420937902459164150004835781371893878839475301617292925707508874975102558388990001315786419341804043737604037226331752
+6423865093791333509337877707981916567162340796885934470115945789596479789320653277617641131277451340371426117129794514423620761
+7417609321834214164793102707841568625675868448913528641242723253295495191476269874558175687931888576975179732585669568870748778
+5922089337143793314961512325922930026645734559888635155138481555659443901618808201784727019382947895019140665125084159195324704
+2832300412363246058905063308416630201890917641050411420603351067801736891124820850891397186056454796477918095532199343583413766
+3842538349880871712437577001398701888177344881522702272474861972439339253087204797211344636084653095826769076765966355059432859
+9877839498202302366738674681533509411775934456542381162185787945980551914209016996885507489310451917077029188324180322160260432
+2738878897545393488539641042595991720479279596803533846602159358145022104838297930283221202267258855473584700375502341592186375
+9062102173051107870783580788794675784912283028909776152369743147402812551267763802726764393893702046520930303504745751378996798
+1890158543698671287785156969862722836025364759849336645190863408137034806850238192071351320453303572785270717307117565718365448
+7734822410504169526033583218346170435610106103279145679136488844339942839493180608845290017442034674025577300763459944350044123
+6105040904995754702216898271414142776115817083443246834852579568391309141621714380298793479424942862844759389997283360409266478
+8207744090633188685115276563756960203356370566871533095111186389044186232441179082078908516925531610020829064403059153715127765
+4543411669625489070844963508370766554494552051662899693726257799474616282059274838670819153036396550543481066774790569529843561
+6679799651036598201198464287278166599830430479287605906552407498711145045497296895091710143423667516678729308766311555682391918
+9060618446032966067396024483927774799271013972963401931215359008050857228820472502367068320857075813753280582206475097498167537
+1091834892775689353192772704190529392359261014072163618697328287354942394830079331974933337512857161868992496906607708010073398
+5364177554337994653512816619520240821994073186844625407311661314696382001907220045017648487411581430791143507856735567122196867
+0716761726451434192525856251744493844256079661428358229774069510316066898590543756088198375973992063361152435222465923662351366
+0043075513893517349925411233398957648025096112448548886678072991181902374596438596256297098774636238148028169588473828501924259
+3228516645884143195864667466124866845099402543607000135666586926382976262509368071827459582454935921975303881150829096536404067
+4761157693052962556888050028734514069905365690844215214316263823173976897101122538440327270223709317772895230031391498145736860
+6385041084622772519780334652630409495229736116311103527030831268982936563366735822928512879378203876837625284271193343076105495
+8825229991999801614347782438381474867852878074358430022437396713162807802543161593009219312576950358519990247724194904234397934
+7703801976947027234960802861233790319790676821468496141323682139060568458559647230530529267618724263639883376817372167884440632
+1726382143017323548108870010820096752312836426102452450577004449101845698867822824844060001600494219691513701486376765683162295
+8567344046439933818792026021934172754782928648841755910876641284145941585066904498876784179002951113808421135227067381608911653
+2236981696764483162752804813037353468784452076739585261632267090804876266610444767882886160729217192498345880705115733282372008
+1313046830998564657547840785183730714291004250275503590948256987454019097344722968276149211207582987088443854985798581722550023
+9063006406664758572850022859344148370428972822517076773683529207252067208935050546823673576957790680951020623419459032466629849
+7938928170423206022080881849589066531884975323736816185913375521669990715327020849225286810140422793741838143465182856377816749
+1265756842388175742586708059491362377918488379984875832030848543287918941984050070389106581268802594158962582407355351035627049
+5900221712437059899622129468224343840497771816212975521659975058333318690798732737341876177817630804815720469182652538833483463
+5823081639915099173836211725045578069819187508359785075471465778986260818861591546963352470179514396250583548650281488440780418
+7451048170517299540822354367273854496577812259623792325601325690996083083112151683648900535783537568629739368276233311118065909
+9084734714613092289461178939653038690130944168935857129538400432419569476969252314501208058863985767404598559353985694589773895
+6277214607560240011967714168838143750302367595949536752213657372427124984199709048837186130780108450270594932950252051594320147
+3499572321088417920853211811454866152496225537457554175697449661675274675801653044218258736968600625898775131530277707042339508
+9914225219653958408220404955503421597988800462882509224240059485399789816322467527449242209991095322026817971575335077154317985
+5278081500892846628897442768350495212681297210154604830667333056587120720522354514329460517681155334733974540010110756237411297
+8210591237075811936724693019310304435150990235368637778807792760313222154371335709089813727563208995319466715986861635780866968
+7932415587435911762210037637958044637519791039364219987373646146500303943912999127265553435145017969397164413915816752545161718
+5633226031400350789184112011648210881013020831437183038308240362781644283374155015679893305443987813011631237184023671550613020
+5811978080228290171238069706605813947244025818423549831774560590994763911374360626408512454006214897383037052649605527910939842
+1578662832737601740265954708879993575835470810729170613732770615041114798158887175252200232752097837948350852301754510131346245
+6068409444406865116594371496646576550470605636603063539678037419994055698404550683594340710909264161990867009969259182486360989
+3207255402572128867597708386762297362519921843080894171603067736003753278183424031926979188196805787920726466251458690002582913
+5008569364534625206093594865389861974491057988729642501378201086357626134901180260883065306275795854872408871966970358994916566
+5260870280380960692056382943423819321600456629197713258529958092905135072192290151897612011642141070383635146934909632500071674
+5103943101344555719687493820066438065019249811470335254469779344109290667032018362593087359223818942995619770011635033602760781
+6090182191502983738438010896590866621707943859659299906860770756177151013807688207972939771298998138528654622092955429850905653
+1626336772125369872523005387925612023085181385255260458074393235131647700974860337649978590067937668268507156384372177447503498
+0983088220975640726485831380650348574527016263360984693517646111104451963030529155545125362875373684368744288268392996464031787
+1886577864886560438915496753180364296870396016073972814584707172757602216484353054194841318491639088652070784986581587056423963
+5791295955798452846006486957884980659241458306340044696019455166134558465794056766142717707049752847050948964499027310212291201
+3920118159051788842792018209898781792646763214510193250573669914454162275192491103856842226701566784572791940951044194717542411
+5568425247114245514540844570366702834465456557122445652286286614869534230920871827766118797945440453053831301603663599611151007
+9132285049335898106348530191639824752961756612096827245060794650887002292087021431444313048295402370831165699527783501924024187
+9094264576555332744996979181892440388769625070877328456545115444598432716233979462060670021904359658071557042696819752714761359
+2624335032983933790947468174067700780434730280286305837296068262033116687738482347338258135450536831314508366201724139587815922
+8450751384747855334597310320588125802084226440657572189418133991724784364158225409421748567123411489197359560319327166452150553
+0217315146965805878176534045386582646736519057669936823885725039838691917663928104666774688631639185290691596050519297245051431
+7940957013433199012061114563562278128253591876081307949974283942244584406336676182042124767131849195077146222822951756668914757
+6589005956437167623060683298552386150740712051896264556502825752701728084586373026820140301271827258402697782005508526864025995
+3287288894211530920495178421618385358928209601522908652144815977173646436635300032777312309529559530424309089857544514218168330
+6097483328468004536631471410495796391660358670051698715076410248502303660016161800128810231929174703618080502422800241933644130
+2956392224013095847029227680428083425620941588942686433369479814315411693725173853101111802188051631515982053459377355277916857
+3065681935968907368748287973480293783213808382487086015879418794067438804225330554229750223350574245985145312570124344685276455
+3489772935059313564818602631010215526615299221297140830316899208960430528821219213991899112889288129943720176337014173173174332
+4169981630658215328566362976636435099613640630157506404256612156966851420692144492745499377619802506248375541742742014068421649
+3723697831339666759125999969874386488250045997138226100381868783065151573396084764792101954730971063666073382268822664370648202
+7695739092394145422409597895972497681500338948172798211529024633083754418602669479252615594701113082363308526566375385313538692
+0362024243582700927996091721261779876357892824920462321831613846936511858949877169168914710103805138231321626700946199996026230
+0910370398336603134902288593437904852970471827636244578441003561376156126397047213862430430449454667576391124197185148345471598
+5028346423876572027639326365391106837855425740087158529449602646500698308039624506892347711322718143846562617911464289132024496
+9181010776426759091535139982513243227866023899159123168014651495554175929065144279128447458894513674919834462361991122972799428
+6472902683846165829490192503189706567753176937559527683694767361120216602239730653948099377610225798683453077405631209096231256
+0512986051426035486790488833906991553793296020140460296126591780195814787329857676072922129878562425136025882880600984983973989
+8577540121631192413042201337007929873227061283325668352988181356692287167551269236062168964313569524237889901244379824573640154
+5738145734013901847027973765976787682776812683421111101939034836663608749968365412229382487929512185391212964474327857768911300
+7562207836356806317921677823535902895646261255973726228824124734902468677105214682457780953879753523764199156291556619449942205
+6685144408630396033374384521831023348395708816803320958823787110609396335187767019703187308157675845831700883961350733812554544
+7576609828782901349340272529157644117188745883108516505970478068227119245704450471362770646680973620118556831550370068906691429
+7387998131808587529731801781598911046784196725282943998624870759033897379214694560999940160160935915403688360574784745832951209
+6248576464881189569842693329569180599977760906738941622134746107827192298531798906163755685774369390363347404463590563452485459
+0534570888244129725519284614466994594106901806409139995601464274045789187815608635654309801136434736637205014712781222746921224
+7852721958335248170761829133326246797700730414740667697834509581576475365734827900004460335634027879413672459976734498386195835
+5088370360545200433735093090688791665393907039059272593032100436084501418577206986549399579720624028466951070544585214365207165
+6435187129368614449937580538296933531792687165143536181239511296901417188887649499928950174527974591005214327286330726199831884
+5864261175041853165789209708620714822361777843032399821785843235985913827357647540975103877312914819841724359018056154229990484
+1936832320986190570216413377747783409617074645446275675504398782817281167330026961325947267465552277788937638823143961712338389
+6643014994016028760819796829700070956205113377466899907953033114796754643995517690305975245695734383895488045495784881027449542
+9277149772110266765516542199009389979979428729803481968242094114554310414335680714665255584623073310801300516821617747378223514
+5122582985363185134103472499467534154970594419472963412571152321765481331992341844237099548533622925469977982035402603376599366
+5702039170472823969912601643296899307773750835106819267275831078282467998094066465029472821615682366477091470622470049719032042
+0671010358945492991105729283517652015315441687350701252921272273957729883415005085140318681745681298665587818639399209287652478
+8504952151973256765543113775190946452315557877268395630007206112950274261280515123602637574614066439170518948486082023049534264
+8318785147359309244073883391968368385030412213804815219561275632927036049996919071912768810313118985299449822580618372563128123
+5447965794084022881336224721150430474622954063445132529997642171980649882452452874371660709010271333178089011623650142945593513
+7498570392070031176556263724838104407401975655807188803601068318852915004571680712468602581133705435004279673319305506280782318
+4235251770160613000830130983063100984485301111420207302571915861863284245935054969687285090784775829404258632032504825073887582
+6407248272722201582954889873840796724288126199508498948167917317499903480984445960848498060154084891463403285778107348687889003
+4953941330396268815099409977237615027521463257528034758197037642240947224961515275989640733601052280398818164960445717239008728
+4426630124553142687273205330644281511721380282097626819427510520776002629092574526215543555846304555626987349130475830717662512
+2679622415503744585776560549326024439456730222065789254179516934309405880579097989297964155354764447981652276792153719461894070
+6549452078295195952851972101892868752466073329081552637836554870868329745518970415001754631788228704301414087107528862687179382
+3095714010946058367115405111675588241660359378724218257897889232511664785827286570897205547229279697287663245465265895194075831
+9805465298621739062011152177896594580714703932025865262409510756369094551491315344002976208292437754134178483455044310999687172
+5635853083465443752399385809613532628000929554168679920157180193163062291041706935484519604033746044464716659982230583915172977
+1397085494342438160066950214161726216316797535747161972858218528442291370670389809452231490128596440810108729216233152926963393
+8718938957831579949398261083744948669476176529513240710990560722588644755296402086806852345746538236347718030640062631744819555
+9204989031916871283227517942830744003831314993547893753197955379403077174291901637842637655437310798500528596483721526174221178
+4510621681082500438705444746385938892179962383128718253236867948364044872547102979732643922151263657382171953178711857903512864
+3434625913079139632847162412927858083774910063803492872036606235419074389757800463882617655159555904544646003283714069095719127
+9422478480758793975004764634088848124200701219293815383644557399151474644429876593122326476162568364525117348282565684006439054
+6415412788931044743766779624337137193856769272687596658353208728053926044570228051289974744446738511898266628888688489033821326
+3857187055764486798882511807937125159502970249818799519647825055901143034107396715341111836431533491237288074873324479254847609
+1944275217447109672414805304798039892872048551668309961639053276921203694927946551682999672834794575568139407200344761188832584
+9228691574818073805866351085919567356330517627511140717776424135867621344167516969731782408297076690641510925488519425339786231
+2831239904815704920016412032913992948413502229392159186483640311971384616648328934218616172408437024641339341534952850417631408
+7800709599423404547224077175920136421077429331304204846667623312748910375272177983791546978316206296185604509872479031731294077
+6784795879386865023891006814459422181459242147354385223330262696056730516247499993593952360113613078289229711721789291466201911
+1558378948527819137236700414103122090944390583763494240148255786716027072401897565958932034145583789267171948650451004479200278
+5903365269957297061267790413012843976619330012086443873201405355132327717135407147467813950090532723390786355726062359803253439
+7629287528827946090011668159293077488731123501345393936384022425933097863996545653037874008416991412735073016080615679561676815
+3237960418959875052085168366152912866396485668534444686608623522780325138572281373258421046475238324527598957994900036953588632
+9883457218912143598750744649289916045155230666253998012127292069605955397882251577278616463161982956480851083203582599294132885
+8739605725967415654345383552272209454198363876790394143551885453633595477692847087747048445889713841117432214889427740276964122
+1808274594398149686259653460592417452536265711085053636183889817336547379067581749366999937190487929782077243956107305394452893
+2858306534503555758138192142342374976569912519114070071304001216131565171144485590883323767986065555672710513575942087665489357
+4757258115582473299797872077008431880804766429204591994348523186470015406253571125582684142251809933836340635261386229168816736
+9918555292750664784762306372865895993392873092492120139178044227677315162874458415577767229742354738329991177067335396671747156
+9915416169565774505455198608946138326580556663002878103141442158950284935423931276623631554768708518659417736110868144091121408
+7485024844800932215930566743200643612646843426043824587026297306446562930746643938917961270550045568670866510426684185886721448
+4920398501344484751530060228048138752162844188260697740262204586350188489261031255952257367650241279996726021255197979400713310
+0983903945365766675649828378701431579004857069167244696371192650313930100887222144395396003002837274898192175630515559492616368
+3277569441388072350944394279081011821982637576381780324461779633187405677617459795408379063310477462661505822241372624056397980
+2796195339856562934096874382820282192099707799004934067504550995736513197478848274092619553245513516215920528915358178045259427
+3947135872153511247151284668940911981933985156149720562664695031030349744372110088157223178406720212021960705751648342245477823
+8276198303392861443910819050105767637970397653898744484200995946877348235373325786715347188697829025445506211703973576651655150
+5882576032689008918318143363475006909501115410116941599853261283394744451901101910507633092078494500214632287815925595536310673
+7269241743888980922214944937348603959760552838607959592411748713582006971089673926445144319837129979120595791416170081356544964
+3311215693514569183444297282757452024106434743342415838798070572517431245405339373780763180400593713529558089381582197573125752
+4556878108283717136754864320383151773421100605854818531410424407658443836201366417280243912680383714161438889747985913112617159
+3825283938152818066103999819485641639048153915591788440799327104545750772861261496085802570014233362502408220258846139854490942
+3543037705426699624325696485612282411023745859388735341967646420985563945181345313960301854453402790876180716518598169356488497
+0055015399759018591540911328290609447855851641187622864276870240973176403939507548117764594583218172186919643238977138111158956
+2302146157347717928300258596580246250649908644352652697865369736710811431250945078622499892640698932203651495464626034751579299
+0465216581077322245370388400939469195489616593652097640401043603078806904801413336072374703228412879808024013691780444525050754
+9151727760868811886689437563229171390965138504950138407176506255752456724326383897323049258585289255126700265024238726662681731
+0098281899254404044904741984338800905867702052389334861534065540083641450439874866038625038945827791603161398328731872690722059
+6264530562489216043969280034408943083142765136686187837798682491792210809601751533837187815038112873969767271421029102693650921
+7670518311894906730059859298650685509520663627502700465860614043829130684092155123515969024766529965326820247830045239762876384
+1971827918374425559499103800305418434180845901819771222995898394549615763182780848478726307902754377493105414864115497763562067
+7293146824231836764324358936471102982745003549454252992884038807314576844595566006507289403671236553892547396334547842381936455
+3707012658412106034610065750021436552038057251146149724375405389299956024255098042568008242870114719254029045709055991603654930
+4543749521242879802728408392725236169206369176046813175364511678612424177154836269263324760122983569594445005273913013269664551
+5817700093174352547416009939112502133121085536020612539401905269863944981266637678387919942591042471679114800424206674615903746
+9928390417067700668674925186060124842260894166668581468768675095262594932684909013159566891337437296287921942274275342136808279
+1720526807320641693668140417766107453595978158154018754776221360462162393984770342801365549647871062173743896063916005240392253
+5161802386530577435326894842370519298812054283209695964545050386222673476579184628919106024296128426895608065795872894836272477
+9269809290510364760281346041981538977140734635535715877861564862122154561230471413453427434440292536928348809500100637413855174
+0657501300841813074935854851050163894991818276164751987873048063138250805404584707419292446697964047248725308217946641983844311
+8063478785147013188508380911686106501438761736788881545360437305874844044022285005421389985126661063912349587081288388003345466
+5080385912620164034274035663131591931589292314684519240800453976434478145811035864455399019210261903984106215732682395895799522
+0939020059406813121907073513079575778716665344964094359764782266431575550874973231091097656538411338304404129653958312868999842
+6732798933518323978985303323091966916070134400750942228988862433672654847071015762525448860254590537863809085645618465872667306
+0427846766351683194895724811056690695837239230026578986973494357639196637007765612283664140977141629336513743191474504552821790
+3228155682944358310924291228796943417467684350283874136741330013804595358442242749651649995689037646356343539795964269040555905
+6826145487746532059740843858150338835296508366342272235981293613561407683050389559856243442342524690245207486156018191382164551
+1327436225221742602074234993619036983345996345216008664910823535986496447271949044534929738194453356131648251656209560053354614
+0407290886807276555505472513777566509192309345071661761386510676177956004136233159240180697853305064135526857625954524710679122
+1431829687708285619275876929673787963838663779016128696006658789855078135858492072768308764926825429711165034052613724177837083
+7028553048202580189681827868563421125284289066186493489485470631057243002992982744971998313406439308961352814738730662842546474
+1661580089658576037549874036611720164076275368701553799369961428692585978010787204558502174932891500734632543309652429899761996
+9575856899639421670892327891209797029282817824375074240277705275435359082312316792956844954585652271368228646822716619012170165
+4690146795978834583378953218274128128954879679834962721495470431115747652300230454490265247933455376976025418712883919785265770
+4032584676449148273007032590154174755542691092611500872882432669889260868344191769763590664159630537010368972815582431630162563
+5692592732110530293190433213941741940871216528267789341138499704212959459631375151781937020467215223500973204249438057106028338
+1541214818072382006149334712979978351719934230083959861254175062060206728245934867359880240685020444293227864055618527079589472
+1439159705776204064690488345048299759772753492079024651663143703086754589449249599931908249754660757813918172727140178033198709
+7752381183500066741893133463291861429042158260704598873907314527361438231014952758222297919601552459311683576335125432073345960
+4158788096315630807867178963280856579732177587633674289101034755608242832707107748491269005626588055241208204418618388578035469
+1184416032139115028602210049000593619116279959516862765906011705138739437332038056873961010636018153261556031158803924660448426
+9834587809319862013631879808865489908412831755556199315250744409755028410760389172898604230817719091796600511778684843691064279
+7878372956127669698977302339079670592653146391325443980293253311254734925614678750486528888944734310378404782150993544089766813
+4482271911480681906845899905802627519765113355182171607609262740960268207890619067150293516596923655844247586174848972864721468
+9552003526630991149245651109495761934587784128507108647124483752936558263106644305431230364441437558819641682185001628863763328
+9406159315820904843204929487522677107941937076263988953382649335050929875295580457118791755887589396355358703932935557257606830
+2969493527901243167542109903168828628101917337300403325039813279857934939104326409957807201457446262732489661524241158979368142
+1833967145487476098973136162241392322964264292952490319901422154921305200229075272133864200487657774340560812039475075659326308
+1445298822625141627089594319278576573094647719202883678449230305616300998398218250958603519589651710614887336894157702428315107
+8911019753589361230572967964751571906635823516517521975275494263948066958905939807605210390275340148405377313480598158489558111
+3183749609096747980513864052412964607501407465024842349303716927046134047076464086834827581454812880653390898896534483223922702
+2047220404370553586495348686661844320582343653984119122227275984849504305399708851775077220602618170548438073982557547603633042
+5484875538490583169391720574953649919139069950121342298729189319935008363006908499817188567294646844902804708973781249800855552
+7421001424990409022663446235185073936721530809635245828159482916215742480785440259606637437758227633658889520747280770098045723
+6510075506635860479703887783619213078585799368504850589990946726994909109916359460180863720392604659818835051505356439580781411
+0959165291367850253561235537386721365762207442766902579631829064237987397582522884081947056330594794737026301952693630585102680
+6267281924773054128920399667616892395906931391070201721710734680164804934661829697133693962106573047827000567454860592220102084
+6351225785373403775734572811446819619019190839393144125015360556285521375890386016901082233720031340998488590003458019399286006
+8086983669350678861956334882898616321436714400384547300867927315159417274826609618496301870293049853960758679069277021904136960
+9865037759852510085988938641077600576537641357106366728530348981390205491195956901092388717027996104357442748303975082427786786
+7507248774842522159480897459767378325396763974897420116495369220388118224704985677597657612836164641593242643705906198310715923
+6020323897854469493762019753971728667497338537420217765895884555350482562903234559598367966289598307357713584270039680501758042
+2970682482901424731104641663111768757582340710358846705532647449734646971482108058532929343635001949578504462729212526976463810
+8406644630764947233594179128313043631264609165757699872474368034583055609364865453910940072958562666156078109884350362008700655
+9106501316131398908994689175684333822574784889714347654697727209736986308940910431037486363365667132654371414795819563310659169
+0137910472839714679161637852622472509459014895991142745425159229935069751019575455036034662579025492228994125955644298201357138
+2263663590472781654218931217059804728469684174302359039764853349702219977113201315914188584584955078222068657185984247622363558
+5695450824338155861977114741562006985207639935376048162114526556989656274727076392276059583216303897816482298413238883403403632
+0038975862485843345228895776545691226502347548540923009663654944132545600827380276828701039586345737400863528654887451057233197
+1285772332269416234665537910079978608222632602148452508934499816027147308767944385913555512454637610386856292966968437445496548
+1261330191618765210009782014085845073559775965093415001665110717532374517158996315004359428915981278340620344383170562473911188
+0755483943667647640579099438554263999127548734337936583257964438443463208543269429173892355146856191237124938489437234962714824
+9129303544439064208938552091032859116474732583566245269345387009587018850752964356086348467165770868170114265169858965115946288
+7279622065007376862875602615836848329672073134886504804366938182665036461895999032293214820132094992897811456738921945565996030
+4834236494451378286976564913106384851412866607459667235230175488097172277734513000370973157558689076209485032473704000163914074
+2906852713508769108670361019771730001144071549164484831831379004788411810506441972725735257048988599402331202363984166872400551
+4374843284474261559922201408952633150671870157517305411040726961843624607898601648184347808307024923212656070285299487288795732
+8117441033938778257340076295628604371272466046790715921004843853378457388333862596453687093388500288301007959254642621709441228
+8336419205482595246714478040728678515920231077940527413442313540990859460129785367310524821300597125039005330560255760446207185
+3407569957745240672748410048085824476146107644741791845367520753456514888607145322239479922742610070735465164422006326154369011
+8894279996606564122245246476739025836636961740221798143384506169709797876615015522415620193119156094455114077417058486277270353
+7131151035004395224877087554662361771017971918239145723682405673667071436258453271309611849685373102636336093172827546720740657
+8432145665345782054212385521456100690288045272048653500410117161030682916822394178179943934653293870095835416016828701651397729
+9807379993673315841883406823522043062628694861759093682354411179777001696451399181533177926653740164108712792568617753057780749
+7552198060883514609633356358462724322863739238474217533806217264897669042731651388657558396154686026363774639912794923252267503
+6291771443785740732590982981719905524567339994411151615939323485160260431350712239547320702908777027534814334898810771281406391
+8383725943909858701756050979518960102350055348726092344362770497395426060226252186716626586574811491995835598427931237638307288
+8507265667315900242180544608612147833573934012185340789193936346356941286917069481442515796977733286907179390046007293777378415
+8688298391307343027481331662068268845813946664921272848764804887244314914603468930763919183778517730411504413547554154855526591
+5310568546507610904043747230819248926074837842921381365456929822505503792963441504203788828448597610860322974517666735027993699
+8190512204618058514563016675739391233696406975567198996502543146118326981238682542313301537034074950744994938638623004424018628
+5962797353210542352910227068452267455627736914233254078275501019026029219977380762852165264848013890176220808626487330453830607
+1392715231741123546207682784414187261145744424815836598165304144212321073536110482416294352751979189695534837507189501132643925
+9547196873348778230662094351866444409683500705986806451682346762409749401895555972393170493498341109191510645940668680160665767
+9096955810744288162025152776265225979561511052982298941267330985571152782374720461772752985049704669084322641186449467889515212
+4360617959299125510229120098324080014685874269740158186892010379118371918256414709312045505595343772662619039003425826619680875
+8242651081630156918805572079983037638369031262141838260427869758050055377235638965872717517504788429694521145838583513263909672
+4433259455372438105974775408627724880736064277338137893108385178827104479149305047828800826485922049778207824411348676510055718
+8718825984885049258859271868511156347573558547616835487996237695354831720772501296121171500663173314753159506044722718279173640
+2709996430110563394535123371054969016136174141380219513450493806426805948941155396288218826477132071568170532718023856256400877
+4412955918580719390710872526700485018418160226844433869987075876676044792011973789419662798626013873183203506118837233134120481
+8772819562426148199715932002776622117594716096791960417797687467419822085071157480539482033047913473604918965910085487367720357
+4625085282706988812822930138218466374524023159847349699030998731244290316248877616127354994943514784160430249591960166158827428
+3012297335233487487686932791672504848939891571342804916267615897166810277253170819233520663757428230248104405100538854660927429
+9123919446207336590235297840044149569787830675448852079217813254125078565940555357151112153929694801251132171203795549941163920
+7476175369012980559938118310990110840174599144325883878065361105628152837782089093135806082805172562067617245231771061838879589
+4768469919871257284902195592516344833223851928691778696654759047583702848545509080899254152913598427216007302226235522358460750
+5223927757227044947866784478462919350895723643402842384138354740120256079056226884847266693352002580953694527348195695223607106
+4705073558122375415417200921965563405533347843275197814453910296613637292816403322858277400213988846375567124674868467361795016
+4745728385156852832029629080429064757351207656991841817680115495315482039644479548944488439788311653187692817074819840714497361
+5386314847182104599263810424039609228765878994123179215715094367283327303020988006589792974721368333841513658700314945433634456
+3685020221252259142980926069027074077129168059113331677771782227727933843623094566219277157186574916058687802285827552124321505
+0794558617931775588320039074320252238014802597836590634824227249703483529574186006183975509386000848443692647358501225142361167
+3942679708028160995866607265771564423203677879968679929985370044267348240320617033379072586756373490054605230219409903866795469
+7536599276764983130315949383875187945686502994166320326189211280377933687730984141460802381512939077916932152569652666724046409
+0292377825630966235158683241512971091944539929600065707699283877623772501033680549048220288927590692487589517712276010516389098
+4141777627623117777410741182897322646935774432337593489702909715834793849902052358894916963594941828827118210427424755222982593
+0263099400776234259640984881940007947968250580544744304077736076557953616095573458814306253535718606350692981623255928091096507
+0588327094996262431505059042095661828596107333578122924612340170790916991622052806671333685104366780235136494027277232872825498
+1523246308282008538061408160202517775966824053244715248653671495274650673682535042749033828795099010214859776685551489176975506
+5811209762314534687747281829159103097186141033482266881873367741901377849867980657673782571505747169485443159028925476795003998
+963436785863456565690613348237130676523955561372248056220702510606833697646989872355666869136182759934340379879840576201228LAST
diff --git a/libs/cpp-httplib/test/www/dir/index.html b/libs/cpp-httplib/test/www/dir/index.html
new file mode 100644
index 0000000..be3c05f
--- /dev/null
+++ b/libs/cpp-httplib/test/www/dir/index.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+</head>
+<body>
+ <a href="/dir/test.html">Test</a>
+ <a href="/hi">hi</a>
+</body>
+</html>
diff --git a/libs/cpp-httplib/test/www/dir/meson.build b/libs/cpp-httplib/test/www/dir/meson.build
new file mode 100644
index 0000000..e88ec79
--- /dev/null
+++ b/libs/cpp-httplib/test/www/dir/meson.build
@@ -0,0 +1,8 @@
+# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+configure_file(input: 'index.html', output: 'index.html', copy: true)
+configure_file(input: 'test.abcde', output: 'test.abcde', copy: true)
+configure_file(input: 'test.html', output: 'test.html', copy: true)
+configure_file(input: '1MB.txt', output: '1MB.txt', copy: true)
diff --git a/libs/cpp-httplib/test/www/dir/test.abcde b/libs/cpp-httplib/test/www/dir/test.abcde
new file mode 100644
index 0000000..6a81654
--- /dev/null
+++ b/libs/cpp-httplib/test/www/dir/test.abcde
@@ -0,0 +1 @@
+abcde \ No newline at end of file
diff --git a/libs/cpp-httplib/test/www/dir/test.html b/libs/cpp-httplib/test/www/dir/test.html
new file mode 100644
index 0000000..6d70cd0
--- /dev/null
+++ b/libs/cpp-httplib/test/www/dir/test.html
@@ -0,0 +1 @@
+test.html \ No newline at end of file
diff --git a/libs/cpp-httplib/test/www/empty_file b/libs/cpp-httplib/test/www/empty_file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/cpp-httplib/test/www/empty_file
diff --git a/libs/cpp-httplib/test/www/file b/libs/cpp-httplib/test/www/file
new file mode 100644
index 0000000..f73f309
--- /dev/null
+++ b/libs/cpp-httplib/test/www/file
@@ -0,0 +1 @@
+file
diff --git a/libs/cpp-httplib/test/www/meson.build b/libs/cpp-httplib/test/www/meson.build
new file mode 100644
index 0000000..be2b047
--- /dev/null
+++ b/libs/cpp-httplib/test/www/meson.build
@@ -0,0 +1,8 @@
+# SPDX-FileCopyrightText: 2024 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+configure_file(input: 'empty_file', output: 'empty_file', copy: true)
+configure_file(input: 'file', output: 'file', copy: true)
+subdir('dir')
+subdir('日本語Dir')
diff --git a/libs/cpp-httplib/test/www/日本語Dir/meson.build b/libs/cpp-httplib/test/www/日本語Dir/meson.build
new file mode 100644
index 0000000..4cd4150
--- /dev/null
+++ b/libs/cpp-httplib/test/www/日本語Dir/meson.build
@@ -0,0 +1,4 @@
+# SPDX-FileCopyrightText: 2025 Andrea Pappacoda
+# SPDX-License-Identifier: MIT
+
+configure_file(input: '日本語File.txt', output: '日本語File.txt', copy: true)
diff --git a/libs/cpp-httplib/test/www/日本語Dir/日本語File.txt b/libs/cpp-httplib/test/www/日本語Dir/日本語File.txt
new file mode 100644
index 0000000..3cc1ce7
--- /dev/null
+++ b/libs/cpp-httplib/test/www/日本語Dir/日本語File.txt
@@ -0,0 +1 @@
+日本語コンテンツ \ No newline at end of file
diff --git a/libs/cpp-httplib/test/www2/dir/index.html b/libs/cpp-httplib/test/www2/dir/index.html
new file mode 100644
index 0000000..be3c05f
--- /dev/null
+++ b/libs/cpp-httplib/test/www2/dir/index.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+</head>
+<body>
+ <a href="/dir/test.html">Test</a>
+ <a href="/hi">hi</a>
+</body>
+</html>
diff --git a/libs/cpp-httplib/test/www2/dir/meson.build b/libs/cpp-httplib/test/www2/dir/meson.build
new file mode 100644
index 0000000..74fe783
--- /dev/null
+++ b/libs/cpp-httplib/test/www2/dir/meson.build
@@ -0,0 +1,6 @@
+# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+configure_file(input: 'index.html', output: 'index.html', copy: true)
+configure_file(input: 'test.html', output: 'test.html', copy: true)
diff --git a/libs/cpp-httplib/test/www2/dir/test.html b/libs/cpp-httplib/test/www2/dir/test.html
new file mode 100644
index 0000000..6d70cd0
--- /dev/null
+++ b/libs/cpp-httplib/test/www2/dir/test.html
@@ -0,0 +1 @@
+test.html \ No newline at end of file
diff --git a/libs/cpp-httplib/test/www3/dir/index.html b/libs/cpp-httplib/test/www3/dir/index.html
new file mode 100644
index 0000000..be3c05f
--- /dev/null
+++ b/libs/cpp-httplib/test/www3/dir/index.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+</head>
+<body>
+ <a href="/dir/test.html">Test</a>
+ <a href="/hi">hi</a>
+</body>
+</html>
diff --git a/libs/cpp-httplib/test/www3/dir/meson.build b/libs/cpp-httplib/test/www3/dir/meson.build
new file mode 100644
index 0000000..74fe783
--- /dev/null
+++ b/libs/cpp-httplib/test/www3/dir/meson.build
@@ -0,0 +1,6 @@
+# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+configure_file(input: 'index.html', output: 'index.html', copy: true)
+configure_file(input: 'test.html', output: 'test.html', copy: true)
diff --git a/libs/cpp-httplib/test/www3/dir/test.html b/libs/cpp-httplib/test/www3/dir/test.html
new file mode 100644
index 0000000..6d70cd0
--- /dev/null
+++ b/libs/cpp-httplib/test/www3/dir/test.html
@@ -0,0 +1 @@
+test.html \ No newline at end of file