diff --git a/.gitignore b/.gitignore index dfaf72db..0802dbea 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,11 @@ build/ db/ *.gcov **/__pycache__/ +fr_client +tmp +*.onnx # VS Code Specific .devcontainer -.vscode \ No newline at end of file +.vscode +.coverage \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index afda38bf..713b4f66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,6 @@ cmake_minimum_required (VERSION 3.17) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +set(CMAKE_CXX_STANDARD 17) IF(CODE_COVERAGE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -Wall -coverage -fprofile-arcs -ftest-coverage") @@ -7,15 +9,17 @@ IF(CODE_COVERAGE) ENDIF() project(vdms_application) -add_compile_options(-g -fPIC) +add_compile_options(-g -fPIC -std=c++17) find_package( OpenCV REQUIRED ) find_package(Protobuf REQUIRED) +find_package( CURL REQUIRED ) +find_package(AWSSDK REQUIRED COMPONENTS core s3) include_directories(${Protobuf_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) -execute_process(COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/utils/src/api_schema/createApiString.py ${CMAKE_CURRENT_SOURCE_DIR}/utils/src/api_schema/api_schema.json ${CMAKE_CURRENT_BINARY_DIR}/APISchema.h) +execute_process(COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/utils/src/api_schema/createApiString.py ${CMAKE_CURRENT_SOURCE_DIR}/utils/src/api_schema/api_schema.json ${CMAKE_CURRENT_BINARY_DIR}/APISchema.h) protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS utils/src/protobuf/partitionerMessages.proto utils/src/protobuf/pmgdMessages.proto utils/src/protobuf/queryMessage.proto) add_library(vdms_protobuf SHARED ${PROTO_SRCS} ${PROTO_HDRS}) @@ -28,7 +32,6 @@ if (CLIENT) add_subdirectory(utils) add_subdirectory(client/cpp) - else() add_subdirectory(src/pmgd) add_subdirectory(utils) @@ -41,29 +44,29 @@ else() link_directories(/usr/local/lib /usr/lib/x86_64-linux-gnu/) include_directories(/usr/include/jsoncpp utils/include/ src/pmgd/include src/pmgd/util include/ src/vcl /usr/include ${CMAKE_CURRENT_BINARY_DIR}/utils/src/protobuf) add_library(dms SHARED - src/BoundingBoxCommand.cc - src/BlobCommand.cc - src/CommunicationManager.cc - src/DescriptorsCommand.cc - src/DescriptorsManager.cc - src/ExceptionsCommand.cc - src/ImageCommand.cc - src/PMGDIterators.cc - src/PMGDQuery.cc - src/PMGDQueryHandler.cc - src/QueryHandler.cc - src/QueryMessage.cc - src/RSCommand.cc - src/SearchExpression.cc - src/Server.cc - src/VDMSConfig.cc - src/VideoCommand.cc - src/AutoDeleteNode.cc - ${PROTO_SRCS} ${PROTO_HDRS} - ) - target_link_libraries(dms vcl pmgd pmgd-util protobuf vdms-utils pthread) - + src/BoundingBoxCommand.cc + src/BlobCommand.cc + src/CommunicationManager.cc + src/DescriptorsCommand.cc + src/DescriptorsManager.cc + src/ExceptionsCommand.cc + src/ImageCommand.cc + src/PMGDIterators.cc + src/PMGDQuery.cc + src/PMGDQueryHandler.cc + src/QueryHandler.cc + src/QueryMessage.cc + src/RSCommand.cc + src/SearchExpression.cc + src/Server.cc + src/VDMSConfig.cc + src/VideoCommand.cc + src/AutoDeleteNode.cc + src/ImageLoop.cc + ${PROTO_SRCS} ${PROTO_HDRS} +) + target_link_libraries(dms vcl pmgd pmgd-util protobuf tbb tiledb vdms-utils pthread -lcurl -lzmq ${AWSSDK_LINK_LIBRARIES}) add_executable(vdms src/vdms.cc) - target_link_libraries(vdms dms vdms_protobuf vcl tiledb faiss flinng jsoncpp ${OpenCV_LIBS}) + target_link_libraries(vdms dms vdms_protobuf vcl tiledb faiss flinng jsoncpp ${OpenCV_LIBS} ${AWSSDK_LINK_LIBRARIES}) endif () diff --git a/INSTALL.md b/INSTALL.md index b22c4e78..9348eb44 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -2,117 +2,113 @@ Here is the detailed process of installation of VDMS dependencies. ## Dependencies -Here we will install the Ubuntu 20.04 and Python3 packages. We assume `python`/`pip` is an alias for `python3`/`pip3`. If your system has both Python 2 and Python 3, please replace all pip and python commands with pip3 and python3, respectively. +To install VDMS, we must install the necessary dependencies via apt, github, and pip. + +### Install Debian Packages +Here we will install the Debian and Python3 packages. ```bash sudo apt-get update -sudo apt-get -y install --no-install-recommends software-properties-common -sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu focal-security main" -sudo apt-get -y install --no-install-recommends apt-transport-https autoconf automake bison build-essential \ - bzip2 ca-certificates curl=7.68.0-1ubuntu2.18 ed flex g++ git gnupg-agent javacc libarchive-tools \ - libatlas-base-dev libavcodec-dev libavformat-dev libboost-all-dev libbz2-dev \ - libc-ares-dev libdc1394-22-dev libgflags-dev libgoogle-glog-dev libgtest-dev \ - libgtk-3-dev libgtk2.0-dev libhdf5-serial-dev libjpeg-dev libjpeg8-dev libjsoncpp-dev \ - libleveldb-dev liblmdb-dev liblz4-dev libopenblas-dev libopenmpi-dev \ - libpng-dev librdkafka-dev libsnappy-dev libssl-dev libswscale-dev libtbb-dev \ - libtbb2 libtiff-dev libtiff5-dev libtool mpich openjdk-11-jdk-headless \ - pkg-config python3-dev python3-pip unzip -pip install --no-cache-dir "numpy>=1.23.2" "setuptools>=65.5.1" -``` -### Clone/Download Dependencies -Here we clone the repositories for grpc v1.40.0, libpng12, Swig v4.0.2, OpenCV 4.5.3, Valijson v0.6, CMake v3.21.2, Faiss v1.7.1, and FLINNG. Then download necesarry files for zlib v1.2.13, Json-simple v1.1.1, and TileDB v1.3.1. -Here we assume `$VDMS_DEP_DIR` is the working directory for installing dependencies and `python` is Python 3. +sudo apt-get install -y --no-install-suggests --no-install-recommends \ + apt-transport-https autoconf automake bison build-essential bzip2 ca-certificates \ + curl ed flex g++-9 gcc-9 git gnupg-agent javacc libarchive-tools libatlas-base-dev \ + libavcodec-dev libavformat-dev libboost-all-dev libbz2-dev libc-ares-dev libcurl4-openssl-dev \ + libdc1394-22-dev libgflags-dev libgoogle-glog-dev libgtest-dev libgtk-3-dev libgtk2.0-dev \ + libhdf5-dev libjpeg-dev libjpeg62-turbo-dev libjsoncpp-dev libleveldb-dev liblmdb-dev \ + liblz4-dev libopenblas-dev libopenmpi-dev libpng-dev librdkafka-dev libsnappy-dev libssl-dev \ + libswscale-dev libtbb-dev libtbb2 libtiff-dev libtiff5-dev libtool libzmq3-dev mpich \ + openjdk-11-jdk-headless pkg-config procps python3-dev python3-pip software-properties-common \ + swig unzip uuid-dev +``` +Note: Your system may have g++ or gcc version 10+. If this is the case, please use version 9 to build VDMS. Optional method for setting version 9 as default: +```bash +update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 1 +update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 1 +``` + +### Install Remaining Dependencies +Here we assume `$VDMS_DEP_DIR` is the directory for installing additional dependencies. +This directory is user-defined but here we use `/dependencies`. +These instructions assume you have full permissions to your system. +If not running as root, add `sudo` where necessary. ```bash -cd $VDMS_DEP_DIR -git clone --branch v3.21.2 https://github.com/Kitware/CMake.git && \ -git clone --branch v4.0.2 https://github.com/swig/swig.git && \ -git clone --branch v1.7.1 https://github.com/facebookresearch/faiss.git && \ -git clone https://github.com/tonyzhang617/FLINNG.git && \ -git clone --recurse-submodules -b v1.40.0 https://github.com/grpc/grpc.git && \ -git clone --branch 4.5.3 https://github.com/opencv/opencv.git && \ -git clone --branch v0.6 https://github.com/tristanpenman/valijson.git +VDMS_DEP_DIR=/dependencies # Set to any directory +BUILD_THREADS="-j`nproc`" +mkdir -p $VDMS_DEP_DIR +``` -sudo curl -L -o /usr/share/java/json-simple-1.1.1.jar https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/json-simple/json-simple-1.1.1.jar && \ -sudo curl -L -o 1.3.1.tar.gz https://github.com/TileDB-Inc/TileDB/archive/refs/tags/1.3.1.tar.gz && \ -sudo curl -L -o zlib-1.2.13.tar.gz http://zlib.net/zlib-1.2.13.tar.gz +#### Python3 Packages +Here we will install the necessary Python3 packages Numpy and Protobuf 3.20.3. +You can also install the coverage package if interested in running the Python unit tests. +```bash +PROTOBUF_VERSION="3.20.3" +pip3 install --no-cache-dir "numpy>=1.25.1" "protobuf==${PROTOBUF_VERSION}" "coverage>=7.2.7" ``` -### Install Dependencies -These instructions assume you have full permissions to your system. -If running as root, remove `sudo` where necessary. -#### CMAKE +#### CMAKE v3.26.4 +VDMS requires CMake v3.21+. Here we install CMake v3.26.4. ```bash -cd $VDMS_DEP_DIR/CMake && ./bootstrap -make -j && sudo make install +CMAKE_VERSION="v3.26.4" +git clone --branch ${CMAKE_VERSION} https://github.com/Kitware/CMake.git $VDMS_DEP_DIR/CMake +cd $VDMS_DEP_DIR/CMake +./bootstrap +make ${BUILD_THREADS} +make install ``` -### Swig +### gtest +Unfortunately apt doesn't build gtest so you need to do the following: ```bash -cd $VDMS_DEP_DIR/swig -./autogen.sh && ./configure -make -j && sudo make install +cd /usr/src/gtest/ +cmake . +make ${BUILD_THREADS} +mv lib/libgtest* /usr/lib ``` -### Faiss +### Faiss v1.7.3 ```bash +FAISS_VERSION="v1.7.3" +git clone --branch ${FAISS_VERSION} https://github.com/facebookresearch/faiss.git $VDMS_DEP_DIR/faiss cd $VDMS_DEP_DIR/faiss mkdir build && cd build cmake -DFAISS_ENABLE_GPU=OFF .. -make -j && sudo make install +make ${BUILD_THREADS} +make install ``` ### FLINNG ```bash +git clone https://github.com/tonyzhang617/FLINNG.git $VDMS_DEP_DIR/FLINNG cd $VDMS_DEP_DIR/FLINNG mkdir build && cd build cmake .. -make -j && sudo make install +make ${BUILD_THREADS} +make install ``` -### grpc +### Protobuf 3.20.3 ```bash -cd $VDMS_DEP_DIR/grpc -pip install --no-cache-dir -r requirements.txt -GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install --no-cache-dir . - -cd tools/distrib/python/grpcio_tools -python ../make_grpcio_tools.py -GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install --no-cache-dir . - -cd $VDMS_DEP_DIR/grpc/third_party/zlib/ && mkdir build && cd build -cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE .. -make -j && sudo make install - -cd $VDMS_DEP_DIR/grpc/third_party/protobuf/cmake -mkdir build && cd build -cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -Dprotobuf_BUILD_TESTS=OFF .. -make -j && sudo make install - -cd ../../../abseil-cpp && mkdir build && cd build -cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE .. -make -j && sudo make install - -cd ../../re2/ && mkdir build && cd build -cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE .. -make -j && sudo make install - -cd $VDMS_DEP_DIR/grpc/cmake && mkdir build && cd build -cmake -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DgRPC_ABSL_PROVIDER=package \ - -DgRPC_CARES_PROVIDER=package -DgRPC_PROTOBUF_PROVIDER=package \ - -DgRPC_RE2_PROVIDER=package -DgRPC_SSL_PROVIDER=package \ - -DgRPC_ZLIB_PROVIDER=package -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ../.. -make -j && sudo make install +PROTOBUF_VERSION="3.20.3" +curl -L -o ${VDMS_DEP_DIR}/${PROTOBUF_VERSION}.tar.gz https://github.com/protocolbuffers/protobuf/archive/refs/tags/v${PROTOBUF_VERSION}.tar.gz +cd ${VDMS_DEP_DIR} && tar -xvf ${PROTOBUF_VERSION}.tar.gz +cd protobuf-${PROTOBUF_VERSION} +./autogen.sh +./configure +make ${BUILD_THREADS} +make install +ldconfig ``` -### [OpenCV](https://opencv.org/) - -Below are instructions for installing ***OpenCV v4.5.3***. It may also work with newer versions of OpenCV. +### [OpenCV](https://opencv.org/) 4.5.5 +Below are instructions for installing ***OpenCV v4.5.5***. ```bash +OPENCV_VERSION="4.5.5" +git clone --branch ${OPENCV_VERSION} https://github.com/opencv/opencv.git $VDMS_DEP_DIR/opencv cd $VDMS_DEP_DIR/opencv mkdir build && cd build -cmake -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF .. -make -j -sudo make install +cmake -D BUILD_PERF_TESTS=OFF -D BUILD_TESTS=OFF .. +make ${BUILD_THREADS} +make install ``` **Note**: When using videos, and getting the following error: "Unable to stop the stream: Inappropriate ioctl for device", you may need to include more flags when compiling OpenCV. Follow these instructions ([source](https://stackoverflow.com/questions/41200201/opencv-unable-to-stop-the-stream-inappropriate-ioctl-for-device)): @@ -124,51 +120,51 @@ cmake -D BUILD_PERF_TESTS=OFF -D BUILD_TESTS=OFF -D CMAKE_BUILD_TYPE=RELEASE -D -D WITH_FFMPEG=ON -D WITH_TBB=ON -D WITH_GTK=ON \ -D WITH_V4L=ON -D WITH_OPENGL=ON -D WITH_CUBLAS=ON \ -DWITH_QT=OFF -DCUDA_NVCC_FLAGS="-D_FORCE_INLINES" .. -make -j +make ${BUILD_THREADS} make install ``` -### Zlib +### Valijson v0.6 +This is a headers-only library, no compilation/installation necessary ```bash -cd $VDMS_DEP_DIR && tar -xvzf zlib-1.2.13.tar.gz -cd zlib-1.2.13 && ./configure -make -j && sudo make install +VALIJSON_VERSION="v0.6" +git clone --branch ${VALIJSON_VERSION} https://github.com/tristanpenman/valijson.git $VDMS_DEP_DIR/valijson +cd $VDMS_DEP_DIR/valijson +cp -r include/* /usr/local/include/ ``` -### [TileDB](https://tiledb.io/) -VDMS works with ***TileDB v1.3.1.***
-The directions below will help you install TileDB v1.3.1 from the source. -You can also follow the directions listed -[here](https://docs.tiledb.io/en/latest/installation.html). -```bash -cd $VDMS_DEP_DIR && tar -xvf 1.3.1.tar.gz -cd TileDB-1.3.1 && mkdir build && cd build -../bootstrap --prefix=/usr/local/ -make -j && sudo make install-tiledb -``` -### gtest -Unfortunately apt doesn't build gtest; -you need to do the following steps to get it to work correctly: +### [TileDB](https://tiledb.io/) 2.14.1 +The directions below will help you install TileDB v2.14.1 from the source. +You can also follow the directions listed [here](https://docs.tiledb.io/en/latest/installation.html). ```bash -cd /usr/src/gtest/ -sudo cmake . -sudo make -j -sudo mv lib/libgtest* /usr/lib +TILEDB_VERSION="2.14.1" +curl -L -o $VDMS_DEP_DIR/${TILEDB_VERSION}.tar.gz https://github.com/TileDB-Inc/TileDB/archive/refs/tags/${TILEDB_VERSION}.tar.gz && \ +cd $VDMS_DEP_DIR +tar -xvf ${TILEDB_VERSION}.tar.gz +cd TileDB-${TILEDB_VERSION} +mkdir build && cd build +../bootstrap --prefix=/usr/local/ +make ${BUILD_THREADS} +make install-tiledb ``` -### Valijson -This is a headers-only library, no compilation/installation necessary +### AWS SDK CPP 1.11.0 ```bash -cd $VDMS_DEP_DIR/valijson -sudo cp -r include/* /usr/local/include +AWS_SDK_VERSION="1.11.0" +git clone -b ${AWS_SDK_VERSION} --recurse-submodules https://github.com/aws/aws-sdk-cpp ${VDMS_DEP_DIR}/aws-sdk-cpp +mkdir -p ${VDMS_DEP_DIR}/aws-sdk-cpp/build +cd ${VDMS_DEP_DIR}/aws-sdk-cpp/build +cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local/ -DCMAKE_INSTALL_PREFIX=/usr/local/ -DBUILD_ONLY="s3" -DCUSTOM_MEMORY_MANAGEMENT=OFF +make ${BUILD_THREADS} +make install ``` ## Install VDMS This version of VDMS treats PMGD as a submodule so both libraries are compiled at one time. After entering the vdms directory, the command `git submodule update --init --recursive` will pull pmgd into the appropriate directory. Furthermore, Cmake is used to compile all directories. ```bash -git clone https://github.com/IntelLabs/vdms.git -cd vdms && git checkout develop +git clone -b develop https://github.com/IntelLabs/vdms.git +cd vdms git submodule update --init --recursive ``` @@ -186,3 +182,4 @@ mkdir build && cd build cmake -DCMAKE_CXX_FLAGS='-DPM' .. make -j ``` + diff --git a/client/cpp/BoundingBoxQueryParser.h b/client/cpp/BoundingBoxQueryParser.h index 77928157..7ba8d075 100644 --- a/client/cpp/BoundingBoxQueryParser.h +++ b/client/cpp/BoundingBoxQueryParser.h @@ -1,88 +1,92 @@ #include "CSVParserUtil.h" namespace VDMS { -class BoundingBoxQueryParser : public CSVParserUtil{ - private: - vector rectangleKeys{"x","y","w","h"}; - void parseRectangle(string row,string queryType,Json::Value &aquery); - public: - VDMS::Response ParseAddBoundingBox(vector row, vector cols); - // VDMS::Response ParseUpdateBoundingBox(vector row, vector& cols); +class BoundingBoxQueryParser : public CSVParserUtil { +private: + vector rectangleKeys{"x", "y", "w", "h"}; + void parseRectangle(string row, string queryType, Json::Value &aquery); +public: + VDMS::Response ParseAddBoundingBox(vector row, vector cols); + // VDMS::Response ParseUpdateBoundingBox(vector row, vector& + // cols); }; -}; +}; // namespace VDMS -VDMS::Response VDMS::BoundingBoxQueryParser::ParseAddBoundingBox(vector row, vector columnNames){ - if (row.empty() || row[0].empty()) { - throw "please provide rectangle details"; - } +VDMS::Response +VDMS::BoundingBoxQueryParser::ParseAddBoundingBox(vector row, + vector columnNames) { + if (row.empty() || row[0].empty()) { + throw "please provide rectangle details"; + } - Json::Value aquery; - Json::Value allquery; - std::string command_name = "AddBoundingBox"; + Json::Value aquery; + Json::Value allquery; + std::string command_name = "AddBoundingBox"; - aquery["AddBoundingBox"]["_ref"] = 1; - // aquery["AddBoundingBox"]["image"] = 3; + aquery["AddBoundingBox"]["_ref"] = 1; + // aquery["AddBoundingBox"]["image"] = 3; - Json::Value aqueryf; - // aqueryf["FindImage"]["_ref"] = 3; - bool cons = false; + Json::Value aqueryf; + // aqueryf["FindImage"]["_ref"] = 3; + bool cons = false; - parseRectangle(row[0], "AddBoundingBox", aquery); + parseRectangle(row[0], "AddBoundingBox", aquery); - for (int j = 1; j < columnNames.size(); j++){ - const string& columnName = columnNames[j]; - const string& cellValue = row[j]; + for (int j = 1; j < columnNames.size(); j++) { + const string &columnName = columnNames[j]; + const string &cellValue = row[j]; - if (cellValue.empty()) { - continue; - } + if (cellValue.empty()) { + continue; + } - if (columnName.find("prop_") != string::npos){ - parseProperty(columnName, cellValue, command_name, aquery); - } - else if (columnName.find("cons_") != string::npos){ - std::string find_image = "FindImage"; - parseConstraints(columnName, cellValue, find_image, aqueryf); - cons = true; - } + if (columnName.find("prop_") != string::npos) { + parseProperty(columnName, cellValue, command_name, aquery); + } else if (columnName.find("cons_") != string::npos) { + std::string find_image = "FindImage"; + parseConstraints(columnName, cellValue, find_image, aqueryf); + cons = true; } + } - if (cons) - allquery.append(aqueryf); + if (cons) + allquery.append(aqueryf); - allquery.append(aquery); - // std::cout< row, vector& columnNames){ +// VDMS::Response +// VDMS::BoundingBoxQueryParser::ParseUpdateBoundingBox(vector row, +// vector& columnNames){ // Json::Value aquery; // Json::Value allquery; // aquery["UpdateBoundingBox"]["_ref"]=3; diff --git a/client/cpp/CSVParser.h b/client/cpp/CSVParser.h index eac01aee..401ae8f1 100644 --- a/client/cpp/CSVParser.h +++ b/client/cpp/CSVParser.h @@ -1,73 +1,79 @@ -#include +#include "CSVParserUtil.h" +#include "rapidcsv.h" #include -#include +#include +#include #include #include -#include -#include "rapidcsv.h" -#include "CSVParserUtil.h" +#include namespace VDMS { class CSVParser { public: - CSVParser(std::string filename, size_t num_threads, std::string server, int port) : m_filename(filename), m_num_threads(num_threads),vdms_server(server),vdms_port(port) {} - std::vector parse_csv_lines(const std::string& filename, int start_line, int end_line, std::mutex& mutex, std::vector& all_results, const size_t thread_id) - { + CSVParser(std::string filename, size_t num_threads, std::string server, + int port) + : m_filename(filename), m_num_threads(num_threads), vdms_server(server), + vdms_port(port) {} + std::vector + parse_csv_lines(const std::string &filename, int start_line, int end_line, + std::mutex &mutex, std::vector &all_results, + const size_t thread_id) { rapidcsv::Document csv(filename); size_t rowCount = csv.GetRowCount(); std::vector columnNames = csv.GetColumnNames(); - VDMS::CSVParserUtil csv_util(vdms_server, vdms_port, columnNames, static_cast(thread_id)); - for (int i = start_line; i < end_line; ++i) - { - std::vector row = csv.GetRow(i); - VDMS::Response result = csv_util.parse_row(row); + VDMS::CSVParserUtil csv_util(vdms_server, vdms_port, columnNames, + static_cast(thread_id)); + for (int i = start_line; i < end_line; ++i) { + std::vector row = csv.GetRow(i); + VDMS::Response result = csv_util.parse_row(row); - std::lock_guard lock(mutex); - all_results.push_back(result); + std::lock_guard lock(mutex); + all_results.push_back(result); } return all_results; } -std::vector parse() { - auto start = std::chrono::high_resolution_clock::now(); + std::vector parse() { + auto start = std::chrono::high_resolution_clock::now(); - std::ifstream file(m_filename); - if (!file) { - std::cerr << "Error opening file\n"; - - } - - int num_lines = std::count(std::istreambuf_iterator(file), std::istreambuf_iterator(), '\n'); - std::size_t lines_per_thread = num_lines / m_num_threads; - - std::mutex mutex; - std::vector threads; - std::vector all_results; + std::ifstream file(m_filename); + if (!file) { + std::cerr << "Error opening file\n"; + } - for (size_t i = 0; i < m_num_threads; i++) { - size_t start_line = i * lines_per_thread; - size_t end_line = (i == m_num_threads - 1) ? num_lines-1 : (i + 1) * lines_per_thread; + int num_lines = std::count(std::istreambuf_iterator(file), + std::istreambuf_iterator(), '\n'); + std::size_t lines_per_thread = num_lines / m_num_threads; - threads.emplace_back(&CSVParser::parse_csv_lines, this, std::ref(m_filename), start_line, end_line, std::ref(mutex),std::ref(all_results), i); - } + std::mutex mutex; + std::vector threads; + std::vector all_results; - for (auto& thread : threads) { - thread.join(); - } + for (size_t i = 0; i < m_num_threads; i++) { + size_t start_line = i * lines_per_thread; + size_t end_line = + (i == m_num_threads - 1) ? num_lines - 1 : (i + 1) * lines_per_thread; - auto finish = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = finish - start; - //std::cout << "Elapsed time: " << elapsed.count() << " s\n"; - return all_results; + threads.emplace_back(&CSVParser::parse_csv_lines, this, + std::ref(m_filename), start_line, end_line, + std::ref(mutex), std::ref(all_results), i); } -private: - std::string m_filename; - size_t m_num_threads; - std::string vdms_server; - int vdms_port; + for (auto &thread : threads) { + thread.join(); + } + auto finish = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = finish - start; + // std::cout << "Elapsed time: " << elapsed.count() << " s\n"; + return all_results; + } - }; -}; \ No newline at end of file +private: + std::string m_filename; + size_t m_num_threads; + std::string vdms_server; + int vdms_port; +}; +}; // namespace VDMS \ No newline at end of file diff --git a/client/cpp/CSVParserUtil.cpp b/client/cpp/CSVParserUtil.cpp index 298345c5..d5b10dbe 100644 --- a/client/cpp/CSVParserUtil.cpp +++ b/client/cpp/CSVParserUtil.cpp @@ -1,15 +1,15 @@ -#include -#include #include "CSVParserUtil.h" -#include "rapidcsv.h" +#include "BoundingBoxQueryParser.h" +#include "ConnectionQueryParser.h" +#include "DescriptorQueryParser.h" +#include "DescriptorSetQueryParser.h" #include "EntityQueryParser.h" #include "ImageQueryParser.h" #include "VideoQueryParser.h" -#include "DescriptorQueryParser.h" -#include "DescriptorSetQueryParser.h" -#include "BoundingBoxQueryParser.h" -#include "ConnectionQueryParser.h" +#include "rapidcsv.h" +#include +#include #include static std::mutex barrier; std::mutex mtx; @@ -17,619 +17,531 @@ using namespace std; using namespace std::chrono; using namespace VDMS; -VDMS::CSVParserUtil::CSVParserUtil() : vdms_server("localhost"), vdms_port(55558), - vdms_client(std::unique_ptr(new VDMS::VDMSClient(vdms_server, vdms_port))) -{ - initCommandsMap(); +VDMS::CSVParserUtil::CSVParserUtil() + : vdms_server("localhost"), vdms_port(55558), + vdms_client(std::unique_ptr( + new VDMS::VDMSClient(vdms_server, vdms_port))) { + initCommandsMap(); } -VDMS::CSVParserUtil::CSVParserUtil(const std::string &server, int port, const std::vector columnNames, int index) : vdms_server(server), - vdms_port(port), - _columnNames(columnNames), - id(index), vdms_client(std::unique_ptr(new VDMS::VDMSClient(vdms_server, vdms_port))) -{ - initCommandsMap(); +VDMS::CSVParserUtil::CSVParserUtil(const std::string &server, int port, + const std::vector columnNames, + int index) + : vdms_server(server), vdms_port(port), _columnNames(columnNames), + id(index), vdms_client(std::unique_ptr( + new VDMS::VDMSClient(vdms_server, vdms_port))) { + initCommandsMap(); } -void VDMS::CSVParserUtil::initCommandsMap() -{ - commands = { - {"EntityClass", EntityClass}, - {"ConnectionClass", ConnectionClass}, - {"ImagePath", ImagePath}, - {"VideoPath", VideoPath}, - {"DescriptorType", DescriptorType}, - {"DescriptorClass", DescriptorClass}, - {"RectangleBound", RectangleBound}, - {"EntityUpdate", EntityUpdate}, - {"ConnectionUpdate", ConnectionUpdate}, - {"ImageUpdate", ImageUpdate}, - {"RectangleUpdate", RectangleUpdate}}; +void VDMS::CSVParserUtil::initCommandsMap() { + commands = {{"EntityClass", EntityClass}, + {"ConnectionClass", ConnectionClass}, + {"ImagePath", ImagePath}, + {"VideoPath", VideoPath}, + {"DescriptorType", DescriptorType}, + {"DescriptorClass", DescriptorClass}, + {"RectangleBound", RectangleBound}, + {"EntityUpdate", EntityUpdate}, + {"ConnectionUpdate", ConnectionUpdate}, + {"ImageUpdate", ImageUpdate}, + {"RectangleUpdate", RectangleUpdate}}; } -string VDMS::CSVParserUtil::function_accessing_columnNames(int i) -{ - std::lock_guard lock(mtx); +string VDMS::CSVParserUtil::function_accessing_columnNames(int i) { + std::lock_guard lock(mtx); - return _columnNames[i]; + return _columnNames[i]; } -VDMS::Response VDMS::CSVParserUtil::parse_row(std::vector &row) -{ - VDMS::Response result; - - VDMS::CSVParserUtil::commandType queryType = get_query_type(_columnNames[0]); - switch (queryType) - { - case commandType::AddEntity: - { - EntityQueryParser entityquery; - result = entityquery.ParseAddEntity(row, _columnNames); - } - - break; - case commandType::AddConnection: - { - - ConnectionQueryParser connectionquery; - result = connectionquery.ParseAddConnection(row, _columnNames); - } - break; - - case commandType::AddImage: - { - ImageQueryParser imagequery; - result = imagequery.ParseAddImage(row, _columnNames); - } - break; - case commandType::AddVideo: - { - VideoQueryParser videoquery; - result = videoquery.ParseAddVideo(row, _columnNames); - } - break; - case commandType::AddDescriptorSet: - { - DescriptorSetQueryParser descriptorsetquery; - - result = descriptorsetquery.ParseAddDescriptorSet(row, _columnNames); - } - break; - case commandType::AddDescriptor: - { - DescriptorQueryParser descriptorquery; - result = descriptorquery.ParseAddDescriptor(row, _columnNames, id); - } - break; - case commandType::AddBoundingBox: - { - BoundingBoxQueryParser boundingboxquery; - result = boundingboxquery.ParseAddBoundingBox(row, _columnNames); - } - break; - // case commandType::UpdateEntity:{ - // EntityQueryParser update_entityquery; - // update_entityquery.ParseUpdateEntity(row, _columnNames); - // } - // break; - // case commandType::UpdateConnection:{ - // ConnectionQueryParser update_connectionquery; - // update_connectionquery.ParseUpdateConnection(row,allquery,i+1,_columnNames); - // } - // break; - // case commandType::UpdateImage:{ - // ImageQueryParser update_image_query; - // update_image_query.ParseUpdateImage(row,allquery,i+1,_columnNames); - // } - // break; - // case commandType::UpdateBoundingBox:{ - // BoundingBoxQueryParser update_boundingboxquery; - // update_boundingboxquery.ParseUpdateBoundingBox(row,allquery,i+1,_columnNames); - // } - // break; - case commandType::UNKNOWN:{ - Json::Value results; - results["status"] = -1; - results["info"] = "Command does not exist"; - result.json = results.toStyledString(); - } - break; - } - return result; +VDMS::Response VDMS::CSVParserUtil::parse_row(std::vector &row) { + VDMS::Response result; + + VDMS::CSVParserUtil::commandType queryType = get_query_type(_columnNames[0]); + switch (queryType) { + case commandType::AddEntity: { + EntityQueryParser entityquery; + result = entityquery.ParseAddEntity(row, _columnNames); + } + + break; + case commandType::AddConnection: { + + ConnectionQueryParser connectionquery; + result = connectionquery.ParseAddConnection(row, _columnNames); + } break; + + case commandType::AddImage: { + ImageQueryParser imagequery; + result = imagequery.ParseAddImage(row, _columnNames); + } break; + case commandType::AddVideo: { + VideoQueryParser videoquery; + result = videoquery.ParseAddVideo(row, _columnNames); + } break; + case commandType::AddDescriptorSet: { + DescriptorSetQueryParser descriptorsetquery; + + result = descriptorsetquery.ParseAddDescriptorSet(row, _columnNames); + } break; + case commandType::AddDescriptor: { + DescriptorQueryParser descriptorquery; + result = descriptorquery.ParseAddDescriptor(row, _columnNames, id); + } break; + case commandType::AddBoundingBox: { + BoundingBoxQueryParser boundingboxquery; + result = boundingboxquery.ParseAddBoundingBox(row, _columnNames); + } break; + // case commandType::UpdateEntity:{ + // EntityQueryParser update_entityquery; + // update_entityquery.ParseUpdateEntity(row, _columnNames); + // } + // break; + // case commandType::UpdateConnection:{ + // ConnectionQueryParser update_connectionquery; + // update_connectionquery.ParseUpdateConnection(row,allquery,i+1,_columnNames); + // } + // break; + // case commandType::UpdateImage:{ + // ImageQueryParser update_image_query; + // update_image_query.ParseUpdateImage(row,allquery,i+1,_columnNames); + // } + // break; + // case commandType::UpdateBoundingBox:{ + // BoundingBoxQueryParser update_boundingboxquery; + // update_boundingboxquery.ParseUpdateBoundingBox(row,allquery,i+1,_columnNames); + // } + // break; + case commandType::UNKNOWN: { + Json::Value results; + results["status"] = -1; + results["info"] = "Command does not exist"; + result.json = results.toStyledString(); + } break; + } + return result; } -int VDMS::CSVParserUtil::isBool(const std::string &s) -{ - std::string lower = s; - std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); - if (lower == "true") - return 1; - else if (lower == "false") - return 2; - return 0; +int VDMS::CSVParserUtil::isBool(const std::string &s) { + std::string lower = s; + std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); + if (lower == "true") + return 1; + else if (lower == "false") + return 2; + return 0; } -bool VDMS::CSVParserUtil::isFloat(const std::string &s) -{ - std::istringstream ss(s); - float x; - char c; - return (ss >> x) && !(ss >> c); +bool VDMS::CSVParserUtil::isFloat(const std::string &s) { + std::istringstream ss(s); + float x; + char c; + return (ss >> x) && !(ss >> c); } -bool VDMS::CSVParserUtil::isInt(const std::string &s) -{ - std::istringstream ss(s); - int x; - char c; - return (ss >> x) && (floor(x)) && !(ss >> c); +bool VDMS::CSVParserUtil::isInt(const std::string &s) { + std::istringstream ss(s); + int x; + char c; + return (ss >> x) && (floor(x)) && !(ss >> c); } -VDMS::CSVParserUtil::commandType VDMS::CSVParserUtil::get_query_type(const string &str) -{ - CSVParserUtil::commandType querytype = commandType::UNKNOWN; - - std::lock_guard lock(CSVParserUtil::querytype_mutex); - std::map::iterator iter; - iter = commands.find(str); - if (iter != commands.end()) { - switch (commands[str]) - { - case EntityClass: - querytype = commandType::AddEntity; - break; - case ConnectionClass: - querytype = commandType::AddConnection; - break; - case ImagePath: - querytype = commandType::AddImage; - break; - case VideoPath: - querytype = commandType::AddVideo; - break; - case DescriptorType: - querytype = commandType::AddDescriptorSet; - break; - case DescriptorClass: - querytype = commandType::AddDescriptor; - break; - case RectangleBound: - querytype = commandType::AddBoundingBox; - break; - } - // std::cout << " I executed queryType "<< querytype << std::endl; - // return querytype; - } - - return querytype; +VDMS::CSVParserUtil::commandType +VDMS::CSVParserUtil::get_query_type(const string &str) { + CSVParserUtil::commandType querytype = commandType::UNKNOWN; + + std::lock_guard lock(CSVParserUtil::querytype_mutex); + std::map::iterator iter; + iter = commands.find(str); + if (iter != commands.end()) { + switch (commands[str]) { + case EntityClass: + querytype = commandType::AddEntity; + break; + case ConnectionClass: + querytype = commandType::AddConnection; + break; + case ImagePath: + querytype = commandType::AddImage; + break; + case VideoPath: + querytype = commandType::AddVideo; + break; + case DescriptorType: + querytype = commandType::AddDescriptorSet; + break; + case DescriptorClass: + querytype = commandType::AddDescriptor; + break; + case RectangleBound: + querytype = commandType::AddBoundingBox; + break; + } + // std::cout << " I executed queryType "<< querytype << std::endl; + // return querytype; + } + + return querytype; } -VDMS::CSVParserUtil::DATATYPE VDMS::CSVParserUtil::getDataType(const string &str, const string &propname) -{ - if (propname.substr(0, 5) == "date:") - return DATATYPE::DATE; - else if (isInt(str)) - return DATATYPE::INTEGER; - else if (isFloat(str)) - return DATATYPE::FLOAT; - else if (isBool(str) == 1) - return DATATYPE::TRUE; - else if (isBool(str) == 2) - return DATATYPE::FALSE; - else - return DATATYPE::STRING; +VDMS::CSVParserUtil::DATATYPE +VDMS::CSVParserUtil::getDataType(const string &str, const string &propname) { + if (propname.substr(0, 5) == "date:") + return DATATYPE::DATE; + else if (isInt(str)) + return DATATYPE::INTEGER; + else if (isFloat(str)) + return DATATYPE::FLOAT; + else if (isBool(str) == 1) + return DATATYPE::TRUE; + else if (isBool(str) == 2) + return DATATYPE::FALSE; + else + return DATATYPE::STRING; } -void VDMS::CSVParserUtil::parseProperty(const string &columnNames, const string &row, const string &queryType, Json::Value &aquery) -{ - std::lock_guard lock(CSVParserUtil::aquery_mutex); - string propname = columnNames.substr(5, string::npos); - // std::cout << "Inside parseProp " << propname < lock(CSVParserUtil::aquery_mutex); + string propname = columnNames.substr(5, string::npos); + // std::cout << "Inside parseProp " << propname < lock(CSVParserUtil::cons_mutex); - vector consvals = spiltrow(row); - string consname = consvals[0]; - if (consname.substr(0, 5) == "date:") - { - for (int z = 1; z < consvals.size(); z++) - { - if (z % 2 == 1) - { - aquery[queryType]["constraints"][consname.substr(5, string::npos)].append(consvals[z]); - } - else - { - Json::Value date; - date["_date"] = consvals[z]; - aquery[queryType]["constraints"][consname.substr(5, string::npos)].append(date); - } - } - } - else - { - for (int z = 1; z < consvals.size(); z++) - { - CSVParserUtil::DATATYPE dtype = getDataType(consvals[z], consname); - if (dtype == DATATYPE::TRUE) - { - aquery[queryType]["constraints"][consname].append(true); - } - else if (dtype == DATATYPE::FALSE) - { - aquery[queryType]["constraints"][consname].append(false); - } - else if (dtype == DATATYPE::INTEGER) - { - aquery[queryType]["constraints"][consname].append(stoi(consvals[z])); - } - else if (dtype == DATATYPE::FLOAT) - { - aquery[queryType]["constraints"][consname].append(stof(consvals[z])); - } - else - { - aquery[queryType]["constraints"][consname].append(consvals[z]); - } - } - } +void VDMS::CSVParserUtil::parseConstraints(const string &columnNames, + const string &row, string &queryType, + Json::Value &aquery) { + std::lock_guard lock(CSVParserUtil::cons_mutex); + vector consvals = spiltrow(row); + string consname = consvals[0]; + if (consname.substr(0, 5) == "date:") { + for (int z = 1; z < consvals.size(); z++) { + if (z % 2 == 1) { + aquery[queryType]["constraints"][consname.substr(5, string::npos)] + .append(consvals[z]); + } else { + Json::Value date; + date["_date"] = consvals[z]; + aquery[queryType]["constraints"][consname.substr(5, string::npos)] + .append(date); + } + } + } else { + for (int z = 1; z < consvals.size(); z++) { + CSVParserUtil::DATATYPE dtype = getDataType(consvals[z], consname); + if (dtype == DATATYPE::TRUE) { + aquery[queryType]["constraints"][consname].append(true); + } else if (dtype == DATATYPE::FALSE) { + aquery[queryType]["constraints"][consname].append(false); + } else if (dtype == DATATYPE::INTEGER) { + aquery[queryType]["constraints"][consname].append(stoi(consvals[z])); + } else if (dtype == DATATYPE::FLOAT) { + aquery[queryType]["constraints"][consname].append(stof(consvals[z])); + } else { + aquery[queryType]["constraints"][consname].append(consvals[z]); + } + } + } } -vector VDMS::CSVParserUtil::spiltrow(const string &str) -{ - string row = str; - vector rowv; - int start = 0; - for (int i = 0; i < row.size(); i++) - { - if ((row[i] == '<') || (row[i] == '>') || (row[i] == '=')) - { - if (row[i + 1] == '=') - { - rowv.push_back(row.substr(start, i - start)); - rowv.push_back(row.substr(i, 2)); - i++; - } - else - { - rowv.push_back(row.substr(start, i - start)); - rowv.push_back(row.substr(i, 1)); - } - start = i + 1; - } - else if (row[i] == ',') - { - row.erase(i, 1); - i--; - } - } - rowv.push_back(row.substr(start, string::npos)); - return rowv; +vector VDMS::CSVParserUtil::spiltrow(const string &str) { + string row = str; + vector rowv; + int start = 0; + for (int i = 0; i < row.size(); i++) { + if ((row[i] == '<') || (row[i] == '>') || (row[i] == '=')) { + if (row[i + 1] == '=') { + rowv.push_back(row.substr(start, i - start)); + rowv.push_back(row.substr(i, 2)); + i++; + } else { + rowv.push_back(row.substr(start, i - start)); + rowv.push_back(row.substr(i, 1)); + } + start = i + 1; + } else if (row[i] == ',') { + row.erase(i, 1); + i--; + } + } + rowv.push_back(row.substr(start, string::npos)); + return rowv; } -void VDMS::CSVParserUtil::parseOperations(string columnNames, string row, string queryType, Json::Value &aquery) -{ - - std::lock_guard lock(CSVParserUtil::ops_mutex); - string type = columnNames.substr(4, string::npos); - Json::Value opsjson; - vector opsKeys; - if (isValidOpsType(type)) - opsjson["type"] = type; - else - throw "invalid operation command name"; - vector rowvec; - int c; - splitRowOnComma(row, rowvec); - if (type == "crop") - { - if (rowvec.size() <= 3 || rowvec.size() > 4) - throw "For crop data should be of size 4"; - opsKeys = {"x", "y", "width", "height"}; - for (c = 0; c < rowvec.size(); c++) - { - string substr = rowvec[c]; - DATATYPE dType = isValidDataType(substr, 2); - - if (dType == DATATYPE::INTEGER) - opsjson[opsKeys[c]] = stoi(substr); - else if (dType == DATATYPE::FLOAT) - opsjson[opsKeys[c]] = stof(substr); - - else - { - throw "Numeric data is required for crop command"; - } - } - } - - else if (type == "threshold") - { - DATATYPE dType = isValidDataType(row, 2); +void VDMS::CSVParserUtil::parseOperations(string columnNames, string row, + string queryType, + Json::Value &aquery) { + + std::lock_guard lock(CSVParserUtil::ops_mutex); + string type = columnNames.substr(4, string::npos); + Json::Value opsjson; + vector opsKeys; + if (isValidOpsType(type)) + opsjson["type"] = type; + else + throw "invalid operation command name"; + vector rowvec; + int c; + splitRowOnComma(row, rowvec); + if (type == "crop") { + if (rowvec.size() <= 3 || rowvec.size() > 4) + throw "For crop data should be of size 4"; + opsKeys = {"x", "y", "width", "height"}; + for (c = 0; c < rowvec.size(); c++) { + string substr = rowvec[c]; + DATATYPE dType = isValidDataType(substr, 2); + + if (dType == DATATYPE::INTEGER) + opsjson[opsKeys[c]] = stoi(substr); + else if (dType == DATATYPE::FLOAT) + opsjson[opsKeys[c]] = stof(substr); + + else { + throw "Numeric data is required for crop command"; + } + } + } + + else if (type == "threshold") { + DATATYPE dType = isValidDataType(row, 2); + if (dType == DATATYPE::INTEGER) + opsjson["value"] = stoi(row); + else if (dType == DATATYPE::FLOAT) + opsjson["value"] = stof(row); + + else { + throw "Numeric data is required for threshold command"; + } + } + + else if (type == "resize") { + if (rowvec.size() <= 1 || rowvec.size() > 2) + throw "For resize data should be of size 2"; + opsKeys = {"width", "height"}; + for (c = 0; c < rowvec.size(); c++) { + string substr = rowvec[c]; + DATATYPE dType = isValidDataType(substr, 2); + + if (dType == DATATYPE::INTEGER) + opsjson[opsKeys[c]] = stoi(substr); + else if (dType == DATATYPE::FLOAT) + opsjson[opsKeys[c]] = stof(substr); + + else { + throw "Numeric data is required for resize command"; + } + } + } + + else if (type == "flip") { + DATATYPE dType = isValidDataType(row, 2); + if (dType == DATATYPE::INTEGER) { + opsjson["code"] = stoi(row); + } else { + throw "Numeric data is required for flip command"; + } + } + + else if (type == "rotate") { + if (rowvec.size() <= 1 || rowvec.size() > 2) + throw "For rotate data should be of size 2"; + opsKeys = {"angle", "resize"}; + for (c = 0; c < rowvec.size(); c++) { + string substr = rowvec[c]; + if (c == 0) { + DATATYPE dType = isValidDataType(substr, 2); if (dType == DATATYPE::INTEGER) - opsjson["value"] = stoi(row); + opsjson[opsKeys[c]] = stoi(substr); else if (dType == DATATYPE::FLOAT) - opsjson["value"] = stof(row); - - else - { - throw "Numeric data is required for threshold command"; - } - } + opsjson[opsKeys[c]] = stof(substr); - else if (type == "resize") - { - if (rowvec.size() <= 1 || rowvec.size() > 2) - throw "For resize data should be of size 2"; - opsKeys = {"width", "height"}; - for (c = 0; c < rowvec.size(); c++) - { - string substr = rowvec[c]; - DATATYPE dType = isValidDataType(substr, 2); - - if (dType == DATATYPE::INTEGER) - opsjson[opsKeys[c]] = stoi(substr); - else if (dType == DATATYPE::FLOAT) - opsjson[opsKeys[c]] = stof(substr); - - else - { - throw "Numeric data is required for resize command"; - } + else { + throw "Numeric data is required for rotate angle"; } - } - - else if (type == "flip") - { - DATATYPE dType = isValidDataType(row, 2); - if (dType == DATATYPE::INTEGER) - { - opsjson["code"] = stoi(row); - } - else - { - throw "Numeric data is required for flip command"; - } - } - - else if (type == "rotate") - { - if (rowvec.size() <= 1 || rowvec.size() > 2) - throw "For rotate data should be of size 2"; - opsKeys = {"angle", "resize"}; - for (c = 0; c < rowvec.size(); c++) - { - string substr = rowvec[c]; - if (c == 0) - { - DATATYPE dType = isValidDataType(substr, 2); - if (dType == DATATYPE::INTEGER) - opsjson[opsKeys[c]] = stoi(substr); - else if (dType == DATATYPE::FLOAT) - opsjson[opsKeys[c]] = stof(substr); - - else - { - throw "Numeric data is required for rotate angle"; - } - } - else if (c == 1) - { - DATATYPE dType = isValidDataType(substr, 1); - if (dType == DATATYPE::TRUE) - opsjson[opsKeys[c]] = true; - else if (dType == DATATYPE::FALSE) - opsjson[opsKeys[c]] = false; - - else - { - throw "Boolean data is required for rotate resize"; - } - } - } - } - - else if (type == "interval") - { - if (rowvec.size() <= 2 || rowvec.size() > 3) - throw "interval operation has 3 values to specify"; - opsKeys = {"start", "stop", "step"}; - for (c = 0; c < rowvec.size(); c++) - { - string substr = rowvec[c]; - DATATYPE dType = isValidDataType(substr, 2); - if (dType == DATATYPE::INTEGER) - { - opsjson[opsKeys[c]] = stoi(substr); - } - else - { - throw "Numeric datatype is required for the interval"; - } + } else if (c == 1) { + DATATYPE dType = isValidDataType(substr, 1); + if (dType == DATATYPE::TRUE) + opsjson[opsKeys[c]] = true; + else if (dType == DATATYPE::FALSE) + opsjson[opsKeys[c]] = false; + + else { + throw "Boolean data is required for rotate resize"; } - } - - aquery[queryType]["operations"].append(opsjson); + } + } + } + + else if (type == "interval") { + if (rowvec.size() <= 2 || rowvec.size() > 3) + throw "interval operation has 3 values to specify"; + opsKeys = {"start", "stop", "step"}; + for (c = 0; c < rowvec.size(); c++) { + string substr = rowvec[c]; + DATATYPE dType = isValidDataType(substr, 2); + if (dType == DATATYPE::INTEGER) { + opsjson[opsKeys[c]] = stoi(substr); + } else { + throw "Numeric datatype is required for the interval"; + } + } + } + + aquery[queryType]["operations"].append(opsjson); } -void VDMS::CSVParserUtil::splitRowOnComma(const std::string &row, std::vector &rowvec) -{ - std::string::size_type start = 0; - while (start != std::string::npos) - { - std::string::size_type end = row.find(',', start); - if (end == std::string::npos) - { - if (start < row.size()) - { - rowvec.emplace_back(std::move(row.substr(start))); - } - break; - } - if (end > start) - { - rowvec.emplace_back(std::move(row.substr(start, end - start))); - } - start = end + 1; - } +void VDMS::CSVParserUtil::splitRowOnComma(const std::string &row, + std::vector &rowvec) { + std::string::size_type start = 0; + while (start != std::string::npos) { + std::string::size_type end = row.find(',', start); + if (end == std::string::npos) { + if (start < row.size()) { + rowvec.emplace_back(std::move(row.substr(start))); + } + break; + } + if (end > start) { + rowvec.emplace_back(std::move(row.substr(start, end - start))); + } + start = end + 1; + } } -VDMS::CSVParserUtil::DATATYPE VDMS::CSVParserUtil ::isValidDataType(string data, int type) -{ - CSVParserUtil::DATATYPE actualtype = getDataType(data, ""); - return actualtype; - - // if(type==2 && (actualt=3 || acype=tualtype==4))//2 is for num - // return actualtype; - // else if(type==1 && (actualtype==1 || actualtype==2))//1 is for bool - // return actualtype; - // else - // return -1; +VDMS::CSVParserUtil::DATATYPE VDMS::CSVParserUtil ::isValidDataType(string data, + int type) { + CSVParserUtil::DATATYPE actualtype = getDataType(data, ""); + return actualtype; + + // if(type==2 && (actualt=3 || acype=tualtype==4))//2 is for num + // return actualtype; + // else if(type==1 && (actualtype==1 || actualtype==2))//1 is for bool + // return actualtype; + // else + // return -1; } -bool VDMS::CSVParserUtil::isValidOpsType(string &type) -{ - if (type == "resize" || type == "threshold" || type == "flip" || type == "rotate" || type == "interval" || type == "crop") - return true; - return false; +bool VDMS::CSVParserUtil::isValidOpsType(string &type) { + if (type == "resize" || type == "threshold" || type == "flip" || + type == "rotate" || type == "interval" || type == "crop") + return true; + return false; } -void VDMS::CSVParserUtil::parseBlobFile(const std::string &filename, std::string **descriptor_ptr) -{ - std::vector v; - - std::ifstream input(filename); - if (!input.is_open()) - { - // handle error if file cannot be opened - std::cerr << "Error: Could not open file " << filename << std::endl; - *descriptor_ptr = nullptr; - return; - } +void VDMS::CSVParserUtil::parseBlobFile(const std::string &filename, + std::string **descriptor_ptr) { + std::vector v; - std::string str; - input >> str; + std::ifstream input(filename); + if (!input.is_open()) { + // handle error if file cannot be opened + std::cerr << "Error: Could not open file " << filename << std::endl; + *descriptor_ptr = nullptr; + return; + } - std::stringstream ss(str); - while (ss.good()) - { - std::string substr; - getline(ss, substr, ';'); - v.push_back(std::stof(substr)); - } + std::string str; + input >> str; - input.close(); + std::stringstream ss(str); + while (ss.good()) { + std::string substr; + getline(ss, substr, ';'); + v.push_back(std::stof(substr)); + } - // Convert vector to array of bytes - const size_t byteSize = v.size() * sizeof(float); - unsigned char *bytes = new unsigned char[byteSize]; - std::memcpy(bytes, v.data(), byteSize); + input.close(); - // Copy bytes to dynamically allocated string - *descriptor_ptr = new std::string(reinterpret_cast(bytes), byteSize); + // Convert vector to array of bytes + const size_t byteSize = v.size() * sizeof(float); + unsigned char *bytes = new unsigned char[byteSize]; + std::memcpy(bytes, v.data(), byteSize); - // Clean up dynamically-allocated memory - delete[] bytes; -} + // Copy bytes to dynamically allocated string + *descriptor_ptr = new std::string(reinterpret_cast(bytes), byteSize); -void VDMS::CSVParserUtil::videoToString(const std::string &filename, std::string **video_data_ptr) -{ - // Open the video file in binary mode - std::ifstream file(filename, std::ios::binary); - - if (!file) - { - std::cerr << "Failed to open file: " << filename << std::endl; - *video_data_ptr = nullptr; - } - else - { - // Read the entire content of the file into a string - std::stringstream buffer; - buffer << file.rdbuf(); - std::string video_data = buffer.str(); - - *video_data_ptr = new std::string(video_data); - } + // Clean up dynamically-allocated memory + delete[] bytes; +} - // Close the file - file.close(); +void VDMS::CSVParserUtil::videoToString(const std::string &filename, + std::string **video_data_ptr) { + // Open the video file in binary mode + std::ifstream file(filename, std::ios::binary); + + if (!file) { + std::cerr << "Failed to open file: " << filename << std::endl; + *video_data_ptr = nullptr; + } else { + // Read the entire content of the file into a string + std::stringstream buffer; + buffer << file.rdbuf(); + std::string video_data = buffer.str(); + + *video_data_ptr = new std::string(video_data); + } + + // Close the file + file.close(); } -void VDMS::CSVParserUtil::read_blob_image(const std::string &filename, std::string **image_data_ptr) -{ - std::ifstream file(filename, std::ios::binary); +void VDMS::CSVParserUtil::read_blob_image(const std::string &filename, + std::string **image_data_ptr) { + std::ifstream file(filename, std::ios::binary); - if (file.is_open()) - { + if (file.is_open()) { - // Get the size of the file - file.seekg(0, std::ios::end); - size_t size = file.tellg(); - file.seekg(0, std::ios::beg); + // Get the size of the file + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + file.seekg(0, std::ios::beg); - // Allocate a buffer to hold the file data - char *buffer = new char[size]; + // Allocate a buffer to hold the file data + char *buffer = new char[size]; - // Read the file data into the buffer - file.read(buffer, size); + // Read the file data into the buffer + file.read(buffer, size); - if (file.gcount() != size) - { - std::cerr << "Error: Failed to read entire file." << std::endl; - delete[] buffer; - *image_data_ptr = nullptr; - return; - } + if (file.gcount() != size) { + std::cerr << "Error: Failed to read entire file." << std::endl; + delete[] buffer; + *image_data_ptr = nullptr; + return; + } - // Close the file - file.close(); + // Close the file + file.close(); - // Allocate a new std::string to hold the image data - std::string *image_data = new std::string; - image_data->assign(buffer, size); + // Allocate a new std::string to hold the image data + std::string *image_data = new std::string; + image_data->assign(buffer, size); - // Free the buffer - delete[] buffer; + // Free the buffer + delete[] buffer; - // Assign the std::string pointer to the image_data_ptr - *image_data_ptr = image_data; - } - else - { - std::cerr << "Error: Failed to open file." << std::endl; - *image_data_ptr = nullptr; - } + // Assign the std::string pointer to the image_data_ptr + *image_data_ptr = image_data; + } else { + std::cerr << "Error: Failed to open file." << std::endl; + *image_data_ptr = nullptr; + } } -VDMS::Response VDMS::CSVParserUtil::send_to_vdms(const Json::Value &query, - const std::vector blobs) -{ - Json::StyledWriter _fastwriter; +VDMS::Response +VDMS::CSVParserUtil::send_to_vdms(const Json::Value &query, + const std::vector blobs) { + Json::StyledWriter _fastwriter; - return vdms_client->query(_fastwriter.write(query), blobs); + return vdms_client->query(_fastwriter.write(query), blobs); } diff --git a/client/cpp/CSVParserUtil.h b/client/cpp/CSVParserUtil.h index ad30bd9d..9d223fe7 100644 --- a/client/cpp/CSVParserUtil.h +++ b/client/cpp/CSVParserUtil.h @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include +#include "VDMSClient.h" #include "rapidcsv.h" -#include -#include #include -#include #include -#include "VDMSClient.h" +#include +#include +#include +#include +#include +#include using namespace std; using namespace std::chrono; @@ -16,87 +16,92 @@ using namespace std::chrono; namespace VDMS { class CSVParserUtil { - enum QueryType { EntityClass, - ConnectionClass, - ImagePath, - VideoPath, - DescriptorType, - DescriptorClass, - RectangleBound, - EntityUpdate, - ConnectionUpdate, - ImageUpdate, - RectangleUpdate - }; - enum class commandType { - AddEntity, - AddConnection, - AddImage, - AddVideo, - AddDescriptorSet, - AddDescriptor, - AddBoundingBox, - UpdateEntity, - UpdateConnection, - UpdateImage, - UpdateBoundingBox, - UNKNOWN - - }; - enum class DATATYPE{ - TRUE, - FALSE, - INTEGER, - FLOAT, - STRING, - DATE, - WRONG + enum QueryType { + EntityClass, + ConnectionClass, + ImagePath, + VideoPath, + DescriptorType, + DescriptorClass, + RectangleBound, + EntityUpdate, + ConnectionUpdate, + ImageUpdate, + RectangleUpdate + }; + enum class commandType { + AddEntity, + AddConnection, + AddImage, + AddVideo, + AddDescriptorSet, + AddDescriptor, + AddBoundingBox, + UpdateEntity, + UpdateConnection, + UpdateImage, + UpdateBoundingBox, + UNKNOWN - }; - std::map commands; - std::map command_list; + }; + enum class DATATYPE { + TRUE, + FALSE, + INTEGER, + FLOAT, + STRING, + DATE, + WRONG + }; + std::map commands; + std::map command_list; +public: + CSVParserUtil(); + CSVParserUtil(const std::string &, int port, const std::vector, + int id); + void initCommandsMap(); + int isBool(const string &data); + bool isFloat(const string &); + bool isInt(const string &); + VDMS::Response parse_row(std::vector &fields); + commandType get_query_type(const string &data); + CSVParserUtil::DATATYPE getDataType(const string &data, + const string &colname); + void parseProperty(const string &columnNames, const string &row, + const string &queryType, Json::Value &aquery); + void parseConstraints(const string &columnNames, const string &row, + string &queryType, Json::Value &aquery); + void parseOperations(const string columnNames, string row, string queryType, + Json::Value &aquery); - public: - CSVParserUtil(); - CSVParserUtil(const std::string&, int port, const std::vector, int id ); - void initCommandsMap(); - int isBool( const string& data); - bool isFloat(const string &); - bool isInt(const string &); - VDMS::Response parse_row(std::vector& fields); - commandType get_query_type(const string &data); - CSVParserUtil::DATATYPE getDataType(const string& data,const string& colname); - void parseProperty(const string& columnNames,const string& row,const string& queryType, Json::Value &aquery); - void parseConstraints(const string &columnNames,const string& row, string& queryType, Json::Value &aquery); - void parseOperations(const string columnNames,string row,string queryType,Json::Value &aquery); + // void parseCSVdata(int startrowcount,int endcount,rapidcsv::Document &doc, + // int &); + vector spiltrow(const string &row); + bool isValidOpsType(string &type); + void splitRowOnComma(const std::string &row, + std::vector &rowvec); - // void parseCSVdata(int startrowcount,int endcount,rapidcsv::Document &doc, int &); - vector spiltrow(const string& row); - bool isValidOpsType(string& type); - void splitRowOnComma(const std::string& row, std::vector& rowvec); + string function_accessing_columnNames(int i); + DATATYPE isValidDataType(string data, int type); + void read_blob_image(const std::string &filename, + std::string **image_data_ptr); + void videoToString(const std::string &filename, std::string **video_data); + void parseBlobFile(const std::string &filename, std::string **descriptor_ptr); - string function_accessing_columnNames(int i); - DATATYPE isValidDataType(string data,int type); - void read_blob_image(const std::string& filename, std::string** image_data_ptr); - void videoToString(const std::string& filename, std::string** video_data); - void parseBlobFile(const std::string& filename, std::string** descriptor_ptr); + VDMS::Response send_to_vdms(const Json::Value &json_query, + const std::vector blobs = {}); - VDMS::Response send_to_vdms(const Json::Value &json_query, const std::vector blobs = {}); - - public: - std::string vdms_server; - int vdms_port; - std::vector _columnNames; - std::mutex querytype_mutex; - std::mutex aquery_mutex; - std::mutex cons_mutex; - std::mutex ops_mutex; - int id; - std::unique_ptr vdms_client; - - }; +public: + std::string vdms_server; + int vdms_port; + std::vector _columnNames; + std::mutex querytype_mutex; + std::mutex aquery_mutex; + std::mutex cons_mutex; + std::mutex ops_mutex; + int id; + std::unique_ptr vdms_client; }; - - +}; // namespace VDMS diff --git a/client/cpp/ConnectionQueryParser.h b/client/cpp/ConnectionQueryParser.h index 6b79a011..d57a3d5e 100644 --- a/client/cpp/ConnectionQueryParser.h +++ b/client/cpp/ConnectionQueryParser.h @@ -1,81 +1,76 @@ #include "CSVParserUtil.h" namespace VDMS { -class ConnectionQueryParser : public CSVParserUtil{ - public: - VDMS::Response ParseAddConnection(vector row, vector & cols); - // VDMS::Response ParseUpdateConnection(vector row, vector & cols); -}; +class ConnectionQueryParser : public CSVParserUtil { +public: + VDMS::Response ParseAddConnection(vector row, vector &cols); + // VDMS::Response ParseUpdateConnection(vector row, vector + // & cols); }; +}; // namespace VDMS -VDMS::Response VDMS::ConnectionQueryParser::ParseAddConnection(vector row, vector & columnNames){ - Json::Value aquery; - Json::Value allquery; - Json::Value find_query1, find_query2,find_query; +VDMS::Response +VDMS::ConnectionQueryParser::ParseAddConnection(vector row, + vector &columnNames) { + Json::Value aquery; + Json::Value allquery; + Json::Value find_query1, find_query2, find_query; - if (row[0].empty()) { + if (row[0].empty()) { std::cerr << "Error: Connection Class not provided\n"; + } -} - -// Set command name and connection class -const string command_name = "AddConnection"; -const string connection_class = row[0]; -int ref1=1, ref2=3; -aquery["AddConnection"]["class"] = connection_class; - -// Parse class1 and class2 columns -for (int i = 1; i < columnNames.size(); i++) { - string column_name = columnNames[i]; - string column_value = row[i]; - string column_type = column_name.substr(0, 5); - string command="FindEntity"; + // Set command name and connection class + const string command_name = "AddConnection"; + const string connection_class = row[0]; + int ref1 = 1, ref2 = 3; + aquery["AddConnection"]["class"] = connection_class; + // Parse class1 and class2 columns + for (int i = 1; i < columnNames.size(); i++) { + string column_name = columnNames[i]; + string column_value = row[i]; + string column_type = column_name.substr(0, 5); + string command = "FindEntity"; if (column_value.empty()) { - continue; + continue; } - - if (column_name.find('@') != std::string::npos) { - std::size_t at_pos = column_name.find('@'); - - if (at_pos != std::string::npos) { - // Extract the name and id substrings. - std::string class1 = column_name.substr(0, at_pos); - std::string class_prop = column_name.substr(at_pos + 1); - - find_query["FindEntity"]["class"]=class1; - find_query["FindEntity"]["_ref"]=ref1++; - find_query["FindEntity"]["constraints"][class_prop][0] = "=="; - find_query["FindEntity"]["constraints"][class_prop][1]=column_value; - } - allquery.append(find_query); - + std::size_t at_pos = column_name.find('@'); + + if (at_pos != std::string::npos) { + // Extract the name and id substrings. + std::string class1 = column_name.substr(0, at_pos); + std::string class_prop = column_name.substr(at_pos + 1); + + find_query["FindEntity"]["class"] = class1; + find_query["FindEntity"]["_ref"] = ref1++; + find_query["FindEntity"]["constraints"][class_prop][0] = "=="; + find_query["FindEntity"]["constraints"][class_prop][1] = column_value; + } + allquery.append(find_query); } if (column_type == "prop_") { - parseProperty(column_name, column_value, command_name, aquery); + parseProperty(column_name, column_value, command_name, aquery); } find_query.clear(); + } + // Set connection references + aquery["AddConnection"]["ref1"] = allquery[0]["FindEntity"]["_ref"]; + aquery["AddConnection"]["ref2"] = allquery[1]["FindEntity"]["_ref"]; -} - -// Set connection references -aquery["AddConnection"]["ref1"] = allquery[0]["FindEntity"]["_ref"]; -aquery["AddConnection"]["ref2"] = allquery[1]["FindEntity"]["_ref"]; - - - -allquery.append(aquery); -// std::cout< row, vector & columnNames){ +// VDMS::Response +// VDMS::ConnectionQueryParser::ParseUpdateConnection(vector row, +// vector & columnNames){ // Json::Value aquery; // Json::Value aqueryf; // Json::Value allquery; diff --git a/client/cpp/DescriptorQueryParser.h b/client/cpp/DescriptorQueryParser.h index 6a5d634e..1e7dc3b0 100644 --- a/client/cpp/DescriptorQueryParser.h +++ b/client/cpp/DescriptorQueryParser.h @@ -1,56 +1,48 @@ #pragma once #include "CSVParserUtil.h" namespace VDMS { -class DescriptorQueryParser : public CSVParserUtil{ - public: - VDMS::Response ParseAddDescriptor(vector row, vector& columnNames, int id); - -}; +class DescriptorQueryParser : public CSVParserUtil { +public: + VDMS::Response ParseAddDescriptor(vector row, + vector &columnNames, int id); }; +}; // namespace VDMS -VDMS::Response VDMS::DescriptorQueryParser::ParseAddDescriptor(vector row, vector& columnNames, int id){ - - if(row[0]==""){ - throw "Set not provided"; - } - Json::Value aquery; - Json::Value fullquery; - std::vector blobs; - std::string* descriptor; - std::string command_name="AddDescriptor"; - aquery["AddDescriptor"]["set"]=row[0]; - aquery["AddDescriptor"]["_ref"]=id+3; - for(int j=1;j row, vector &columnNames, int id) { - parseBlobFile(row[j], &descriptor); - if (descriptor == nullptr) { - std::cout << "Failed to parse blob file" << std::endl; - - } - - if(descriptor!=nullptr){ - blobs.push_back(descriptor); - - } - - } - - } - - -} -fullquery.append(aquery); -return send_to_vdms(fullquery,blobs); -} - + if (row[0] == "") { + throw "Set not provided"; + } + Json::Value aquery; + Json::Value fullquery; + std::vector blobs; + std::string *descriptor; + std::string command_name = "AddDescriptor"; + aquery["AddDescriptor"]["set"] = row[0]; + aquery["AddDescriptor"]["_ref"] = id + 3; + for (int j = 1; j < columnNames.size(); j++) { + if (row[j] != "") { + if (columnNames[j].find("prop_") != string::npos) { + parseProperty(columnNames[j], row[j], command_name, aquery); + } + if (columnNames[j] == "label") { + aquery["AddDescriptor"]["label"] = row[j]; + } + if (columnNames[j] == "inputdata") { + parseBlobFile(row[j], &descriptor); + if (descriptor == nullptr) { + std::cout << "Failed to parse blob file" << std::endl; + } + + if (descriptor != nullptr) { + blobs.push_back(descriptor); + } + } + } + } + fullquery.append(aquery); + return send_to_vdms(fullquery, blobs); +} diff --git a/client/cpp/DescriptorSetQueryParser.h b/client/cpp/DescriptorSetQueryParser.h index 31d35d23..27640b14 100644 --- a/client/cpp/DescriptorSetQueryParser.h +++ b/client/cpp/DescriptorSetQueryParser.h @@ -1,53 +1,54 @@ #pragma once #include "CSVParserUtil.h" namespace VDMS { -class DescriptorSetQueryParser : public CSVParserUtil{ - public: - VDMS::Response ParseAddDescriptorSet(vector row, vector& columnNames); - bool isValidMetric(string& metric); - bool isValidEngine(string& engine); +class DescriptorSetQueryParser : public CSVParserUtil { +public: + VDMS::Response ParseAddDescriptorSet(vector row, + vector &columnNames); + bool isValidMetric(string &metric); + bool isValidEngine(string &engine); }; -}; -VDMS::Response VDMS::DescriptorSetQueryParser::ParseAddDescriptorSet(vector row, vector& columnNames){ - if(row[0]==""){ - throw "Descriptor Name not provided"; - } - Json::Value aquery; - Json::Value fullquery; - std::string command_name="AddDescriptorSet"; - aquery["AddDescriptorSet"]["name"]=row[0]; - - for(int j=1;j row, vector &columnNames) { + if (row[0] == "") { + throw "Descriptor Name not provided"; + } + Json::Value aquery; + Json::Value fullquery; + std::string command_name = "AddDescriptorSet"; + aquery["AddDescriptorSet"]["name"] = row[0]; + for (int j = 1; j < columnNames.size(); j++) { + if (!row[j].empty()) { + if (columnNames[j].find("prop_") != string::npos) { + parseProperty(columnNames[j], row[j], command_name, aquery); + } + if (columnNames[j] == "dimensions") { + aquery["AddDescriptorSet"]["dimensions"] = stoi(row[j]); + } + if (columnNames[j] == "distancemetric") { + if (!isValidMetric(row[j])) + throw "Metric value is not valid"; + aquery["AddDescriptorSet"]["metric"] = row[j]; + } + if (columnNames[j] == "searchengine") { + if (!isValidEngine(row[j])) + throw "Engine value is not valid"; + aquery["AddDescriptorSet"]["engine"] = row[j]; + } } + } - fullquery.append(aquery); - return send_to_vdms(fullquery); + fullquery.append(aquery); + return send_to_vdms(fullquery); } -bool VDMS::DescriptorSetQueryParser::isValidMetric(string& metric) { - return (metric=="L2" || metric=="IP"); +bool VDMS::DescriptorSetQueryParser::isValidMetric(string &metric) { + return (metric == "L2" || metric == "IP"); } -bool VDMS::DescriptorSetQueryParser::isValidEngine(string& engine) { - return (engine=="TileDBDense" || engine=="TileDBSparse" || engine=="FaissFlat" || engine=="FaissIVFFlat"); +bool VDMS::DescriptorSetQueryParser::isValidEngine(string &engine) { + return (engine == "TileDBDense" || engine == "TileDBSparse" || + engine == "FaissFlat" || engine == "FaissIVFFlat"); } diff --git a/client/cpp/EntityQueryParser.h b/client/cpp/EntityQueryParser.h index a6e334f6..4f966a73 100644 --- a/client/cpp/EntityQueryParser.h +++ b/client/cpp/EntityQueryParser.h @@ -2,58 +2,52 @@ #include "CSVParserUtil.h" #include -namespace VDMS -{ +namespace VDMS { - class EntityQueryParser : public CSVParserUtil - { - public: - VDMS::Response ParseAddEntity(vector row, vector &cols); - // VDMS::Response ParseUpdateEntity(vector row, vector & cols); - }; +class EntityQueryParser : public CSVParserUtil { +public: + VDMS::Response ParseAddEntity(vector row, vector &cols); + // VDMS::Response ParseUpdateEntity(vector row, vector & + // cols); }; +}; // namespace VDMS -VDMS::Response VDMS::EntityQueryParser::ParseAddEntity(vector row, vector &cols) -{ - Json::Value aquery; - Json::Value fullquery; +VDMS::Response VDMS::EntityQueryParser::ParseAddEntity(vector row, + vector &cols) { + Json::Value aquery; + Json::Value fullquery; - std::string command_name = "AddEntity"; - if (row[0].empty()) - { - throw "Entity Class not specified"; - } - if (cols.size() == 0) - { - throw std::invalid_argument("Error: Column names vector is empty."); - } - aquery[command_name]["class"] = row[0]; - aquery[command_name]["_ref"] = 11; + std::string command_name = "AddEntity"; + if (row[0].empty()) { + throw "Entity Class not specified"; + } + if (cols.size() == 0) { + throw std::invalid_argument("Error: Column names vector is empty."); + } + aquery[command_name]["class"] = row[0]; + aquery[command_name]["_ref"] = 11; - for (int j = 1; j < cols.size(); j++) - { + for (int j = 1; j < cols.size(); j++) { - if (!row[j].empty()) - { + if (!row[j].empty()) { - string columnType = cols[j].substr(0, 5); - if (columnType == "prop_") - { + string columnType = cols[j].substr(0, 5); + if (columnType == "prop_") { - parseProperty(cols[j], row[j], command_name, aquery); - } - else if(columnType=="cons_"){ + parseProperty(cols[j], row[j], command_name, aquery); + } else if (columnType == "cons_") { - parseConstraints(cols[j],row[j],command_name,aquery); - } - } + parseConstraints(cols[j], row[j], command_name, aquery); + } } - fullquery.append(aquery); + } + fullquery.append(aquery); - return send_to_vdms(fullquery); + return send_to_vdms(fullquery); } -// VDMS::Response VDMS::EntityQueryParser::ParseUpdateEntity(vector row, vector & cols){ +// VDMS::Response VDMS::EntityQueryParser::ParseUpdateEntity(vector row, +// vector & cols){ // Json:: Value aquery; // Json::Value all_query; // Json::Value find_query; diff --git a/client/cpp/ImageQueryParser.h b/client/cpp/ImageQueryParser.h index c485926d..f56c18ff 100644 --- a/client/cpp/ImageQueryParser.h +++ b/client/cpp/ImageQueryParser.h @@ -1,79 +1,78 @@ #pragma once #include "CSVParserUtil.h" namespace VDMS { -class ImageQueryParser : public CSVParserUtil{ - private: - std::mutex file_access_mutex; - public: - // ImageQueryParser(); - VDMS::Response ParseAddImage(vector row, vector columnNames); - // VDMS::Response ParseUpdateImage(vector row, vector columnNames); - bool ValidImageFormat(string data); - - -}; +class ImageQueryParser : public CSVParserUtil { +private: + std::mutex file_access_mutex; + +public: + // ImageQueryParser(); + VDMS::Response ParseAddImage(vector row, vector columnNames); + // VDMS::Response ParseUpdateImage(vector row, vector + // columnNames); + bool ValidImageFormat(string data); }; - - - -VDMS::Response VDMS::ImageQueryParser::ParseAddImage(vector row, vector columnNames){ - Json::Value aquery; - Json::Value fullquery; - std::vector blobs; - // - if(row[0].empty()) - throw "Image path is not specified"; - if (columnNames.size() == 0) { - throw std::invalid_argument("Error: Column names vector is empty."); - } - - std::string command_name="AddImage"; - - aquery["AddImage"]["_ref"]=11; - - std::string name =row[0]; - - std::string* image_data_ptr = nullptr; - - read_blob_image(name, &image_data_ptr); - - // std::cout << *image_data_ptr << std::endl; - if(image_data_ptr!=nullptr){ - blobs.push_back(image_data_ptr); - // std::cout <<*blobs[0] < row, + vector columnNames) { + Json::Value aquery; + Json::Value fullquery; + std::vector blobs; + // + if (row[0].empty()) + throw "Image path is not specified"; + if (columnNames.size() == 0) { + throw std::invalid_argument("Error: Column names vector is empty."); + } + + std::string command_name = "AddImage"; + + aquery["AddImage"]["_ref"] = 11; + + std::string name = row[0]; + + std::string *image_data_ptr = nullptr; + + read_blob_image(name, &image_data_ptr); + + // std::cout << *image_data_ptr << std::endl; + if (image_data_ptr != nullptr) { + blobs.push_back(image_data_ptr); + // std::cout <<*blobs[0] < row, vector columnNames){ +// VDMS::Response VDMS::ImageQueryParser::ParseUpdateImage(vector row, +// vector columnNames){ // Json :: Value aquery; // Json::Value fullquery; diff --git a/client/cpp/VDMSClient.cc b/client/cpp/VDMSClient.cc index c8c259cd..c72ab42d 100644 --- a/client/cpp/VDMSClient.cc +++ b/client/cpp/VDMSClient.cc @@ -30,48 +30,45 @@ #include "VDMSClient.h" #include "queryMessage.pb.h" - using namespace VDMS; -VDMSClient::VDMSClient(std::string addr, int port) : _conn(addr, port) -{ -} -// void VDMSClient::parse_csv_file(std::string filename, std::string server, int p){ +VDMSClient::VDMSClient(std::string addr, int port) : _conn(addr, port) {} +// void VDMSClient::parse_csv_file(std::string filename, std::string server, int +// p){ // CSVParser _csv_parser(filename, server, p); -// auto start = high_resolution_clock::now(); +// auto start = high_resolution_clock::now(); // // _csv_parser.create_thread_pool(); // auto end = high_resolution_clock::now(); // auto duration = duration_cast(end - start); -// cout << "duaration in ms is "< blobs) -{ - protobufs::queryMessage cmd; - cmd.set_json(json); + const std::vector blobs) { + protobufs::queryMessage cmd; + cmd.set_json(json); - for (auto& it : blobs) { - std::string *blob = cmd.add_blobs(); - *blob = *it; - } + for (auto &it : blobs) { + std::string *blob = cmd.add_blobs(); + *blob = *it; + } - std::basic_string msg(cmd.ByteSize(),0); - cmd.SerializeToArray((void*)msg.data(), msg.length()); - _conn.send_message(msg.data(), msg.length()); + std::basic_string msg(cmd.ByteSize(), 0); + cmd.SerializeToArray((void *)msg.data(), msg.length()); + _conn.send_message(msg.data(), msg.length()); - // Wait for response (blocking call) - msg = _conn.recv_message(); + // Wait for response (blocking call) + msg = _conn.recv_message(); - protobufs::queryMessage protobuf_response; - protobuf_response.ParseFromArray((const void*)msg.data(), msg.length()); + protobufs::queryMessage protobuf_response; + protobuf_response.ParseFromArray((const void *)msg.data(), msg.length()); - VDMS::Response response; - response.json = protobuf_response.json(); + VDMS::Response response; + response.json = protobuf_response.json(); - for (auto& it : protobuf_response.blobs()) { - response.blobs.push_back(it); - } + for (auto &it : protobuf_response.blobs()) { + response.blobs.push_back(it); + } - return response; + return response; } diff --git a/client/cpp/VDMSClient.h b/client/cpp/VDMSClient.h index ced571d7..67e20938 100644 --- a/client/cpp/VDMSClient.h +++ b/client/cpp/VDMSClient.h @@ -29,37 +29,34 @@ #pragma once +#include "comm/Connection.h" #include #include -#include "comm/Connection.h" // #include "CSVParser.h" namespace VDMS { - struct Response { - std::string json; - std::vector blobs; - }; - +struct Response { + std::string json; + std::vector blobs; +}; - class VDMSClient { - static const int VDMS_PORT = 55555; +class VDMSClient { + static const int VDMS_PORT = 55555; - // The constructor of the ConnClient class already connects to the - // server if instantiated with the right address and port and it gets - // disconnected when the class goes out of scope. For now, we - // will leave the functioning like that. If the client has a need to - // disconnect and connect specifically, then we can add explicit calls. - comm::ConnClient _conn; - + // The constructor of the ConnClient class already connects to the + // server if instantiated with the right address and port and it gets + // disconnected when the class goes out of scope. For now, we + // will leave the functioning like that. If the client has a need to + // disconnect and connect specifically, then we can add explicit calls. + comm::ConnClient _conn; - public: - VDMSClient(std::string addr = "localhost", int port = VDMS_PORT); +public: + VDMSClient(std::string addr = "localhost", int port = VDMS_PORT); - // Blocking call - VDMS::Response query(const std::string &json_query, - const std::vector blobs = {}); - // void parse_csv_file(std::string filename, std::string , int); - - }; + // Blocking call + VDMS::Response query(const std::string &json_query, + const std::vector blobs = {}); + // void parse_csv_file(std::string filename, std::string , int); }; +}; // namespace VDMS diff --git a/client/cpp/VideoQueryParser.h b/client/cpp/VideoQueryParser.h index 3c89758b..6ac5747a 100644 --- a/client/cpp/VideoQueryParser.h +++ b/client/cpp/VideoQueryParser.h @@ -1,84 +1,83 @@ #pragma once #include "CSVParserUtil.h" namespace VDMS { -class VideoQueryParser : public CSVParserUtil{ - public: - VDMS::Response ParseAddVideo(vector row, vector& columnNames); - bool isValidCodec(string& row); - bool isValidContainer(string& row); - +class VideoQueryParser : public CSVParserUtil { +public: + VDMS::Response ParseAddVideo(vector row, vector &columnNames); + bool isValidCodec(string &row); + bool isValidContainer(string &row); }; -} -VDMS::Response VDMS::VideoQueryParser::ParseAddVideo(vector row, vector& columnNames){ - Json::Value aquery; - Json::Value fullquery; - std::vector blobs; - if(row[0]=="") - throw "Video not provided"; - std::string command_name="AddVideo"; - - std::string video_name=row[0]; - try { - std::string* video_data_ptr; - CSVParserUtil::videoToString(video_name, &video_data_ptr); +} // namespace VDMS +VDMS::Response +VDMS::VideoQueryParser::ParseAddVideo(vector row, + vector &columnNames) { + Json::Value aquery; + Json::Value fullquery; + std::vector blobs; + if (row[0] == "") + throw "Video not provided"; + std::string command_name = "AddVideo"; - if(video_data_ptr!=nullptr){ - blobs.push_back(video_data_ptr); - // std::cout <<*blobs[0] <::signaling_NaN(), - const long long pDefaultInteger = 0) - : mHasDefaultConverter(pHasDefaultConverter) - , mDefaultFloat(pDefaultFloat) - , mDefaultInteger(pDefaultInteger) - { - } + * @brief Constructor + * @param pHasDefaultConverter specifies if conversion of non-numerical + * strings shall be converted to a default numerical value, instead of causing + * an exception to be thrown (default). + * @param pDefaultFloat floating-point default value to represent + * invalid numbers. + * @param pDefaultInteger integer default value to represent invalid + * numbers. + */ + explicit ConverterParams( + const bool pHasDefaultConverter = false, + const long double pDefaultFloat = + std::numeric_limits::signaling_NaN(), + const long long pDefaultInteger = 0) + : mHasDefaultConverter(pHasDefaultConverter), + mDefaultFloat(pDefaultFloat), mDefaultInteger(pDefaultInteger) {} - /** - * @brief specifies if conversion of non-numerical strings shall be converted to a default - * numerical value, instead of causing an exception to be thrown (default). - */ - bool mHasDefaultConverter; + /** + * @brief specifies if conversion of non-numerical strings shall be + * converted to a default numerical value, instead of causing an exception to + * be thrown (default). + */ + bool mHasDefaultConverter; - /** - * @brief floating-point default value to represent invalid numbers. - */ - long double mDefaultFloat; + /** + * @brief floating-point default value to represent invalid numbers. + */ + long double mDefaultFloat; - /** - * @brief integer default value to represent invalid numbers. - */ - long long mDefaultInteger; - }; + /** + * @brief integer default value to represent invalid numbers. + */ + long long mDefaultInteger; +}; +/** + * @brief Exception thrown when attempting to access Document data in a + * datatype which is not supported by the Converter class. + */ +class no_converter : public std::exception { /** - * @brief Exception thrown when attempting to access Document data in a datatype which - * is not supported by the Converter class. + * @brief Provides details about the exception + * @returns an explanatory string */ - class no_converter : public std::exception - { - /** - * @brief Provides details about the exception - * @returns an explanatory string - */ - virtual const char* what() const throw() - { - return "unsupported conversion datatype"; - } - }; - - /** - * @brief Class providing conversion to/from numerical datatypes and strings. Only - * intended for rapidcsv internal usage, but exposed externally to allow - * specialization for custom datatype conversions. - */ - template - class Converter - { - public: - /** - * @brief Constructor - * @param pConverterParams specifies how conversion of non-numerical values to - * numerical datatype shall be handled. - */ - Converter(const ConverterParams& pConverterParams) - : mConverterParams(pConverterParams) - { - } + virtual const char *what() const throw() { + return "unsupported conversion datatype"; + } +}; - /** - * @brief Converts numerical value to string representation. - * @param pVal numerical value - * @param pStr output string - */ - void ToStr(const T& pVal, std::string& pStr) const - { - if (typeid(T) == typeid(int) || - typeid(T) == typeid(long) || - typeid(T) == typeid(long long) || - typeid(T) == typeid(unsigned) || - typeid(T) == typeid(unsigned long) || - typeid(T) == typeid(unsigned long long) || - typeid(T) == typeid(float) || - typeid(T) == typeid(double) || - typeid(T) == typeid(long double) || - typeid(T) == typeid(char)) - { - std::ostringstream out; - out << pVal; - pStr = out.str(); - } - else - { - throw no_converter(); - } - } +/** + * @brief Class providing conversion to/from numerical datatypes and + * strings. Only intended for rapidcsv internal usage, but exposed externally to + * allow specialization for custom datatype conversions. + */ +template class Converter { +public: + /** + * @brief Constructor + * @param pConverterParams specifies how conversion of non-numerical + * values to numerical datatype shall be handled. + */ + Converter(const ConverterParams &pConverterParams) + : mConverterParams(pConverterParams) {} - /** - * @brief Converts string holding a numerical value to numerical datatype representation. - * @param pVal numerical value - * @param pStr output string - */ - void ToVal(const std::string& pStr, T& pVal) const - { - try - { - if (typeid(T) == typeid(int)) - { - pVal = static_cast(std::stoi(pStr)); - return; - } - else if (typeid(T) == typeid(long)) - { - pVal = static_cast(std::stol(pStr)); - return; - } - else if (typeid(T) == typeid(long long)) - { - pVal = static_cast(std::stoll(pStr)); - return; - } - else if (typeid(T) == typeid(unsigned)) - { - pVal = static_cast(std::stoul(pStr)); - return; - } - else if (typeid(T) == typeid(unsigned long)) - { - pVal = static_cast(std::stoul(pStr)); - return; - } - else if (typeid(T) == typeid(unsigned long long)) - { - pVal = static_cast(std::stoull(pStr)); - return; - } - } - catch (...) - { - if (!mConverterParams.mHasDefaultConverter) - { - throw; - } - else - { - pVal = static_cast(mConverterParams.mDefaultInteger); - return; - } - } + /** + * @brief Converts numerical value to string representation. + * @param pVal numerical value + * @param pStr output string + */ + void ToStr(const T &pVal, std::string &pStr) const { + if (typeid(T) == typeid(int) || typeid(T) == typeid(long) || + typeid(T) == typeid(long long) || typeid(T) == typeid(unsigned) || + typeid(T) == typeid(unsigned long) || + typeid(T) == typeid(unsigned long long) || typeid(T) == typeid(float) || + typeid(T) == typeid(double) || typeid(T) == typeid(long double) || + typeid(T) == typeid(char)) { + std::ostringstream out; + out << pVal; + pStr = out.str(); + } else { + throw no_converter(); + } + } - try - { - if (typeid(T) == typeid(float)) - { - pVal = static_cast(std::stof(pStr)); - return; - } - else if (typeid(T) == typeid(double)) - { - pVal = static_cast(std::stod(pStr)); - return; - } - else if (typeid(T) == typeid(long double)) - { - pVal = static_cast(std::stold(pStr)); - return; - } + /** + * @brief Converts string holding a numerical value to numerical datatype + * representation. + * @param pVal numerical value + * @param pStr output string + */ + void ToVal(const std::string &pStr, T &pVal) const { + try { + if (typeid(T) == typeid(int)) { + pVal = static_cast(std::stoi(pStr)); + return; + } else if (typeid(T) == typeid(long)) { + pVal = static_cast(std::stol(pStr)); + return; + } else if (typeid(T) == typeid(long long)) { + pVal = static_cast(std::stoll(pStr)); + return; + } else if (typeid(T) == typeid(unsigned)) { + pVal = static_cast(std::stoul(pStr)); + return; + } else if (typeid(T) == typeid(unsigned long)) { + pVal = static_cast(std::stoul(pStr)); + return; + } else if (typeid(T) == typeid(unsigned long long)) { + pVal = static_cast(std::stoull(pStr)); + return; } - catch (...) - { - if (!mConverterParams.mHasDefaultConverter) - { - throw; - } - else - { - pVal = static_cast(mConverterParams.mDefaultFloat); - return; - } + } catch (...) { + if (!mConverterParams.mHasDefaultConverter) { + throw; + } else { + pVal = static_cast(mConverterParams.mDefaultInteger); + return; } + } - if (typeid(T) == typeid(char)) - { - pVal = static_cast(pStr[0]); + try { + if (typeid(T) == typeid(float)) { + pVal = static_cast(std::stof(pStr)); + return; + } else if (typeid(T) == typeid(double)) { + pVal = static_cast(std::stod(pStr)); + return; + } else if (typeid(T) == typeid(long double)) { + pVal = static_cast(std::stold(pStr)); return; } - else - { - throw no_converter(); + } catch (...) { + if (!mConverterParams.mHasDefaultConverter) { + throw; + } else { + pVal = static_cast(mConverterParams.mDefaultFloat); + return; } } - private: - const ConverterParams& mConverterParams; - }; + if (typeid(T) == typeid(char)) { + pVal = static_cast(pStr[0]); + return; + } else { + throw no_converter(); + } + } +private: + const ConverterParams &mConverterParams; +}; + +/** + * @brief Specialized implementation handling string to string conversion. + * @param pVal string + * @param pStr string + */ +template <> +inline void Converter::ToStr(const std::string &pVal, + std::string &pStr) const { + pStr = pVal; +} + +/** + * @brief Specialized implementation handling string to string conversion. + * @param pVal string + * @param pStr string + */ +template <> +inline void Converter::ToVal(const std::string &pStr, + std::string &pVal) const { + pVal = pStr; +} + +template +using ConvFunc = std::function; + +/** + * @brief Datastructure holding parameters controlling which row and column + * should be treated as labels. + */ +struct LabelParams { /** - * @brief Specialized implementation handling string to string conversion. - * @param pVal string - * @param pStr string + * @brief Constructor + * @param pColumnNameIdx specifies the zero-based row index of the + * column labels, setting it to -1 prevents column lookup by label name, and + * gives access to all rows as document data. Default: 0 + * @param pRowNameIdx specifies the zero-based column index of the + * row labels, setting it to -1 prevents row lookup by label name, and gives + * access to all columns as document data. Default: -1 */ - template<> - inline void Converter::ToStr(const std::string& pVal, std::string& pStr) const - { - pStr = pVal; - } + explicit LabelParams(const int pColumnNameIdx = 0, const int pRowNameIdx = -1) + : mColumnNameIdx(pColumnNameIdx), mRowNameIdx(pRowNameIdx) {} /** - * @brief Specialized implementation handling string to string conversion. - * @param pVal string - * @param pStr string + * @brief specifies the zero-based row index of the column labels. */ - template<> - inline void Converter::ToVal(const std::string& pStr, std::string& pVal) const - { - pVal = pStr; - } + int mColumnNameIdx; - template - using ConvFunc = std::function; - - /** - * @brief Datastructure holding parameters controlling which row and column should be - * treated as labels. - */ - struct LabelParams - { - /** - * @brief Constructor - * @param pColumnNameIdx specifies the zero-based row index of the column labels, setting - * it to -1 prevents column lookup by label name, and gives access - * to all rows as document data. Default: 0 - * @param pRowNameIdx specifies the zero-based column index of the row labels, setting - * it to -1 prevents row lookup by label name, and gives access - * to all columns as document data. Default: -1 - */ - explicit LabelParams(const int pColumnNameIdx = 0, const int pRowNameIdx = -1) - : mColumnNameIdx(pColumnNameIdx) - , mRowNameIdx(pRowNameIdx) - { - } + /** + * @brief specifies the zero-based column index of the row labels. + */ + int mRowNameIdx; +}; - /** - * @brief specifies the zero-based row index of the column labels. - */ - int mColumnNameIdx; - - /** - * @brief specifies the zero-based column index of the row labels. - */ - int mRowNameIdx; - }; - - /** - * @brief Datastructure holding parameters controlling how the CSV data fields are separated. - */ - struct SeparatorParams - { - /** - * @brief Constructor - * @param pSeparator specifies the column separator (default ','). - * @param pTrim specifies whether to trim leading and trailing spaces from - * cells read (default false). - * @param pHasCR specifies whether a new document (i.e. not an existing document read) - * should use CR/LF instead of only LF (default is to use standard - * behavior of underlying platforms - CR/LF for Win, and LF for others). - * @param pQuotedLinebreaks specifies whether to allow line breaks in quoted text (default false) - * @param pAutoQuote specifies whether to automatically dequote data during read, and add - * quotes during write (default true). - */ - explicit SeparatorParams(const char pSeparator = ',', const bool pTrim = false, - const bool pHasCR = sPlatformHasCR, const bool pQuotedLinebreaks = false, - const bool pAutoQuote = true) - : mSeparator(pSeparator) - , mTrim(pTrim) - , mHasCR(pHasCR) - , mQuotedLinebreaks(pQuotedLinebreaks) - , mAutoQuote(pAutoQuote) - { - } +/** + * @brief Datastructure holding parameters controlling how the CSV data + * fields are separated. + */ +struct SeparatorParams { + /** + * @brief Constructor + * @param pSeparator specifies the column separator (default + * ','). + * @param pTrim specifies whether to trim leading and + * trailing spaces from cells read (default false). + * @param pHasCR specifies whether a new document (i.e. not + * an existing document read) should use CR/LF instead of only LF (default is + * to use standard behavior of underlying platforms - CR/LF for Win, and LF + * for others). + * @param pQuotedLinebreaks specifies whether to allow line breaks in + * quoted text (default false) + * @param pAutoQuote specifies whether to automatically dequote + * data during read, and add quotes during write (default true). + */ + explicit SeparatorParams(const char pSeparator = ',', + const bool pTrim = false, + const bool pHasCR = sPlatformHasCR, + const bool pQuotedLinebreaks = false, + const bool pAutoQuote = true) + : mSeparator(pSeparator), mTrim(pTrim), mHasCR(pHasCR), + mQuotedLinebreaks(pQuotedLinebreaks), mAutoQuote(pAutoQuote) {} - /** - * @brief specifies the column separator. - */ - char mSeparator; - - /** - * @brief specifies whether to trim leading and trailing spaces from cells read. - */ - bool mTrim; - - /** - * @brief specifies whether new documents should use CR/LF instead of LF. - */ - bool mHasCR; - - /** - * @brief specifies whether to allow line breaks in quoted text. - */ - bool mQuotedLinebreaks; - - /** - * @brief specifies whether to automatically dequote cell data. - */ - bool mAutoQuote; - }; - - /** - * @brief Datastructure holding parameters controlling how special line formats should be - * treated. - */ - struct LineReaderParams - { - /** - * @brief Constructor - * @param pSkipCommentLines specifies whether to skip lines prefixed with - * mCommentPrefix. Default: false - * @param pCommentPrefix specifies which prefix character to indicate a comment - * line. Default: # - * @param pSkipEmptyLines specifies whether to skip empty lines. Default: false - */ - explicit LineReaderParams(const bool pSkipCommentLines = false, - const char pCommentPrefix = '#', - const bool pSkipEmptyLines = false) - : mSkipCommentLines(pSkipCommentLines) - , mCommentPrefix(pCommentPrefix) - , mSkipEmptyLines(pSkipEmptyLines) - { - } + /** + * @brief specifies the column separator. + */ + char mSeparator; - /** - * @brief specifies whether to skip lines prefixed with mCommentPrefix. - */ - bool mSkipCommentLines; - - /** - * @brief specifies which prefix character to indicate a comment line. - */ - char mCommentPrefix; - - /** - * @brief specifies whether to skip empty lines. - */ - bool mSkipEmptyLines; - }; - - /** - * @brief Class representing a CSV document. - */ - class Document - { - public: - /** - * @brief Constructor - * @param pPath specifies the path of an existing CSV-file to populate the Document - * data with. - * @param pLabelParams specifies which row and column should be treated as labels. - * @param pSeparatorParams specifies which field and row separators should be used. - * @param pConverterParams specifies how invalid numbers (including empty strings) should be - * handled. - * @param pLineReaderParams specifies how special line formats should be treated. - */ - explicit Document(const std::string& pPath = std::string(), - const LabelParams& pLabelParams = LabelParams(), - const SeparatorParams& pSeparatorParams = SeparatorParams(), - const ConverterParams& pConverterParams = ConverterParams(), - const LineReaderParams& pLineReaderParams = LineReaderParams()) - : mPath(pPath) - , mLabelParams(pLabelParams) - , mSeparatorParams(pSeparatorParams) - , mConverterParams(pConverterParams) - , mLineReaderParams(pLineReaderParams) - { - if (!mPath.empty()) - { - ReadCsv(); - } - } + /** + * @brief specifies whether to trim leading and trailing spaces from cells + * read. + */ + bool mTrim; - /** - * @brief Constructor - * @param pStream specifies an input stream to read CSV data from. - * @param pLabelParams specifies which row and column should be treated as labels. - * @param pSeparatorParams specifies which field and row separators should be used. - * @param pConverterParams specifies how invalid numbers (including empty strings) should be - * handled. - * @param pLineReaderParams specifies how special line formats should be treated. - */ - explicit Document(std::istream& pStream, - const LabelParams& pLabelParams = LabelParams(), - const SeparatorParams& pSeparatorParams = SeparatorParams(), - const ConverterParams& pConverterParams = ConverterParams(), - const LineReaderParams& pLineReaderParams = LineReaderParams()) - : mPath() - , mLabelParams(pLabelParams) - , mSeparatorParams(pSeparatorParams) - , mConverterParams(pConverterParams) - , mLineReaderParams(pLineReaderParams) - { - ReadCsv(pStream); - } - - /** - * @brief Read Document data from file. - * @param pPath specifies the path of an existing CSV-file to populate the Document - * data with. - * @param pLabelParams specifies which row and column should be treated as labels. - * @param pSeparatorParams specifies which field and row separators should be used. - * @param pConverterParams specifies how invalid numbers (including empty strings) should be - * handled. - * @param pLineReaderParams specifies how special line formats should be treated. - */ - void Load(const std::string& pPath, - const LabelParams& pLabelParams = LabelParams(), - const SeparatorParams& pSeparatorParams = SeparatorParams(), - const ConverterParams& pConverterParams = ConverterParams(), - const LineReaderParams& pLineReaderParams = LineReaderParams()) - { - mPath = pPath; - mLabelParams = pLabelParams; - mSeparatorParams = pSeparatorParams; - mConverterParams = pConverterParams; - mLineReaderParams = pLineReaderParams; + /** + * @brief specifies whether new documents should use CR/LF instead of LF. + */ + bool mHasCR; + + /** + * @brief specifies whether to allow line breaks in quoted text. + */ + bool mQuotedLinebreaks; + + /** + * @brief specifies whether to automatically dequote cell data. + */ + bool mAutoQuote; +}; + +/** + * @brief Datastructure holding parameters controlling how special line + * formats should be treated. + */ +struct LineReaderParams { + /** + * @brief Constructor + * @param pSkipCommentLines specifies whether to skip lines prefixed + * with mCommentPrefix. Default: false + * @param pCommentPrefix specifies which prefix character to indicate + * a comment line. Default: # + * @param pSkipEmptyLines specifies whether to skip empty lines. + * Default: false + */ + explicit LineReaderParams(const bool pSkipCommentLines = false, + const char pCommentPrefix = '#', + const bool pSkipEmptyLines = false) + : mSkipCommentLines(pSkipCommentLines), mCommentPrefix(pCommentPrefix), + mSkipEmptyLines(pSkipEmptyLines) {} + + /** + * @brief specifies whether to skip lines prefixed with mCommentPrefix. + */ + bool mSkipCommentLines; + + /** + * @brief specifies which prefix character to indicate a comment line. + */ + char mCommentPrefix; + + /** + * @brief specifies whether to skip empty lines. + */ + bool mSkipEmptyLines; +}; + +/** + * @brief Class representing a CSV document. + */ +class Document { +public: + /** + * @brief Constructor + * @param pPath specifies the path of an existing CSV-file + * to populate the Document data with. + * @param pLabelParams specifies which row and column should be + * treated as labels. + * @param pSeparatorParams specifies which field and row separators + * should be used. + * @param pConverterParams specifies how invalid numbers (including + * empty strings) should be handled. + * @param pLineReaderParams specifies how special line formats should be + * treated. + */ + explicit Document( + const std::string &pPath = std::string(), + const LabelParams &pLabelParams = LabelParams(), + const SeparatorParams &pSeparatorParams = SeparatorParams(), + const ConverterParams &pConverterParams = ConverterParams(), + const LineReaderParams &pLineReaderParams = LineReaderParams()) + : mPath(pPath), mLabelParams(pLabelParams), + mSeparatorParams(pSeparatorParams), mConverterParams(pConverterParams), + mLineReaderParams(pLineReaderParams) { + if (!mPath.empty()) { ReadCsv(); } + } - /** - * @brief Read Document data from stream. - * @param pStream specifies an input stream to read CSV data from. - * @param pLabelParams specifies which row and column should be treated as labels. - * @param pSeparatorParams specifies which field and row separators should be used. - * @param pConverterParams specifies how invalid numbers (including empty strings) should be - * handled. - * @param pLineReaderParams specifies how special line formats should be treated. - */ - void Load(std::istream& pStream, - const LabelParams& pLabelParams = LabelParams(), - const SeparatorParams& pSeparatorParams = SeparatorParams(), - const ConverterParams& pConverterParams = ConverterParams(), - const LineReaderParams& pLineReaderParams = LineReaderParams()) - { - mPath = ""; - mLabelParams = pLabelParams; - mSeparatorParams = pSeparatorParams; - mConverterParams = pConverterParams; - mLineReaderParams = pLineReaderParams; - ReadCsv(pStream); - } - - /** - * @brief Write Document data to file. - * @param pPath optionally specifies the path where the CSV-file will be created - * (if not specified, the original path provided when creating or - * loading the Document data will be used). - */ - void Save(const std::string& pPath = std::string()) - { - if (!pPath.empty()) - { - mPath = pPath; - } - WriteCsv(); - } + /** + * @brief Constructor + * @param pStream specifies an input stream to read CSV data + * from. + * @param pLabelParams specifies which row and column should be + * treated as labels. + * @param pSeparatorParams specifies which field and row separators + * should be used. + * @param pConverterParams specifies how invalid numbers (including + * empty strings) should be handled. + * @param pLineReaderParams specifies how special line formats should be + * treated. + */ + explicit Document( + std::istream &pStream, const LabelParams &pLabelParams = LabelParams(), + const SeparatorParams &pSeparatorParams = SeparatorParams(), + const ConverterParams &pConverterParams = ConverterParams(), + const LineReaderParams &pLineReaderParams = LineReaderParams()) + : mPath(), mLabelParams(pLabelParams), mSeparatorParams(pSeparatorParams), + mConverterParams(pConverterParams), + mLineReaderParams(pLineReaderParams) { + ReadCsv(pStream); + } - /** - * @brief Write Document data to stream. - * @param pStream specifies an output stream to write the data to. - */ - void Save(std::ostream& pStream) - { - WriteCsv(pStream); + /** + * @brief Read Document data from file. + * @param pPath specifies the path of an existing CSV-file + * to populate the Document data with. + * @param pLabelParams specifies which row and column should be + * treated as labels. + * @param pSeparatorParams specifies which field and row separators + * should be used. + * @param pConverterParams specifies how invalid numbers (including + * empty strings) should be handled. + * @param pLineReaderParams specifies how special line formats should be + * treated. + */ + void Load(const std::string &pPath, + const LabelParams &pLabelParams = LabelParams(), + const SeparatorParams &pSeparatorParams = SeparatorParams(), + const ConverterParams &pConverterParams = ConverterParams(), + const LineReaderParams &pLineReaderParams = LineReaderParams()) { + mPath = pPath; + mLabelParams = pLabelParams; + mSeparatorParams = pSeparatorParams; + mConverterParams = pConverterParams; + mLineReaderParams = pLineReaderParams; + ReadCsv(); + } + + /** + * @brief Read Document data from stream. + * @param pStream specifies an input stream to read CSV data + * from. + * @param pLabelParams specifies which row and column should be + * treated as labels. + * @param pSeparatorParams specifies which field and row separators + * should be used. + * @param pConverterParams specifies how invalid numbers (including + * empty strings) should be handled. + * @param pLineReaderParams specifies how special line formats should be + * treated. + */ + void Load(std::istream &pStream, + const LabelParams &pLabelParams = LabelParams(), + const SeparatorParams &pSeparatorParams = SeparatorParams(), + const ConverterParams &pConverterParams = ConverterParams(), + const LineReaderParams &pLineReaderParams = LineReaderParams()) { + mPath = ""; + mLabelParams = pLabelParams; + mSeparatorParams = pSeparatorParams; + mConverterParams = pConverterParams; + mLineReaderParams = pLineReaderParams; + ReadCsv(pStream); + } + + /** + * @brief Write Document data to file. + * @param pPath optionally specifies the path where the + * CSV-file will be created (if not specified, the original path provided when + * creating or loading the Document data will be used). + */ + void Save(const std::string &pPath = std::string()) { + if (!pPath.empty()) { + mPath = pPath; } + WriteCsv(); + } - /** - * @brief Clears loaded Document data. - * - */ - void Clear() - { - mData.clear(); - mColumnNames.clear(); - mRowNames.clear(); + /** + * @brief Write Document data to stream. + * @param pStream specifies an output stream to write the data + * to. + */ + void Save(std::ostream &pStream) { WriteCsv(pStream); } + + /** + * @brief Clears loaded Document data. + * + */ + void Clear() { + mData.clear(); + mColumnNames.clear(); + mRowNames.clear(); #ifdef HAS_CODECVT - mIsUtf16 = false; - mIsLE = false; + mIsUtf16 = false; + mIsLE = false; #endif - } + } - /** - * @brief Get column index by name. - * @param pColumnName column label name. - * @returns zero-based column index. - */ - ssize_t GetColumnIdx(const std::string& pColumnName) const - { - if (mLabelParams.mColumnNameIdx >= 0) - { - if (mColumnNames.find(pColumnName) != mColumnNames.end()) - { - return mColumnNames.at(pColumnName) - (mLabelParams.mRowNameIdx + 1); - } + /** + * @brief Get column index by name. + * @param pColumnName column label name. + * @returns zero-based column index. + */ + ssize_t GetColumnIdx(const std::string &pColumnName) const { + if (mLabelParams.mColumnNameIdx >= 0) { + if (mColumnNames.find(pColumnName) != mColumnNames.end()) { + return mColumnNames.at(pColumnName) - (mLabelParams.mRowNameIdx + 1); } - return -1; } + return -1; + } - /** - * @brief Get column by index. - * @param pColumnIdx zero-based column index. - * @returns vector of column data. - */ - template - std::vector GetColumn(const size_t pColumnIdx) const - { - const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); - std::vector column; - Converter converter(mConverterParams); - for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) - { - if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) - { - if (columnIdx < static_cast(itRow->size())) - { - T val; - converter.ToVal(itRow->at(columnIdx), val); - column.push_back(val); - } - else - { - const std::string errStr = "requested column index " + - std::to_string(columnIdx - (mLabelParams.mRowNameIdx + 1)) + " >= " + + /** + * @brief Get column by index. + * @param pColumnIdx zero-based column index. + * @returns vector of column data. + */ + template + std::vector GetColumn(const size_t pColumnIdx) const { + const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + std::vector column; + Converter converter(mConverterParams); + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) { + if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) { + if (columnIdx < static_cast(itRow->size())) { + T val; + converter.ToVal(itRow->at(columnIdx), val); + column.push_back(val); + } else { + const std::string errStr = + "requested column index " + + std::to_string(columnIdx - (mLabelParams.mRowNameIdx + 1)) + + " >= " + std::to_string(itRow->size() - (mLabelParams.mRowNameIdx + 1)) + " (number of columns on row index " + std::to_string(std::distance(mData.begin(), itRow) - - (mLabelParams.mColumnNameIdx + 1)) + ")"; - throw std::out_of_range(errStr); - } + (mLabelParams.mColumnNameIdx + 1)) + + ")"; + throw std::out_of_range(errStr); } } - return column; } + return column; + } - /** - * @brief Get column by index. - * @param pColumnIdx zero-based column index. - * @param pToVal conversion function. - * @returns vector of column data. - */ - template - std::vector GetColumn(const size_t pColumnIdx, ConvFunc pToVal) const - { - const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); - std::vector column; - for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) - { - if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) - { - T val; - pToVal(itRow->at(columnIdx), val); - column.push_back(val); - } - } - return column; + /** + * @brief Get column by index. + * @param pColumnIdx zero-based column index. + * @param pToVal conversion function. + * @returns vector of column data. + */ + template + std::vector GetColumn(const size_t pColumnIdx, ConvFunc pToVal) const { + const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + std::vector column; + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) { + if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) { + T val; + pToVal(itRow->at(columnIdx), val); + column.push_back(val); + } + } + return column; + } + + /** + * @brief Get column by name. + * @param pColumnName column label name. + * @returns vector of column data. + */ + template + std::vector GetColumn(const std::string &pColumnName) const { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); } + return GetColumn(columnIdx); + } - /** - * @brief Get column by name. - * @param pColumnName column label name. - * @returns vector of column data. - */ - template - std::vector GetColumn(const std::string& pColumnName) const - { - const ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); - } - return GetColumn(columnIdx); + /** + * @brief Get column by name. + * @param pColumnName column label name. + * @param pToVal conversion function. + * @returns vector of column data. + */ + template + std::vector GetColumn(const std::string &pColumnName, + ConvFunc pToVal) const { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); + } + return GetColumn(columnIdx, pToVal); + } + + /** + * @brief Set column by index. + * @param pColumnIdx zero-based column index. + * @param pColumn vector of column data. + */ + template + void SetColumn(const size_t pColumnIdx, const std::vector &pColumn) { + const size_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + + while (pColumn.size() + (mLabelParams.mColumnNameIdx + 1) > + GetDataRowCount()) { + std::vector row; + row.resize(GetDataColumnCount()); + mData.push_back(row); } - /** - * @brief Get column by name. - * @param pColumnName column label name. - * @param pToVal conversion function. - * @returns vector of column data. - */ - template - std::vector GetColumn(const std::string& pColumnName, ConvFunc pToVal) const - { - const ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); + if ((columnIdx + 1) > GetDataColumnCount()) { + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) { + itRow->resize(columnIdx + 1 + (mLabelParams.mRowNameIdx + 1)); } - return GetColumn(columnIdx, pToVal); } - /** - * @brief Set column by index. - * @param pColumnIdx zero-based column index. - * @param pColumn vector of column data. - */ - template - void SetColumn(const size_t pColumnIdx, const std::vector& pColumn) - { - const size_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + Converter converter(mConverterParams); + for (auto itRow = pColumn.begin(); itRow != pColumn.end(); ++itRow) { + std::string str; + converter.ToStr(*itRow, str); + mData + .at(std::distance(pColumn.begin(), itRow) + + (mLabelParams.mColumnNameIdx + 1)) + .at(columnIdx) = str; + } + } - while (pColumn.size() + (mLabelParams.mColumnNameIdx + 1) > GetDataRowCount()) - { - std::vector row; - row.resize(GetDataColumnCount()); - mData.push_back(row); - } + /** + * @brief Set column by name. + * @param pColumnName column label name. + * @param pColumn vector of column data. + */ + template + void SetColumn(const std::string &pColumnName, + const std::vector &pColumn) { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); + } + SetColumn(columnIdx, pColumn); + } - if ((columnIdx + 1) > GetDataColumnCount()) - { - for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) - { - itRow->resize(columnIdx + 1 + (mLabelParams.mRowNameIdx + 1)); - } - } + /** + * @brief Remove column by index. + * @param pColumnIdx zero-based column index. + */ + void RemoveColumn(const size_t pColumnIdx) { + const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) { + itRow->erase(itRow->begin() + columnIdx); + } + } + + /** + * @brief Remove column by name. + * @param pColumnName column label name. + */ + void RemoveColumn(const std::string &pColumnName) { + ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); + } + + RemoveColumn(columnIdx); + } + /** + * @brief Insert column at specified index. + * @param pColumnIdx zero-based column index. + * @param pColumn vector of column data (optional argument). + * @param pColumnName column label name (optional argument). + */ + template + void InsertColumn(const size_t pColumnIdx, + const std::vector &pColumn = std::vector(), + const std::string &pColumnName = std::string()) { + const size_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + + std::vector column; + if (pColumn.empty()) { + column.resize(GetDataRowCount()); + } else { + column.resize(pColumn.size() + (mLabelParams.mColumnNameIdx + 1)); Converter converter(mConverterParams); - for (auto itRow = pColumn.begin(); itRow != pColumn.end(); ++itRow) - { + for (auto itRow = pColumn.begin(); itRow != pColumn.end(); ++itRow) { std::string str; converter.ToStr(*itRow, str); - mData.at(std::distance(pColumn.begin(), itRow) + (mLabelParams.mColumnNameIdx + 1)).at(columnIdx) = str; + const size_t rowIdx = std::distance(pColumn.begin(), itRow) + + (mLabelParams.mColumnNameIdx + 1); + column.at(rowIdx) = str; } } - /** - * @brief Set column by name. - * @param pColumnName column label name. - * @param pColumn vector of column data. - */ - template - void SetColumn(const std::string& pColumnName, const std::vector& pColumn) - { - const ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); - } - SetColumn(columnIdx, pColumn); + while (column.size() > GetDataRowCount()) { + std::vector row; + const size_t columnCount = + std::max(static_cast(mLabelParams.mColumnNameIdx + 1), + GetDataColumnCount()); + row.resize(columnCount); + mData.push_back(row); } - /** - * @brief Remove column by index. - * @param pColumnIdx zero-based column index. - */ - void RemoveColumn(const size_t pColumnIdx) - { - const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); - for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) - { - itRow->erase(itRow->begin() + columnIdx); - } + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) { + const size_t rowIdx = std::distance(mData.begin(), itRow); + itRow->insert(itRow->begin() + columnIdx, column.at(rowIdx)); } - /** - * @brief Remove column by name. - * @param pColumnName column label name. - */ - void RemoveColumn(const std::string& pColumnName) - { - ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); - } - - RemoveColumn(columnIdx); + if (!pColumnName.empty()) { + SetColumnName(pColumnIdx, pColumnName); } + } - /** - * @brief Insert column at specified index. - * @param pColumnIdx zero-based column index. - * @param pColumn vector of column data (optional argument). - * @param pColumnName column label name (optional argument). - */ - template - void InsertColumn(const size_t pColumnIdx, const std::vector& pColumn = std::vector(), - const std::string& pColumnName = std::string()) - { - const size_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + /** + * @brief Get number of data columns (excluding label columns). + * @returns column count. + */ + size_t GetColumnCount() const { + const ssize_t count = + static_cast((mData.size() > 0) ? mData.at(0).size() : 0) - + (mLabelParams.mRowNameIdx + 1); + return (count >= 0) ? count : 0; + } - std::vector column; - if (pColumn.empty()) - { - column.resize(GetDataRowCount()); - } - else - { - column.resize(pColumn.size() + (mLabelParams.mColumnNameIdx + 1)); - Converter converter(mConverterParams); - for (auto itRow = pColumn.begin(); itRow != pColumn.end(); ++itRow) - { - std::string str; - converter.ToStr(*itRow, str); - const size_t rowIdx = std::distance(pColumn.begin(), itRow) + (mLabelParams.mColumnNameIdx + 1); - column.at(rowIdx) = str; - } + /** + * @brief Get row index by name. + * @param pRowName row label name. + * @returns zero-based row index. + */ + ssize_t GetRowIdx(const std::string &pRowName) const { + if (mLabelParams.mRowNameIdx >= 0) { + if (mRowNames.find(pRowName) != mRowNames.end()) { + return mRowNames.at(pRowName) - (mLabelParams.mColumnNameIdx + 1); } + } + return -1; + } - while (column.size() > GetDataRowCount()) - { - std::vector row; - const size_t columnCount = std::max(static_cast(mLabelParams.mColumnNameIdx + 1), - GetDataColumnCount()); - row.resize(columnCount); - mData.push_back(row); - } + /** + * @brief Get row by index. + * @param pRowIdx zero-based row index. + * @returns vector of row data. + */ + template std::vector GetRow(const size_t pRowIdx) const { + const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + std::vector row; + Converter converter(mConverterParams); + for (auto itCol = mData.at(rowIdx).begin(); itCol != mData.at(rowIdx).end(); + ++itCol) { + if (std::distance(mData.at(rowIdx).begin(), itCol) > + mLabelParams.mRowNameIdx) { + T val; + converter.ToVal(*itCol, val); + row.push_back(val); + } + } + return row; + } - for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) - { - const size_t rowIdx = std::distance(mData.begin(), itRow); - itRow->insert(itRow->begin() + columnIdx, column.at(rowIdx)); - } + /** + * @brief Get row by index. + * @param pRowIdx zero-based row index. + * @param pToVal conversion function. + * @returns vector of row data. + */ + template + std::vector GetRow(const size_t pRowIdx, ConvFunc pToVal) const { + const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + std::vector row; + Converter converter(mConverterParams); + for (auto itCol = mData.at(rowIdx).begin(); itCol != mData.at(rowIdx).end(); + ++itCol) { + if (std::distance(mData.at(rowIdx).begin(), itCol) > + mLabelParams.mRowNameIdx) { + T val; + pToVal(*itCol, val); + row.push_back(val); + } + } + return row; + } - if (!pColumnName.empty()) - { - SetColumnName(pColumnIdx, pColumnName); - } + /** + * @brief Get row by name. + * @param pRowName row label name. + * @returns vector of row data. + */ + template + std::vector GetRow(const std::string &pRowName) const { + ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); } + return GetRow(rowIdx); + } - /** - * @brief Get number of data columns (excluding label columns). - * @returns column count. - */ - size_t GetColumnCount() const - { - const ssize_t count = static_cast((mData.size() > 0) ? mData.at(0).size() : 0) - - (mLabelParams.mRowNameIdx + 1); - return (count >= 0) ? count : 0; + /** + * @brief Get row by name. + * @param pRowName row label name. + * @param pToVal conversion function. + * @returns vector of row data. + */ + template + std::vector GetRow(const std::string &pRowName, ConvFunc pToVal) const { + ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); } + return GetRow(rowIdx, pToVal); + } - /** - * @brief Get row index by name. - * @param pRowName row label name. - * @returns zero-based row index. - */ - ssize_t GetRowIdx(const std::string& pRowName) const - { - if (mLabelParams.mRowNameIdx >= 0) - { - if (mRowNames.find(pRowName) != mRowNames.end()) - { - return mRowNames.at(pRowName) - (mLabelParams.mColumnNameIdx + 1); - } - } - return -1; - } + /** + * @brief Set row by index. + * @param pRowIdx zero-based row index. + * @param pRow vector of row data. + */ + template + void SetRow(const size_t pRowIdx, const std::vector &pRow) { + const size_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - /** - * @brief Get row by index. - * @param pRowIdx zero-based row index. - * @returns vector of row data. - */ - template - std::vector GetRow(const size_t pRowIdx) const - { - const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - std::vector row; - Converter converter(mConverterParams); - for (auto itCol = mData.at(rowIdx).begin(); itCol != mData.at(rowIdx).end(); ++itCol) - { - if (std::distance(mData.at(rowIdx).begin(), itCol) > mLabelParams.mRowNameIdx) - { - T val; - converter.ToVal(*itCol, val); - row.push_back(val); - } - } - return row; + while ((rowIdx + 1) > GetDataRowCount()) { + std::vector row; + row.resize(GetDataColumnCount()); + mData.push_back(row); } - /** - * @brief Get row by index. - * @param pRowIdx zero-based row index. - * @param pToVal conversion function. - * @returns vector of row data. - */ - template - std::vector GetRow(const size_t pRowIdx, ConvFunc pToVal) const - { - const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - std::vector row; - Converter converter(mConverterParams); - for (auto itCol = mData.at(rowIdx).begin(); itCol != mData.at(rowIdx).end(); ++itCol) - { - if (std::distance(mData.at(rowIdx).begin(), itCol) > mLabelParams.mRowNameIdx) - { - T val; - pToVal(*itCol, val); - row.push_back(val); - } + if (pRow.size() > GetDataColumnCount()) { + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) { + itRow->resize(pRow.size() + (mLabelParams.mRowNameIdx + 1)); } - return row; } - /** - * @brief Get row by name. - * @param pRowName row label name. - * @returns vector of row data. - */ - template - std::vector GetRow(const std::string& pRowName) const - { - ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } - return GetRow(rowIdx); + Converter converter(mConverterParams); + for (auto itCol = pRow.begin(); itCol != pRow.end(); ++itCol) { + std::string str; + converter.ToStr(*itCol, str); + mData.at(rowIdx).at(std::distance(pRow.begin(), itCol) + + (mLabelParams.mRowNameIdx + 1)) = str; } + } - /** - * @brief Get row by name. - * @param pRowName row label name. - * @param pToVal conversion function. - * @returns vector of row data. - */ - template - std::vector GetRow(const std::string& pRowName, ConvFunc pToVal) const - { - ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } - return GetRow(rowIdx, pToVal); + /** + * @brief Set row by name. + * @param pRowName row label name. + * @param pRow vector of row data. + */ + template + void SetRow(const std::string &pRowName, const std::vector &pRow) { + ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); } + return SetRow(rowIdx, pRow); + } - /** - * @brief Set row by index. - * @param pRowIdx zero-based row index. - * @param pRow vector of row data. - */ - template - void SetRow(const size_t pRowIdx, const std::vector& pRow) - { - const size_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + /** + * @brief Remove row by index. + * @param pRowIdx zero-based row index. + */ + void RemoveRow(const size_t pRowIdx) { + const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + mData.erase(mData.begin() + rowIdx); + } - while ((rowIdx + 1) > GetDataRowCount()) - { - std::vector row; - row.resize(GetDataColumnCount()); - mData.push_back(row); - } + /** + * @brief Remove row by name. + * @param pRowName row label name. + */ + void RemoveRow(const std::string &pRowName) { + ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); + } - if (pRow.size() > GetDataColumnCount()) - { - for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) - { - itRow->resize(pRow.size() + (mLabelParams.mRowNameIdx + 1)); - } - } + RemoveRow(rowIdx); + } + /** + * @brief Insert row at specified index. + * @param pRowIdx zero-based row index. + * @param pRow vector of row data (optional argument). + * @param pRowName row label name (optional argument). + */ + template + void InsertRow(const size_t pRowIdx, + const std::vector &pRow = std::vector(), + const std::string &pRowName = std::string()) { + const size_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + + std::vector row; + if (pRow.empty()) { + row.resize(GetDataColumnCount()); + } else { + row.resize(pRow.size() + (mLabelParams.mRowNameIdx + 1)); Converter converter(mConverterParams); - for (auto itCol = pRow.begin(); itCol != pRow.end(); ++itCol) - { + for (auto itCol = pRow.begin(); itCol != pRow.end(); ++itCol) { std::string str; converter.ToStr(*itCol, str); - mData.at(rowIdx).at(std::distance(pRow.begin(), itCol) + (mLabelParams.mRowNameIdx + 1)) = str; + row.at(std::distance(pRow.begin(), itCol) + + (mLabelParams.mRowNameIdx + 1)) = str; } } - /** - * @brief Set row by name. - * @param pRowName row label name. - * @param pRow vector of row data. - */ - template - void SetRow(const std::string& pRowName, const std::vector& pRow) - { - ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } - return SetRow(rowIdx, pRow); + while (rowIdx > GetDataRowCount()) { + std::vector tempRow; + tempRow.resize(GetDataColumnCount()); + mData.push_back(tempRow); } - /** - * @brief Remove row by index. - * @param pRowIdx zero-based row index. - */ - void RemoveRow(const size_t pRowIdx) - { - const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - mData.erase(mData.begin() + rowIdx); - } + mData.insert(mData.begin() + rowIdx, row); - /** - * @brief Remove row by name. - * @param pRowName row label name. - */ - void RemoveRow(const std::string& pRowName) - { - ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } - - RemoveRow(rowIdx); + if (!pRowName.empty()) { + SetRowName(pRowIdx, pRowName); } + } - /** - * @brief Insert row at specified index. - * @param pRowIdx zero-based row index. - * @param pRow vector of row data (optional argument). - * @param pRowName row label name (optional argument). - */ - template - void InsertRow(const size_t pRowIdx, const std::vector& pRow = std::vector(), - const std::string& pRowName = std::string()) - { - const size_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - - std::vector row; - if (pRow.empty()) - { - row.resize(GetDataColumnCount()); - } - else - { - row.resize(pRow.size() + (mLabelParams.mRowNameIdx + 1)); - Converter converter(mConverterParams); - for (auto itCol = pRow.begin(); itCol != pRow.end(); ++itCol) - { - std::string str; - converter.ToStr(*itCol, str); - row.at(std::distance(pRow.begin(), itCol) + (mLabelParams.mRowNameIdx + 1)) = str; - } - } + /** + * @brief Get number of data rows (excluding label rows). + * @returns row count. + */ + size_t GetRowCount() const { + const ssize_t count = + static_cast(mData.size()) - (mLabelParams.mColumnNameIdx + 1); + return (count >= 0) ? count : 0; + } - while (rowIdx > GetDataRowCount()) - { - std::vector tempRow; - tempRow.resize(GetDataColumnCount()); - mData.push_back(tempRow); - } + /** + * @brief Get cell by index. + * @param pColumnIdx zero-based column index. + * @param pRowIdx zero-based row index. + * @returns cell data. + */ + template + T GetCell(const size_t pColumnIdx, const size_t pRowIdx) const { + const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + + T val; + Converter converter(mConverterParams); + converter.ToVal(mData.at(rowIdx).at(columnIdx), val); + return val; + } - mData.insert(mData.begin() + rowIdx, row); + /** + * @brief Get cell by index. + * @param pColumnIdx zero-based column index. + * @param pRowIdx zero-based row index. + * @param pToVal conversion function. + * @returns cell data. + */ + template + T GetCell(const size_t pColumnIdx, const size_t pRowIdx, + ConvFunc pToVal) const { + const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + + T val; + pToVal(mData.at(rowIdx).at(columnIdx), val); + return val; + } - if (!pRowName.empty()) - { - SetRowName(pRowIdx, pRowName); - } + /** + * @brief Get cell by name. + * @param pColumnName column label name. + * @param pRowName row label name. + * @returns cell data. + */ + template + T GetCell(const std::string &pColumnName, const std::string &pRowName) const { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); } - /** - * @brief Get number of data rows (excluding label rows). - * @returns row count. - */ - size_t GetRowCount() const - { - const ssize_t count = static_cast(mData.size()) - (mLabelParams.mColumnNameIdx + 1); - return (count >= 0) ? count : 0; - } - - /** - * @brief Get cell by index. - * @param pColumnIdx zero-based column index. - * @param pRowIdx zero-based row index. - * @returns cell data. - */ - template - T GetCell(const size_t pColumnIdx, const size_t pRowIdx) const - { - const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); - const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - - T val; - Converter converter(mConverterParams); - converter.ToVal(mData.at(rowIdx).at(columnIdx), val); - return val; - } - - /** - * @brief Get cell by index. - * @param pColumnIdx zero-based column index. - * @param pRowIdx zero-based row index. - * @param pToVal conversion function. - * @returns cell data. - */ - template - T GetCell(const size_t pColumnIdx, const size_t pRowIdx, ConvFunc pToVal) const - { - const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); - const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - - T val; - pToVal(mData.at(rowIdx).at(columnIdx), val); - return val; - } - - /** - * @brief Get cell by name. - * @param pColumnName column label name. - * @param pRowName row label name. - * @returns cell data. - */ - template - T GetCell(const std::string& pColumnName, const std::string& pRowName) const - { - const ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); - } + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); + } - const ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } + return GetCell(columnIdx, rowIdx); + } - return GetCell(columnIdx, rowIdx); + /** + * @brief Get cell by name. + * @param pColumnName column label name. + * @param pRowName row label name. + * @param pToVal conversion function. + * @returns cell data. + */ + template + T GetCell(const std::string &pColumnName, const std::string &pRowName, + ConvFunc pToVal) const { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); } - /** - * @brief Get cell by name. - * @param pColumnName column label name. - * @param pRowName row label name. - * @param pToVal conversion function. - * @returns cell data. - */ - template - T GetCell(const std::string& pColumnName, const std::string& pRowName, ConvFunc pToVal) const - { - const ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); - } + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); + } - const ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } + return GetCell(columnIdx, rowIdx, pToVal); + } - return GetCell(columnIdx, rowIdx, pToVal); + /** + * @brief Get cell by column name and row index. + * @param pColumnName column label name. + * @param pRowIdx zero-based row index. + * @returns cell data. + */ + template + T GetCell(const std::string &pColumnName, const size_t pRowIdx) const { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); } - /** - * @brief Get cell by column name and row index. - * @param pColumnName column label name. - * @param pRowIdx zero-based row index. - * @returns cell data. - */ - template - T GetCell(const std::string& pColumnName, const size_t pRowIdx) const - { - const ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); - } + return GetCell(columnIdx, pRowIdx); + } - return GetCell(columnIdx, pRowIdx); + /** + * @brief Get cell by column name and row index. + * @param pColumnName column label name. + * @param pRowIdx zero-based row index. + * @param pToVal conversion function. + * @returns cell data. + */ + template + T GetCell(const std::string &pColumnName, const size_t pRowIdx, + ConvFunc pToVal) const { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); } - /** - * @brief Get cell by column name and row index. - * @param pColumnName column label name. - * @param pRowIdx zero-based row index. - * @param pToVal conversion function. - * @returns cell data. - */ - template - T GetCell(const std::string& pColumnName, const size_t pRowIdx, ConvFunc pToVal) const - { - const ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); - } + return GetCell(columnIdx, pRowIdx, pToVal); + } - return GetCell(columnIdx, pRowIdx, pToVal); + /** + * @brief Get cell by column index and row name. + * @param pColumnIdx zero-based column index. + * @param pRowName row label name. + * @returns cell data. + */ + template + T GetCell(const size_t pColumnIdx, const std::string &pRowName) const { + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); } - /** - * @brief Get cell by column index and row name. - * @param pColumnIdx zero-based column index. - * @param pRowName row label name. - * @returns cell data. - */ - template - T GetCell(const size_t pColumnIdx, const std::string& pRowName) const - { - const ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } + return GetCell(pColumnIdx, rowIdx); + } - return GetCell(pColumnIdx, rowIdx); + /** + * @brief Get cell by column index and row name. + * @param pColumnIdx zero-based column index. + * @param pRowName row label name. + * @param pToVal conversion function. + * @returns cell data. + */ + template + T GetCell(const size_t pColumnIdx, const std::string &pRowName, + ConvFunc pToVal) const { + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); } - /** - * @brief Get cell by column index and row name. - * @param pColumnIdx zero-based column index. - * @param pRowName row label name. - * @param pToVal conversion function. - * @returns cell data. - */ - template - T GetCell(const size_t pColumnIdx, const std::string& pRowName, ConvFunc pToVal) const - { - const ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } + return GetCell(pColumnIdx, rowIdx, pToVal); + } - return GetCell(pColumnIdx, rowIdx, pToVal); + /** + * @brief Set cell by index. + * @param pRowIdx zero-based row index. + * @param pColumnIdx zero-based column index. + * @param pCell cell data. + */ + template + void SetCell(const size_t pColumnIdx, const size_t pRowIdx, const T &pCell) { + const size_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + const size_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + + while ((rowIdx + 1) > GetDataRowCount()) { + std::vector row; + row.resize(GetDataColumnCount()); + mData.push_back(row); } - /** - * @brief Set cell by index. - * @param pRowIdx zero-based row index. - * @param pColumnIdx zero-based column index. - * @param pCell cell data. - */ - template - void SetCell(const size_t pColumnIdx, const size_t pRowIdx, const T& pCell) - { - const size_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); - const size_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - - while ((rowIdx + 1) > GetDataRowCount()) - { - std::vector row; - row.resize(GetDataColumnCount()); - mData.push_back(row); - } - - if ((columnIdx + 1) > GetDataColumnCount()) - { - for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) - { - itRow->resize(columnIdx + 1); - } + if ((columnIdx + 1) > GetDataColumnCount()) { + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) { + itRow->resize(columnIdx + 1); } + } - std::string str; - Converter converter(mConverterParams); - converter.ToStr(pCell, str); - mData.at(rowIdx).at(columnIdx) = str; - } - - /** - * @brief Set cell by name. - * @param pColumnName column label name. - * @param pRowName row label name. - * @param pCell cell data. - */ - template - void SetCell(const std::string& pColumnName, const std::string& pRowName, const T& pCell) - { - const ssize_t columnIdx = GetColumnIdx(pColumnName); - if (columnIdx < 0) - { - throw std::out_of_range("column not found: " + pColumnName); - } + std::string str; + Converter converter(mConverterParams); + converter.ToStr(pCell, str); + mData.at(rowIdx).at(columnIdx) = str; + } - const ssize_t rowIdx = GetRowIdx(pRowName); - if (rowIdx < 0) - { - throw std::out_of_range("row not found: " + pRowName); - } + /** + * @brief Set cell by name. + * @param pColumnName column label name. + * @param pRowName row label name. + * @param pCell cell data. + */ + template + void SetCell(const std::string &pColumnName, const std::string &pRowName, + const T &pCell) { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) { + throw std::out_of_range("column not found: " + pColumnName); + } - SetCell(columnIdx, rowIdx, pCell); + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) { + throw std::out_of_range("row not found: " + pRowName); } - /** - * @brief Get column name - * @param pColumnIdx zero-based column index. - * @returns column name. - */ - std::string GetColumnName(const ssize_t pColumnIdx) - { - const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); - if (mLabelParams.mColumnNameIdx < 0) - { - throw std::out_of_range("column name row index < 0: " + std::to_string(mLabelParams.mColumnNameIdx)); - } + SetCell(columnIdx, rowIdx, pCell); + } - return mData.at(mLabelParams.mColumnNameIdx).at(columnIdx); + /** + * @brief Get column name + * @param pColumnIdx zero-based column index. + * @returns column name. + */ + std::string GetColumnName(const ssize_t pColumnIdx) { + const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + if (mLabelParams.mColumnNameIdx < 0) { + throw std::out_of_range("column name row index < 0: " + + std::to_string(mLabelParams.mColumnNameIdx)); } - /** - * @brief Set column name - * @param pColumnIdx zero-based column index. - * @param pColumnName column name. - */ - void SetColumnName(size_t pColumnIdx, const std::string& pColumnName) - { - const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); - mColumnNames[pColumnName] = columnIdx; - if (mLabelParams.mColumnNameIdx < 0) - { - throw std::out_of_range("column name row index < 0: " + std::to_string(mLabelParams.mColumnNameIdx)); - } + return mData.at(mLabelParams.mColumnNameIdx).at(columnIdx); + } - // increase table size if necessary: - const int rowIdx = mLabelParams.mColumnNameIdx; - if (rowIdx >= static_cast(mData.size())) - { - mData.resize(rowIdx + 1); - } - auto& row = mData[rowIdx]; - if (columnIdx >= static_cast(row.size())) - { - row.resize(columnIdx + 1); - } + /** + * @brief Set column name + * @param pColumnIdx zero-based column index. + * @param pColumnName column name. + */ + void SetColumnName(size_t pColumnIdx, const std::string &pColumnName) { + const ssize_t columnIdx = pColumnIdx + (mLabelParams.mRowNameIdx + 1); + mColumnNames[pColumnName] = columnIdx; + if (mLabelParams.mColumnNameIdx < 0) { + throw std::out_of_range("column name row index < 0: " + + std::to_string(mLabelParams.mColumnNameIdx)); + } - mData.at(mLabelParams.mColumnNameIdx).at(columnIdx) = pColumnName; + // increase table size if necessary: + const int rowIdx = mLabelParams.mColumnNameIdx; + if (rowIdx >= static_cast(mData.size())) { + mData.resize(rowIdx + 1); + } + auto &row = mData[rowIdx]; + if (columnIdx >= static_cast(row.size())) { + row.resize(columnIdx + 1); } - /** - * @brief Get column names - * @returns vector of column names. - */ - std::vector GetColumnNames() - { - if (mLabelParams.mColumnNameIdx >= 0) - { - return std::vector(mData.at(mLabelParams.mColumnNameIdx).begin() + - (mLabelParams.mRowNameIdx + 1), - mData.at(mLabelParams.mColumnNameIdx).end()); - } + mData.at(mLabelParams.mColumnNameIdx).at(columnIdx) = pColumnName; + } - return std::vector(); + /** + * @brief Get column names + * @returns vector of column names. + */ + std::vector GetColumnNames() { + if (mLabelParams.mColumnNameIdx >= 0) { + return std::vector( + mData.at(mLabelParams.mColumnNameIdx).begin() + + (mLabelParams.mRowNameIdx + 1), + mData.at(mLabelParams.mColumnNameIdx).end()); } - /** - * @brief Get row name - * @param pRowIdx zero-based column index. - * @returns row name. - */ - std::string GetRowName(const ssize_t pRowIdx) - { - const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - if (mLabelParams.mRowNameIdx < 0) - { - throw std::out_of_range("row name column index < 0: " + std::to_string(mLabelParams.mRowNameIdx)); - } + return std::vector(); + } - return mData.at(rowIdx).at(mLabelParams.mRowNameIdx); + /** + * @brief Get row name + * @param pRowIdx zero-based column index. + * @returns row name. + */ + std::string GetRowName(const ssize_t pRowIdx) { + const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + if (mLabelParams.mRowNameIdx < 0) { + throw std::out_of_range("row name column index < 0: " + + std::to_string(mLabelParams.mRowNameIdx)); } - /** - * @brief Set row name - * @param pRowIdx zero-based row index. - * @param pRowName row name. - */ - void SetRowName(size_t pRowIdx, const std::string& pRowName) - { - const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); - mRowNames[pRowName] = rowIdx; - if (mLabelParams.mRowNameIdx < 0) - { - throw std::out_of_range("row name column index < 0: " + std::to_string(mLabelParams.mRowNameIdx)); - } + return mData.at(rowIdx).at(mLabelParams.mRowNameIdx); + } - // increase table size if necessary: - if (rowIdx >= static_cast(mData.size())) - { - mData.resize(rowIdx + 1); - } - auto& row = mData[rowIdx]; - if (mLabelParams.mRowNameIdx >= static_cast(row.size())) - { - row.resize(mLabelParams.mRowNameIdx + 1); - } + /** + * @brief Set row name + * @param pRowIdx zero-based row index. + * @param pRowName row name. + */ + void SetRowName(size_t pRowIdx, const std::string &pRowName) { + const ssize_t rowIdx = pRowIdx + (mLabelParams.mColumnNameIdx + 1); + mRowNames[pRowName] = rowIdx; + if (mLabelParams.mRowNameIdx < 0) { + throw std::out_of_range("row name column index < 0: " + + std::to_string(mLabelParams.mRowNameIdx)); + } - mData.at(rowIdx).at(mLabelParams.mRowNameIdx) = pRowName; + // increase table size if necessary: + if (rowIdx >= static_cast(mData.size())) { + mData.resize(rowIdx + 1); + } + auto &row = mData[rowIdx]; + if (mLabelParams.mRowNameIdx >= static_cast(row.size())) { + row.resize(mLabelParams.mRowNameIdx + 1); } - /** - * @brief Get row names - * @returns vector of row names. - */ - std::vector GetRowNames() - { - std::vector rownames; - if (mLabelParams.mRowNameIdx >= 0) - { - for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) - { - if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) - { - rownames.push_back(itRow->at(mLabelParams.mRowNameIdx)); - } + mData.at(rowIdx).at(mLabelParams.mRowNameIdx) = pRowName; + } + + /** + * @brief Get row names + * @returns vector of row names. + */ + std::vector GetRowNames() { + std::vector rownames; + if (mLabelParams.mRowNameIdx >= 0) { + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) { + if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) { + rownames.push_back(itRow->at(mLabelParams.mRowNameIdx)); } } - return rownames; } + return rownames; + } - private: - void ReadCsv() - { - std::ifstream stream; - stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); - stream.open(mPath, std::ios::binary); - ReadCsv(stream); - } +private: + void ReadCsv() { + std::ifstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + stream.open(mPath, std::ios::binary); + ReadCsv(stream); + } - void ReadCsv(std::istream& pStream) - { - Clear(); - pStream.seekg(0, std::ios::end); - std::streamsize length = pStream.tellg(); - pStream.seekg(0, std::ios::beg); + void ReadCsv(std::istream &pStream) { + Clear(); + pStream.seekg(0, std::ios::end); + std::streamsize length = pStream.tellg(); + pStream.seekg(0, std::ios::beg); #ifdef HAS_CODECVT - std::vector bom2b(2, '\0'); - if (length >= 2) - { - pStream.read(bom2b.data(), 2); - pStream.seekg(0, std::ios::beg); - } + std::vector bom2b(2, '\0'); + if (length >= 2) { + pStream.read(bom2b.data(), 2); + pStream.seekg(0, std::ios::beg); + } - static const std::vector bomU16le = { '\xff', '\xfe' }; - static const std::vector bomU16be = { '\xfe', '\xff' }; - if ((bom2b == bomU16le) || (bom2b == bomU16be)) - { - mIsUtf16 = true; - mIsLE = (bom2b == bomU16le); - - std::wifstream wstream; - wstream.exceptions(std::wifstream::failbit | std::wifstream::badbit); - wstream.open(mPath, std::ios::binary); - if (mIsLE) - { - wstream.imbue(std::locale(wstream.getloc(), - new std::codecvt_utf16(std::consume_header | - std::little_endian)>)); - } - else - { - wstream.imbue(std::locale(wstream.getloc(), - new std::codecvt_utf16)); - } - std::wstringstream wss; - wss << wstream.rdbuf(); - std::string utf8 = ToString(wss.str()); - std::stringstream ss(utf8); - ParseCsv(ss, utf8.size()); - } - else + static const std::vector bomU16le = {'\xff', '\xfe'}; + static const std::vector bomU16be = {'\xfe', '\xff'}; + if ((bom2b == bomU16le) || (bom2b == bomU16be)) { + mIsUtf16 = true; + mIsLE = (bom2b == bomU16le); + + std::wifstream wstream; + wstream.exceptions(std::wifstream::failbit | std::wifstream::badbit); + wstream.open(mPath, std::ios::binary); + if (mIsLE) { + wstream.imbue( + std::locale(wstream.getloc(), + new std::codecvt_utf16( + std::consume_header | + std::little_endian)>)); + } else { + wstream.imbue(std::locale( + wstream.getloc(), + new std::codecvt_utf16)); + } + std::wstringstream wss; + wss << wstream.rdbuf(); + std::string utf8 = ToString(wss.str()); + std::stringstream ss(utf8); + ParseCsv(ss, utf8.size()); + } else #endif - { - // check for UTF-8 Byte order mark and skip it when found - if (length >= 3) - { - std::vector bom3b(3, '\0'); - pStream.read(bom3b.data(), 3); - static const std::vector bomU8 = { '\xef', '\xbb', '\xbf' }; - if (bom3b != bomU8) - { - // file does not start with a UTF-8 Byte order mark - pStream.seekg(0, std::ios::beg); - } - else - { - // file did start with a UTF-8 Byte order mark, simply skip it - length -= 3; - } + { + // check for UTF-8 Byte order mark and skip it when found + if (length >= 3) { + std::vector bom3b(3, '\0'); + pStream.read(bom3b.data(), 3); + static const std::vector bomU8 = {'\xef', '\xbb', '\xbf'}; + if (bom3b != bomU8) { + // file does not start with a UTF-8 Byte order mark + pStream.seekg(0, std::ios::beg); + } else { + // file did start with a UTF-8 Byte order mark, simply skip it + length -= 3; } - - ParseCsv(pStream, length); } + + ParseCsv(pStream, length); } + } - void ParseCsv(std::istream& pStream, std::streamsize p_FileLength) - { - const std::streamsize bufLength = 64 * 1024; - std::vector buffer(bufLength); - std::vector row; - std::string cell; - bool quoted = false; - int cr = 0; - int lf = 0; - - while (p_FileLength > 0) - { - std::streamsize readLength = std::min(p_FileLength, bufLength); - pStream.read(buffer.data(), readLength); - for (int i = 0; i < readLength; ++i) - { - if (buffer[i] == '"') - { - if (cell.empty() || cell[0] == '"') - { - quoted = !quoted; - } - cell += buffer[i]; + void ParseCsv(std::istream &pStream, std::streamsize p_FileLength) { + const std::streamsize bufLength = 64 * 1024; + std::vector buffer(bufLength); + std::vector row; + std::string cell; + bool quoted = false; + int cr = 0; + int lf = 0; + + while (p_FileLength > 0) { + std::streamsize readLength = + std::min(p_FileLength, bufLength); + pStream.read(buffer.data(), readLength); + for (int i = 0; i < readLength; ++i) { + if (buffer[i] == '"') { + if (cell.empty() || cell[0] == '"') { + quoted = !quoted; } - else if (buffer[i] == mSeparatorParams.mSeparator) - { - if (!quoted) - { - row.push_back(Unquote(Trim(cell))); - cell.clear(); - } - else - { - cell += buffer[i]; - } + cell += buffer[i]; + } else if (buffer[i] == mSeparatorParams.mSeparator) { + if (!quoted) { + row.push_back(Unquote(Trim(cell))); + cell.clear(); + } else { + cell += buffer[i]; } - else if (buffer[i] == '\r') - { - if (mSeparatorParams.mQuotedLinebreaks && quoted) - { - cell += buffer[i]; - } - else - { - ++cr; - } + } else if (buffer[i] == '\r') { + if (mSeparatorParams.mQuotedLinebreaks && quoted) { + cell += buffer[i]; + } else { + ++cr; } - else if (buffer[i] == '\n') - { - if (mSeparatorParams.mQuotedLinebreaks && quoted) - { - cell += buffer[i]; - } - else - { - ++lf; - if (mLineReaderParams.mSkipEmptyLines && row.empty() && cell.empty()) - { - // skip empty line - } - else - { - row.push_back(Unquote(Trim(cell))); - - if (mLineReaderParams.mSkipCommentLines && !row.at(0).empty() && - (row.at(0)[0] == mLineReaderParams.mCommentPrefix)) - { - // skip comment line - } - else - { - mData.push_back(row); - } - - cell.clear(); - row.clear(); - quoted = false; + } else if (buffer[i] == '\n') { + if (mSeparatorParams.mQuotedLinebreaks && quoted) { + cell += buffer[i]; + } else { + ++lf; + if (mLineReaderParams.mSkipEmptyLines && row.empty() && + cell.empty()) { + // skip empty line + } else { + row.push_back(Unquote(Trim(cell))); + + if (mLineReaderParams.mSkipCommentLines && !row.at(0).empty() && + (row.at(0)[0] == mLineReaderParams.mCommentPrefix)) { + // skip comment line + } else { + mData.push_back(row); } + + cell.clear(); + row.clear(); + quoted = false; } } - else - { - cell += buffer[i]; - } + } else { + cell += buffer[i]; } - p_FileLength -= readLength; } + p_FileLength -= readLength; + } - // Handle last line without linebreak - if (!cell.empty() || !row.empty()) - { - row.push_back(Unquote(Trim(cell))); - cell.clear(); - mData.push_back(row); - row.clear(); - } + // Handle last line without linebreak + if (!cell.empty() || !row.empty()) { + row.push_back(Unquote(Trim(cell))); + cell.clear(); + mData.push_back(row); + row.clear(); + } - // Assume CR/LF if at least half the linebreaks have CR - mSeparatorParams.mHasCR = (cr > (lf / 2)); - - // Set up column labels - if ((mLabelParams.mColumnNameIdx >= 0) && - (static_cast(mData.size()) > mLabelParams.mColumnNameIdx)) - { - int i = 0; - for (auto& columnName : mData[mLabelParams.mColumnNameIdx]) - { - mColumnNames[columnName] = i++; - } + // Assume CR/LF if at least half the linebreaks have CR + mSeparatorParams.mHasCR = (cr > (lf / 2)); + + // Set up column labels + if ((mLabelParams.mColumnNameIdx >= 0) && + (static_cast(mData.size()) > mLabelParams.mColumnNameIdx)) { + int i = 0; + for (auto &columnName : mData[mLabelParams.mColumnNameIdx]) { + mColumnNames[columnName] = i++; } + } - // Set up row labels - if ((mLabelParams.mRowNameIdx >= 0) && - (static_cast(mData.size()) > - (mLabelParams.mColumnNameIdx + 1))) - { - int i = 0; - for (auto& dataRow : mData) - { - if (static_cast(dataRow.size()) > mLabelParams.mRowNameIdx) - { - mRowNames[dataRow[mLabelParams.mRowNameIdx]] = i++; - } + // Set up row labels + if ((mLabelParams.mRowNameIdx >= 0) && + (static_cast(mData.size()) > + (mLabelParams.mColumnNameIdx + 1))) { + int i = 0; + for (auto &dataRow : mData) { + if (static_cast(dataRow.size()) > mLabelParams.mRowNameIdx) { + mRowNames[dataRow[mLabelParams.mRowNameIdx]] = i++; } } } + } - void WriteCsv() const - { + void WriteCsv() const { #ifdef HAS_CODECVT - if (mIsUtf16) - { - std::stringstream ss; - WriteCsv(ss); - std::string utf8 = ss.str(); - std::wstring wstr = ToWString(utf8); - - std::wofstream wstream; - wstream.exceptions(std::wofstream::failbit | std::wofstream::badbit); - wstream.open(mPath, std::ios::binary | std::ios::trunc); - - if (mIsLE) - { - wstream.imbue(std::locale(wstream.getloc(), - new std::codecvt_utf16(std::little_endian)>)); - } - else - { - wstream.imbue(std::locale(wstream.getloc(), - new std::codecvt_utf16)); - } - - wstream << static_cast(0xfeff); - wstream << wstr; - } - else + if (mIsUtf16) { + std::stringstream ss; + WriteCsv(ss); + std::string utf8 = ss.str(); + std::wstring wstr = ToWString(utf8); + + std::wofstream wstream; + wstream.exceptions(std::wofstream::failbit | std::wofstream::badbit); + wstream.open(mPath, std::ios::binary | std::ios::trunc); + + if (mIsLE) { + wstream.imbue( + std::locale(wstream.getloc(), + new std::codecvt_utf16( + std::little_endian)>)); + } else { + wstream.imbue(std::locale(wstream.getloc(), + new std::codecvt_utf16)); + } + + wstream << static_cast(0xfeff); + wstream << wstr; + } else #endif - { - std::ofstream stream; - stream.exceptions(std::ofstream::failbit | std::ofstream::badbit); - stream.open(mPath, std::ios::binary | std::ios::trunc); - WriteCsv(stream); - } + { + std::ofstream stream; + stream.exceptions(std::ofstream::failbit | std::ofstream::badbit); + stream.open(mPath, std::ios::binary | std::ios::trunc); + WriteCsv(stream); } + } - void WriteCsv(std::ostream& pStream) const - { - for (auto itr = mData.begin(); itr != mData.end(); ++itr) - { - for (auto itc = itr->begin(); itc != itr->end(); ++itc) - { - if (mSeparatorParams.mAutoQuote && - ((itc->find(mSeparatorParams.mSeparator) != std::string::npos) || - (itc->find(' ') != std::string::npos))) - { - // escape quotes in string - std::string str = *itc; - ReplaceString(str, "\"", "\"\""); - - pStream << "\"" << str << "\""; - } - else - { - pStream << *itc; - } + void WriteCsv(std::ostream &pStream) const { + for (auto itr = mData.begin(); itr != mData.end(); ++itr) { + for (auto itc = itr->begin(); itc != itr->end(); ++itc) { + if (mSeparatorParams.mAutoQuote && + ((itc->find(mSeparatorParams.mSeparator) != std::string::npos) || + (itc->find(' ') != std::string::npos))) { + // escape quotes in string + std::string str = *itc; + ReplaceString(str, "\"", "\"\""); + + pStream << "\"" << str << "\""; + } else { + pStream << *itc; + } - if (std::distance(itc, itr->end()) > 1) - { - pStream << mSeparatorParams.mSeparator; - } + if (std::distance(itc, itr->end()) > 1) { + pStream << mSeparatorParams.mSeparator; } - pStream << (mSeparatorParams.mHasCR ? "\r\n" : "\n"); } + pStream << (mSeparatorParams.mHasCR ? "\r\n" : "\n"); } + } - size_t GetDataRowCount() const - { - return mData.size(); - } + size_t GetDataRowCount() const { return mData.size(); } - size_t GetDataColumnCount() const - { - return (mData.size() > 0) ? mData.at(0).size() : 0; - } + size_t GetDataColumnCount() const { + return (mData.size() > 0) ? mData.at(0).size() : 0; + } - std::string Trim(const std::string& pStr) - { - if (mSeparatorParams.mTrim) - { - std::string str = pStr; + std::string Trim(const std::string &pStr) { + if (mSeparatorParams.mTrim) { + std::string str = pStr; - // ltrim - str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](int ch) { return !isspace(ch); })); + // ltrim + str.erase(str.begin(), std::find_if(str.begin(), str.end(), + [](int ch) { return !isspace(ch); })); - // rtrim - str.erase(std::find_if(str.rbegin(), str.rend(), [](int ch) { return !isspace(ch); }).base(), str.end()); + // rtrim + str.erase(std::find_if(str.rbegin(), str.rend(), + [](int ch) { return !isspace(ch); }) + .base(), + str.end()); - return str; - } - else - { - return pStr; - } + return str; + } else { + return pStr; } + } - std::string Unquote(const std::string& pStr) - { - if (mSeparatorParams.mAutoQuote && (pStr.size() >= 2) && (pStr.front() == '"') && (pStr.back() == '"')) - { - // remove start/end quotes - std::string str = pStr.substr(1, pStr.size() - 2); + std::string Unquote(const std::string &pStr) { + if (mSeparatorParams.mAutoQuote && (pStr.size() >= 2) && + (pStr.front() == '"') && (pStr.back() == '"')) { + // remove start/end quotes + std::string str = pStr.substr(1, pStr.size() - 2); - // unescape quotes in string - ReplaceString(str, "\"\"", "\""); + // unescape quotes in string + ReplaceString(str, "\"\"", "\""); - return str; - } - else - { - return pStr; - } + return str; + } else { + return pStr; } + } #ifdef HAS_CODECVT #if defined(_MSC_VER) -#pragma warning (disable: 4996) +#pragma warning(disable : 4996) #endif - static std::string ToString(const std::wstring& pWStr) - { - return std::wstring_convert, wchar_t>{ }.to_bytes(pWStr); - } + static std::string ToString(const std::wstring &pWStr) { + return std::wstring_convert, wchar_t>{}.to_bytes( + pWStr); + } - static std::wstring ToWString(const std::string& pStr) - { - return std::wstring_convert, wchar_t>{ }.from_bytes(pStr); - } + static std::wstring ToWString(const std::string &pStr) { + return std::wstring_convert, wchar_t>{} + .from_bytes(pStr); + } #if defined(_MSC_VER) -#pragma warning (default: 4996) +#pragma warning(default : 4996) #endif #endif - static void ReplaceString(std::string& pStr, const std::string& pSearch, const std::string& pReplace) - { - size_t pos = 0; + static void ReplaceString(std::string &pStr, const std::string &pSearch, + const std::string &pReplace) { + size_t pos = 0; - while ((pos = pStr.find(pSearch, pos)) != std::string::npos) - { - pStr.replace(pos, pSearch.size(), pReplace); - pos += pReplace.size(); - } + while ((pos = pStr.find(pSearch, pos)) != std::string::npos) { + pStr.replace(pos, pSearch.size(), pReplace); + pos += pReplace.size(); } + } - private: - std::string mPath; - LabelParams mLabelParams; - SeparatorParams mSeparatorParams; - ConverterParams mConverterParams; - LineReaderParams mLineReaderParams; - std::vector> mData; - std::map mColumnNames; - std::map mRowNames; +private: + std::string mPath; + LabelParams mLabelParams; + SeparatorParams mSeparatorParams; + ConverterParams mConverterParams; + LineReaderParams mLineReaderParams; + std::vector> mData; + std::map mColumnNames; + std::map mRowNames; #ifdef HAS_CODECVT - bool mIsUtf16 = false; - bool mIsLE = false; + bool mIsUtf16 = false; + bool mIsLE = false; #endif - }; -} \ No newline at end of file +}; +} // namespace rapidcsv \ No newline at end of file diff --git a/client/python/setup.py b/client/python/setup.py index 8bc86ae7..453d849a 100644 --- a/client/python/setup.py +++ b/client/python/setup.py @@ -5,17 +5,17 @@ setuptools.setup( name="vdms", - version="0.0.17", + version="0.0.18", author="Chaunté W. Lacewell", author_email="chaunte.w.lacewell@intel.com", description="VDMS Client Module", - install_requires=['protobuf'], + install_requires=["protobuf==3.20.3"], long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/IntelLabs/vdms", license="MIT", packages=setuptools.find_packages(), - python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4', + python_requires=">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4", classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", diff --git a/client/python/vdms/__init__.py b/client/python/vdms/__init__.py index 1ec484f1..7268a1fd 100644 --- a/client/python/vdms/__init__.py +++ b/client/python/vdms/__init__.py @@ -1,4 +1,3 @@ name = "vdms" from .vdms import * - diff --git a/client/python/vdms/queryMessage_pb2.py b/client/python/vdms/queryMessage_pb2.py index 79134502..f751c403 100644 --- a/client/python/vdms/queryMessage_pb2.py +++ b/client/python/vdms/queryMessage_pb2.py @@ -2,9 +2,9 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: queryMessage.proto """Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database # @@protoc_insertion_point(imports) @@ -13,65 +13,13 @@ -DESCRIPTOR = _descriptor.FileDescriptor( - name='queryMessage.proto', - package='VDMS.protobufs', - syntax='proto3', - serialized_options=None, - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x12queryMessage.proto\x12\x0eVDMS.protobufs\"+\n\x0cqueryMessage\x12\x0c\n\x04json\x18\x01 \x01(\t\x12\r\n\x05\x62lobs\x18\x02 \x03(\x0c\x62\x06proto3' -) - - - - -_QUERYMESSAGE = _descriptor.Descriptor( - name='queryMessage', - full_name='VDMS.protobufs.queryMessage', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='json', full_name='VDMS.protobufs.queryMessage.json', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='blobs', full_name='VDMS.protobufs.queryMessage.blobs', index=1, - number=2, type=12, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=38, - serialized_end=81, -) - -DESCRIPTOR.message_types_by_name['queryMessage'] = _QUERYMESSAGE -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -queryMessage = _reflection.GeneratedProtocolMessageType('queryMessage', (_message.Message,), { - 'DESCRIPTOR' : _QUERYMESSAGE, - '__module__' : 'queryMessage_pb2' - # @@protoc_insertion_point(class_scope:VDMS.protobufs.queryMessage) - }) -_sym_db.RegisterMessage(queryMessage) +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12queryMessage.proto\x12\x0eVDMS.protobufs\"+\n\x0cqueryMessage\x12\x0c\n\x04json\x18\x01 \x01(\t\x12\r\n\x05\x62lobs\x18\x02 \x03(\x0c\x62\x06proto3') +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'queryMessage_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _QUERYMESSAGE._serialized_start=38 + _QUERYMESSAGE._serialized_end=81 # @@protoc_insertion_point(module_scope) diff --git a/client/python/vdms/vdms.py b/client/python/vdms/vdms.py index 1c52a9d3..248d6731 100644 --- a/client/python/vdms/vdms.py +++ b/client/python/vdms/vdms.py @@ -38,8 +38,8 @@ # VDMS Protobuf import (autogenerated) from . import queryMessage_pb2 -class vdms(object): +class vdms(object): def __init__(self): self.dataNotUsed = [] self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -49,16 +49,16 @@ def __init__(self): # We use startswith for checking the platform following Python's # documentation: # https://docs.python.org/dev/library/sys.html#sys.platform - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.conn.setsockopt(socket.SOL_TCP, socket.TCP_QUICKACK, 1) self.connected = False - self.last_response = '' + self.last_response = "" def __del__(self): self.conn.close() - def connect(self, host='localhost', port=55555): + def connect(self, host="localhost", port=55555): self.conn.connect((host, port)) self.connected = True @@ -67,10 +67,9 @@ def disconnect(self): self.connected = False # Recieves a json struct as a string - def query(self, query, blob_array = []): - + def query(self, query, blob_array=[]): # Check the query type - if not isinstance(query, str): # assumes json + if not isinstance(query, str): # assumes json query_str = json.dumps(query) else: query_str = query @@ -98,15 +97,15 @@ def query(self, query, blob_array = []): quer.blobs.append(im) # Serialize with protobuf and send - data = quer.SerializeToString(); - sent_len = struct.pack('@I', len(data)) # send size first - self.conn.send( sent_len ) + data = quer.SerializeToString() + sent_len = struct.pack("@I", len(data)) # send size first + self.conn.send(sent_len) self.conn.send(data) # Recieve response recv_len = self.conn.recv(4) - recv_len = struct.unpack('@I', recv_len)[0] - response = b'' + recv_len = struct.unpack("@I", recv_len)[0] + response = b"" while len(response) < recv_len: packet = self.conn.recv(recv_len - len(response)) if not packet: diff --git a/config-vdms.json b/config-vdms.json index 062c4012..0d1e5fb0 100755 --- a/config-vdms.json +++ b/config-vdms.json @@ -6,5 +6,7 @@ // "backup_path":"backups_test", // set this if you want different path to store the back up file "db_root_path": "db", "backup_flag" : "false", + "storage_type": "local", //local, aws, etc + "bucket_name": "minio-bucket", "more-info": "github.com/IntelLabs/vdms" } diff --git a/distributed/adaptive_platform.cpp b/distributed/adaptive_platform.cpp index 9839d9dd..6a1f3ef0 100644 --- a/distributed/adaptive_platform.cpp +++ b/distributed/adaptive_platform.cpp @@ -2,57 +2,49 @@ #include "kafka_receiver.h" #include "kafka_sender.h" -int main( int argc, char* argv[] ){ - std::cout <<"adaptive-multi-modal" <> receivers; - std::vector > senders; - int num_receivers=5; - int num_senders=5; - int num_topics =5; - std::string topics[num_topics]; - for( int i=0; i< num_topics; i++){ - topics[i]="topic_"+ std::to_string(i); - std::cout<< topics[i]<> receivers; + std::vector> senders; + int num_receivers = 5; + int num_senders = 5; + int num_topics = 5; + std::string topics[num_topics]; + for (int i = 0; i < num_topics; i++) { + topics[i] = "topic_" + std::to_string(i); + std::cout << topics[i] << std::endl; + } + Json::Value result = construct_query(); + + std::string q = writer.write(result); + + std::string msg_meta = query_body(q); std::string msg; - for (int i=0; i< num_senders ; i++){ - senders.push_back(std::make_unique(sender_endpoint)); - senders[i]->Init(); - - - } - for( int i=0; i< num_receivers; i++){ - receivers.push_back(std::make_unique(receiver_endpoint)); - receivers.at(i)->Init(); - + for (int i = 0; i < num_senders; i++) { + senders.push_back(std::make_unique(sender_endpoint)); + senders[i]->Init(); + } + for (int i = 0; i < num_receivers; i++) { + receivers.push_back(std::make_unique(receiver_endpoint)); + receivers.at(i)->Init(); + } + int a = 0; + while (true) { + // while(clock()/CLOCKS_PER_SEC-a < 2); + if (a >= 100) + break; + for (int i = 0; i < num_senders; i++) { + senders[i]->Send(msg_meta, topics[i], MAGENTA); + msg = (receivers[i]->Receive(topics[i], CYAN))->str(); + std::cout << msg << std::endl; + + send_to_vdms(vdms_server2, 55561, msg); } -int a=0; - while(true) - { - // while(clock()/CLOCKS_PER_SEC-a < 2); - if ( a>=100) - break; - for ( int i =0; i< num_senders ; i++ ) { - - senders[i]->Send(msg_meta,topics[i], MAGENTA); - msg=(receivers[i]->Receive(topics[i],CYAN))->str(); - std::cout< -#include -#include +#include "VDMSClient.h" +#include "queryMessage.pb.h" +#include #include -#include +#include #include -#include +#include #include -#include -#include "VDMSClient.h" -#include -#include "queryMessage.pb.h" +#include +#include #include - - #include "utils.h" using namespace std::chrono; -std::string sender_endpoint="broker:19092"; -std::string receiver_endpoint="broker:19092"; -std::string vdms_server1="localhost"; -std::string vdms_server2 ="localhost"; -int number_receivers=1; -int number_senders=1; -int vdms_port1 =55560; -int vdms_port2=55561; +std::string sender_endpoint = "broker:19092"; +std::string receiver_endpoint = "broker:19092"; +std::string vdms_server1 = "localhost"; +std::string vdms_server2 = "localhost"; +int number_receivers = 1; +int number_senders = 1; +int vdms_port1 = 55560; +int vdms_port2 = 55561; Json::FastWriter writer; Json::Reader reader; Json::Value result; - - //*************************** using namespace std; -std::shared_ptr _aclient; - -VDMS::Response send_to_vdms( std::string server_url="localhost", int port=55561, std::string msg="") -{ - std::basic_string t= std::basic_string((const unsigned char*)msg.data(), msg.length()); - std::vector blobs; - - - VDMS::protobufs::queryMessage proto_query; - - proto_query.ParseFromArray((const void*)t.data(), t.length()); - Json::Value root; - Json::Reader reader; - - - const std::string commands = proto_query.json(); - bool parseSuccess = reader.parse(commands.c_str(), root); - if (!parseSuccess) { - root["info"] = "Error parsing the query, ill formed JSON"; - root["status"] =-1; - - } - for (auto& it : proto_query.blobs()) { - blobs.push_back(new std::string (it)); - } - - _aclient.reset(new VDMS::VDMSClient(server_url, port)); - - VDMS::Response responses = _aclient->query(commands,blobs); - Json::Value parsed; - - reader.parse(responses.json.c_str(), parsed); - std::cout < blobs = {}){ - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(query); - - for (auto& it : blobs) { - std::string *blob = proto_query.add_blobs(); - *blob = *it; - } - - std::basic_string msg_image(proto_query.ByteSize(),0); - std::cout << "Sending size " << proto_query.ByteSize() <<"\t" < _aclient; -Json::Value add_set( std::string& name ){ - Json::Value descriptor_set; - Json::Value set_query; - Json::Value tuple; - - descriptor_set["name"] = name ; - descriptor_set["dimensions"] = 1000; - set_query["AddDescriptorSet"] = descriptor_set; - if(add_set) - tuple.append(set_query); - return tuple; -} +VDMS::Response send_to_vdms(std::string server_url = "localhost", + int port = 55561, std::string msg = "") { + std::basic_string t = std::basic_string( + (const unsigned char *)msg.data(), msg.length()); + std::vector blobs; + + VDMS::protobufs::queryMessage proto_query; + + proto_query.ParseFromArray((const void *)t.data(), t.length()); + Json::Value root; + Json::Reader reader; + + const std::string commands = proto_query.json(); + bool parseSuccess = reader.parse(commands.c_str(), root); + if (!parseSuccess) { + root["info"] = "Error parsing the query, ill formed JSON"; + root["status"] = -1; + } + for (auto &it : proto_query.blobs()) { + blobs.push_back(new std::string(it)); + } + + _aclient.reset(new VDMS::VDMSClient(server_url, port)); + + VDMS::Response responses = _aclient->query(commands, blobs); + Json::Value parsed; -Json::Value construct_descriptor(std::string& name){ - - Json::Value AddDesc; - Json::Value Desc; - Json::Value tuple; - Desc["set"] =name; - Desc["label"] ="Person"; - Desc["_ref"]=1; - Desc["properties"]["id"]=123; - Desc["properties"]["name"]="Ali"; - AddDesc["AddDescriptor"] = Desc; - tuple.append(AddDesc); - return tuple; - } - - -std::string send_descriptors( bool new_set, std::string& name){ - std::vector fv_values; - srand( (unsigned)time( NULL ) ); - - for (int i = 0; i < 1000; i++) - { - fv_values.push_back((float) rand()/RAND_MAX); - - } - std::vector blobs; - std::string *bytes_str = new std::string(); - bytes_str->resize(fv_values.size() * sizeof(float)); - std::memcpy((void*) bytes_str->data(), fv_values.data(), fv_values.size() * sizeof(float)); - blobs.push_back(bytes_str); - - Json::Value desc_query= construct_descriptor(name); - std::string add_desc =writer.write(desc_query); - std::cout< blobs = {}) { + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(query); + + for (auto &it : blobs) { + std::string *blob = proto_query.add_blobs(); + *blob = *it; + } + + std::basic_string msg_image(proto_query.ByteSize(), 0); + std::cout << "Sending size " << proto_query.ByteSize() << "\t" + << msg_image.length() << std::endl; + msg_image[msg_image.length() - 1] = '\0'; + proto_query.SerializeToArray((void *)msg_image.data(), msg_image.length()); + std::string t(msg_image.begin(), msg_image.end()); + return t; +} - Json::Value props; - props ["name"] ="Ali"; - image["properties"]=props; - Json::Value add_image; - add_image["AddImage"] =image; - Json::Value tuple; - tuple.append(add_image); - return tuple; +Json::Value add_set(std::string &name) { + Json::Value descriptor_set; + Json::Value set_query; + Json::Value tuple; + descriptor_set["name"] = name; + descriptor_set["dimensions"] = 1000; + set_query["AddDescriptorSet"] = descriptor_set; + if (add_set) + tuple.append(set_query); + return tuple; +} +Json::Value construct_descriptor(std::string &name) { + + Json::Value AddDesc; + Json::Value Desc; + Json::Value tuple; + Desc["set"] = name; + Desc["label"] = "Person"; + Desc["_ref"] = 1; + Desc["properties"]["id"] = 123; + Desc["properties"]["name"] = "Ali"; + AddDesc["AddDescriptor"] = Desc; + tuple.append(AddDesc); + return tuple; } -Json::Value construct_query() -{ Json::Value person_json, bounding_box, add_bounding_box, add_FV_entity, - add_person_entity, edge, connect, tuple_data; - person_json["_ref"] = 1; // to assure the differences between the used references in the DB - person_json["class"] = "Person"; - person_json["properties"]["Id"] = "1234"; - person_json["properties"]["imaginary_node"] = 1; - person_json["constraints"]["Id"][0] = "=="; - person_json["constraints"]["Id"][1] = "1234"; - add_person_entity["AddEntity"] = person_json; - tuple_data.append(add_person_entity); - add_person_entity.clear(); - - bounding_box["_ref"] = 2; - bounding_box["class"] ="BoundingBox"; - bounding_box["properties"]["Id"]= "1234"; - bounding_box["properties"]["X"] = 50; - bounding_box["properties"]["Y"] = 50; - bounding_box["properties"]["Width"] = 100; - bounding_box["properties"]["Height"] = 100; - add_bounding_box["AddEntity"] = bounding_box; - tuple_data.append(add_bounding_box); - - - // add the connection between the person and its bounding box - edge ["ref1"] = person_json ["_ref"].asInt(); - edge ["ref2"] = bounding_box ["_ref"].asInt(); - edge["class"]="Represents"; - connect["AddConnection"]=edge; - tuple_data.append(connect); - - - - return tuple_data; + +std::string send_descriptors(bool new_set, std::string &name) { + std::vector fv_values; + srand((unsigned)time(NULL)); + + for (int i = 0; i < 1000; i++) { + fv_values.push_back((float)rand() / RAND_MAX); + } + std::vector blobs; + std::string *bytes_str = new std::string(); + bytes_str->resize(fv_values.size() * sizeof(float)); + std::memcpy((void *)bytes_str->data(), fv_values.data(), + fv_values.size() * sizeof(float)); + blobs.push_back(bytes_str); + + Json::Value desc_query = construct_descriptor(name); + std::string add_desc = writer.write(desc_query); + std::cout << add_desc << std::endl; + std::string result = query_body(add_desc, blobs); + return result; } +Json::Value add_image() { + Json::Value image; + image["format"] = "png"; + + Json::Value props; + props["name"] = "Ali"; + image["properties"] = props; + Json::Value add_image; + add_image["AddImage"] = image; + Json::Value tuple; + tuple.append(add_image); + return tuple; +} +Json::Value construct_query() { + Json::Value person_json, bounding_box, add_bounding_box, add_FV_entity, + add_person_entity, edge, connect, tuple_data; + person_json["_ref"] = + 1; // to assure the differences between the used references in the DB + person_json["class"] = "Person"; + person_json["properties"]["Id"] = "1234"; + person_json["properties"]["imaginary_node"] = 1; + person_json["constraints"]["Id"][0] = "=="; + person_json["constraints"]["Id"][1] = "1234"; + add_person_entity["AddEntity"] = person_json; + tuple_data.append(add_person_entity); + add_person_entity.clear(); + + bounding_box["_ref"] = 2; + bounding_box["class"] = "BoundingBox"; + bounding_box["properties"]["Id"] = "1234"; + bounding_box["properties"]["X"] = 50; + bounding_box["properties"]["Y"] = 50; + bounding_box["properties"]["Width"] = 100; + bounding_box["properties"]["Height"] = 100; + add_bounding_box["AddEntity"] = bounding_box; + tuple_data.append(add_bounding_box); + // add the connection between the person and its bounding box + edge["ref1"] = person_json["_ref"].asInt(); + edge["ref2"] = bounding_box["_ref"].asInt(); + edge["class"] = "Represents"; + connect["AddConnection"] = edge; + tuple_data.append(connect); -std::string img_query(){ - Json::Value img_query_= add_image(); - std::string addImg =writer.write(img_query_); - std::string image; - std::ifstream file("../tests/test_images/brain.png", - std::ios::in | std::ios::binary | std::ios::ate); - image.resize(file.tellg()); + return tuple_data; +} - file.seekg(0, std::ios::beg); - if( !file.read(&image[ 0 ], image.size())) - std::cout << "error" << std::endl; +std::string img_query() { + Json::Value img_query_ = add_image(); + std::string addImg = writer.write(img_query_); + std::string image; + std::ifstream file("../tests/test_images/brain.png", + std::ios::in | std::ios::binary | std::ios::ate); + image.resize(file.tellg()); - std::vector blobs; - std::string *bytes_str = new std::string(image); - blobs.push_back(bytes_str); - std::string result = query_body(addImg, blobs); + file.seekg(0, std::ios::beg); + if (!file.read(&image[0], image.size())) + std::cout << "error" << std::endl; - return result; + std::vector blobs; + std::string *bytes_str = new std::string(image); + blobs.push_back(bytes_str); + std::string result = query_body(addImg, blobs); + return result; } #endif \ No newline at end of file diff --git a/distributed/kafka_receiver.h b/distributed/kafka_receiver.h index 6fd5b905..be02f544 100644 --- a/distributed/kafka_receiver.h +++ b/distributed/kafka_receiver.h @@ -2,119 +2,112 @@ #ifndef KAFKA_RECIVER #define KAFKA_RECIVER -#include -#include -#include #include +#include #include +#include +#include //#include "utils/hash_utils.h" -#include #include - +#include #include "utils.h" // LOG::FLAGS_minloglevel = 100; - - class BaseReceiver { - public: - +public: BaseReceiver() {} virtual ~BaseReceiver() {} virtual bool Init() = 0; - virtual std::unique_ptr Receive( - const std::string& aux = "", const std::string& color=WHITE) = 0; + virtual std::unique_ptr + Receive(const std::string &aux = "", const std::string &color = WHITE) = 0; }; class KafkaReceiver : public BaseReceiver { - public: - - long duration; - - KafkaReceiver(const std::string& endpoint) +public: + long duration; + + KafkaReceiver(const std::string &endpoint) : conf_(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL)), tconf_(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC)) { std::string errstr; - + conf_->set("bootstrap.servers", endpoint, errstr); conf_->set("message.max.bytes", "1000000000", errstr); // conf_->set("batch.size", "1048576", errstr); - conf_->set("auto_offset_reset" ,"latest", errstr); + conf_->set("auto_offset_reset", "latest", errstr); conf_->set("socket.send.buffer.bytes", "1000000000", errstr); conf_->set("socket.receive.buffer.bytes", "1000000000", errstr); - conf_->set("group.id","auto_replication", errstr); + conf_->set("group.id", "auto_replication", errstr); conf_->set("fetch.message.max.bytes", "1000000000", errstr); conf_->set("socket.receive.message.max.bytes", "209715200", errstr); - - } virtual ~KafkaReceiver() {} virtual bool Init() { std::string errstr; consumer_.reset(RdKafka::Consumer::create(conf_.get(), errstr)); - + return consumer_ != nullptr; } - virtual std::unique_ptr + virtual std::unique_ptr // std::stringstream - Receive(const std::string& aux, const std::string& color =WHITE) { + Receive(const std::string &aux, const std::string &color = WHITE) { if (consumer_.get() == nullptr) { - LOG(FATAL) << color <<"Kafka consumer was not initialized."; + LOG(FATAL) << color << "Kafka consumer was not initialized."; } std::string errstr; std::string topic_str = "vdms" + (aux.empty() ? "" : "-" + aux); - std::cout << " Topic " << topic_str <(RdKafka::Topic::create( consumer_.get(), topic_str, tconf_.get(), errstr)); if (topics_[topic_str].get() == nullptr) { - LOG(FATAL) << color <<"Failed to create topic: " << errstr; + LOG(FATAL) << color << "Failed to create topic: " << errstr; } - std::cout <start(topics_[topic_str].get(), 0,RdKafka::Topic::OFFSET_BEGINNING); + RdKafka::ErrorCode resp = consumer_->start( + topics_[topic_str].get(), 0, RdKafka::Topic::OFFSET_BEGINNING); - - if (resp != RdKafka::ERR_NO_ERROR) { - LOG(INFO) << resp << " \t Kafka consume failed: " << RdKafka::err2str(resp); + LOG(INFO) << resp + << " \t Kafka consume failed: " << RdKafka::err2str(resp); } } std::unique_ptr ret; while (true) { - - RdKafka::Message* msg = + + RdKafka::Message *msg = consumer_->consume(topics_[topic_str].get(), 0, 10000); - + if (msg->err() == RdKafka::ERR_NO_ERROR) { - - - // LOG(INFO) << color <<"Kafka reads message at offset " << msg->offset(); - LOG(INFO) << color << "Receiver " << " \treceived " << static_cast(msg->len()) - << " bytes and storing in \t" << topic_str <payload(), msg->len()); - + + // LOG(INFO) << color <<"Kafka reads message at offset " << + // msg->offset(); + LOG(INFO) << color << "Receiver " + << " \treceived " << static_cast(msg->len()) + << " bytes and storing in \t" << topic_str << std::endl; + ; + std::string str((char *)msg->payload(), msg->len()); + ret.reset(new std::stringstream(str)); - - + delete msg; break; } - + delete msg; } consumer_->poll(0); - - return ret; - + + return ret; } - private: +private: std::unique_ptr conf_; std::unique_ptr tconf_; std::unique_ptr consumer_; diff --git a/distributed/kafka_sender.h b/distributed/kafka_sender.h index e91d0bd4..8856c5d3 100644 --- a/distributed/kafka_sender.h +++ b/distributed/kafka_sender.h @@ -4,30 +4,28 @@ #include #include -#include #include - - +#include #include "utils.h" class BaseSender { - public: +public: BaseSender() {} - + virtual ~BaseSender() {} virtual bool Init() = 0; - virtual void Send(const std::string& str, const std::string& aux = "", std::string color =WHITE) = 0; + virtual void Send(const std::string &str, const std::string &aux = "", + std::string color = WHITE) = 0; }; class KafkaSender : public BaseSender { - public: - - KafkaSender(const std::string& endpoint) +public: + KafkaSender(const std::string &endpoint) : conf_(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL)), tconf_(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC)) { std::string errstr; - + conf_->set("bootstrap.servers", endpoint, errstr); conf_->set("batch.size", "1048576", errstr); conf_->set("acks", "1", errstr); @@ -35,7 +33,6 @@ class KafkaSender : public BaseSender { conf_->set("socket.send.buffer.bytes", "1000000000", errstr); conf_->set("socket.receive.buffer.bytes", "1000000000", errstr); conf_->set("socket.request.max.bytes", "209715200", errstr); - } virtual ~KafkaSender() { if (producer_.get() != nullptr) { @@ -48,16 +45,16 @@ class KafkaSender : public BaseSender { std::string errstr; producer_.reset(RdKafka::Producer::create(conf_.get(), errstr)); return producer_.get() != nullptr; - } - virtual void Send(const std::string& str, const std::string& aux, std::string color =WHITE) { + virtual void Send(const std::string &str, const std::string &aux, + std::string color = WHITE) { if (producer_.get() == nullptr) { - LOG(FATAL) <(RdKafka::Topic::create( @@ -66,26 +63,22 @@ class KafkaSender : public BaseSender { if (topics_[topic_str].get() == nullptr) { LOG(FATAL) << color << "Failed to create topic: " << errstr; } - - - + RdKafka::ErrorCode resp = producer_->produce( topics_[topic_str].get(), RdKafka::Topic::PARTITION_UA, - RdKafka::Producer::RK_MSG_COPY, const_cast(str.c_str()), + RdKafka::Producer::RK_MSG_COPY, const_cast(str.c_str()), str.size(), NULL, NULL); - + if (resp != RdKafka::ERR_NO_ERROR) { - LOG(INFO) << color <<"Kafka produce failed: " << RdKafka::err2str(resp); + LOG(INFO) << color << "Kafka produce failed: " << RdKafka::err2str(resp); } else { - LOG(INFO) << resp <<"\tSender " <<"\tKafka sent " << str.length() << " bytes to " << topic_str; - - + LOG(INFO) << resp << "\tSender " + << "\tKafka sent " << str.length() << " bytes to " << topic_str; } producer_->poll(0); - } - private: +private: std::unique_ptr conf_; std::unique_ptr tconf_; std::unique_ptr producer_; diff --git a/distributed/kafka_test.cpp b/distributed/kafka_test.cpp index 9d484fcc..de778821 100644 --- a/distributed/kafka_test.cpp +++ b/distributed/kafka_test.cpp @@ -3,10 +3,8 @@ #include "kafka_receiver.h" #include "kafka_sender.h" +int main(int argc, char *argv[]) { -int main( int argc, char* argv[] ){ - - Json::Value query; std::string package_type_; @@ -19,35 +17,31 @@ int main( int argc, char* argv[] ){ package_type_ = "message"; topic_meta_1 = "query_test_1"; - topic_meta_2="query_test_2"; - + topic_meta_2 = "query_test_2"; + + sender_meta_1 = std::make_unique(sender_endpoint); + receiver_meta_1 = std::make_unique(receiver_endpoint); - sender_meta_1= std::make_unique(sender_endpoint); - receiver_meta_1= std::make_unique(receiver_endpoint); - receiver_meta_1->Init(); sender_meta_1->Init(); - int a=clock()/CLOCKS_PER_SEC; - std::string msg; - - std::string q =writer.write(construct_query()); - - msg= query_body(q); - - - while(true) - { - while(clock()/CLOCKS_PER_SEC-a < 2); - if ( a>=100) - break; - - sender_meta_1->Send( msg,topic_meta_1, BLUE); - send_to_vdms(vdms_server2, 55561, (receiver_meta_1->Receive(topic_meta_1, GREEN))->str()); - - } + int a = clock() / CLOCKS_PER_SEC; + std::string msg; - return 0; + std::string q = writer.write(construct_query()); -} + msg = query_body(q); + while (true) { + while (clock() / CLOCKS_PER_SEC - a < 2) + ; + if (a >= 100) + break; + + sender_meta_1->Send(msg, topic_meta_1, BLUE); + send_to_vdms(vdms_server2, 55561, + (receiver_meta_1->Receive(topic_meta_1, GREEN))->str()); + } + + return 0; +} diff --git a/distributed/mutli_modal.cpp b/distributed/mutli_modal.cpp index a3543ec1..1c6d212d 100644 --- a/distributed/mutli_modal.cpp +++ b/distributed/mutli_modal.cpp @@ -3,69 +3,67 @@ #include "kafka_receiver.h" #include "kafka_sender.h" -int main( int argc, char* argv[] ){ +int main(int argc, char *argv[]) { - + std::cout << "multi-modal" << std::endl; + std::vector> receivers; + std::vector> senders; - std::cout <<"multi-modal" <> receivers; - std::vector > senders; - - std::unique_ptr receiver_image_1; - std::unique_ptr sender_image_1; - std::unique_ptr receiver_desc; - std::unique_ptr sender_desc; - std::unique_ptr receiver_meta; - std::unique_ptr sender_meta; + std::unique_ptr receiver_image_1; + std::unique_ptr sender_image_1; + std::unique_ptr receiver_desc; + std::unique_ptr sender_desc; + std::unique_ptr receiver_meta; + std::unique_ptr sender_meta; - std::string package_image_type_ = "Blob"; - std::string topic_image_1 = "Image1-1-1-1-1"; - std::string topic_desc_1="desc-110-1-1"; - std::string topic_meta_1= "meta-1-1-1-1"; - - sender_image_1= std::make_unique(sender_endpoint); - receiver_image_1= std::make_unique(sender_endpoint); - receiver_image_1->Init(); - sender_image_1->Init(); + std::string package_image_type_ = "Blob"; + std::string topic_image_1 = "Image1-1-1-1-1"; + std::string topic_desc_1 = "desc-110-1-1"; + std::string topic_meta_1 = "meta-1-1-1-1"; - sender_desc= std::make_unique(sender_endpoint); - receiver_desc= std::make_unique(sender_endpoint); - receiver_desc->Init(); - sender_desc->Init(); + sender_image_1 = std::make_unique(sender_endpoint); + receiver_image_1 = std::make_unique(sender_endpoint); + receiver_image_1->Init(); + sender_image_1->Init(); - sender_meta= std::make_unique(sender_endpoint); - receiver_meta= std::make_unique(sender_endpoint); - receiver_meta->Init(); - sender_meta->Init(); + sender_desc = std::make_unique(sender_endpoint); + receiver_desc = std::make_unique(sender_endpoint); + receiver_desc->Init(); + sender_desc->Init(); - std::string set_name ="feature_set_test11_new"; - - int a=0; - Json::Value result =construct_query(); - - std::string q =writer.write(result); - - - std::string msg_meta= query_body(q); - std::string msg_img=img_query(); - std::string msg_Desc=send_descriptors(true, set_name); - std::unique_ptr ret; - std::string str; - - while(true) - { - - if ( a>=10000) - break; - - sender_image_1->Send(msg_img,topic_image_1, MAGENTA); - send_to_vdms(vdms_server2, 55561, (receiver_image_1->Receive(topic_image_1,CYAN))->str()); - sender_desc->Send( msg_Desc,topic_desc_1, BLUE); - send_to_vdms(vdms_server2, 55561, (receiver_desc->Receive(topic_desc_1, GREEN ))->str()); - sender_meta->Send( msg_meta,topic_meta_1, BLUE); - send_to_vdms(vdms_server2, 55561,(receiver_meta->Receive(topic_meta_1, GREEN ))->str()); - a++; - - } - return 0; + sender_meta = std::make_unique(sender_endpoint); + receiver_meta = std::make_unique(sender_endpoint); + receiver_meta->Init(); + sender_meta->Init(); + + std::string set_name = "feature_set_test11_new"; + + int a = 0; + Json::Value result = construct_query(); + + std::string q = writer.write(result); + + std::string msg_meta = query_body(q); + std::string msg_img = img_query(); + std::string msg_Desc = send_descriptors(true, set_name); + std::unique_ptr ret; + std::string str; + + while (true) { + + if (a >= 10000) + break; + + sender_image_1->Send(msg_img, topic_image_1, MAGENTA); + send_to_vdms(vdms_server2, 55561, + (receiver_image_1->Receive(topic_image_1, CYAN))->str()); + sender_desc->Send(msg_Desc, topic_desc_1, BLUE); + send_to_vdms(vdms_server2, 55561, + (receiver_desc->Receive(topic_desc_1, GREEN))->str()); + sender_meta->Send(msg_meta, topic_meta_1, BLUE); + send_to_vdms(vdms_server2, 55561, + (receiver_meta->Receive(topic_meta_1, GREEN))->str()); + a++; + } + return 0; } \ No newline at end of file diff --git a/distributed/utils.h b/distributed/utils.h index 595abb97..2ba699b2 100644 --- a/distributed/utils.h +++ b/distributed/utils.h @@ -2,23 +2,22 @@ #ifndef UTILS #define UTILS -#define RESET "\033[0m" -#define BLACK "\033[30m" /* Black */ -#define RED "\033[31m" /* Red */ -#define GREEN "\033[32m" /* Green */ -#define YELLOW "\033[33m" /* Yellow */ -#define BLUE "\033[34m" /* Blue */ -#define MAGENTA "\033[35m" /* Magenta */ -#define CYAN "\033[36m" /* Cyan */ -#define WHITE "\033[37m" /* White */ -#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */ -#define BOLDRED "\033[1m\033[31m" /* Bold Red */ -#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */ -#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */ -#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */ -#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */ -#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */ -#define BOLDWHITE "\033[1m\033[37m" /* Bold White */ - +#define RESET "\033[0m" +#define BLACK "\033[30m" /* Black */ +#define RED "\033[31m" /* Red */ +#define GREEN "\033[32m" /* Green */ +#define YELLOW "\033[33m" /* Yellow */ +#define BLUE "\033[34m" /* Blue */ +#define MAGENTA "\033[35m" /* Magenta */ +#define CYAN "\033[36m" /* Cyan */ +#define WHITE "\033[37m" /* White */ +#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */ +#define BOLDRED "\033[1m\033[31m" /* Bold Red */ +#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */ +#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */ +#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */ +#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */ +#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */ +#define BOLDWHITE "\033[1m\033[37m" /* Bold White */ #endif \ No newline at end of file diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile index 96ff4df3..31d4d83b 100644 --- a/docker/base/Dockerfile +++ b/docker/base/Dockerfile @@ -1,73 +1,76 @@ -#Copyright (C) 2021 Intel Corporation +#Copyright (C) 2023 Intel Corporation #SPDX-License-Identifier: MIT -ARG UBUNTU_VERSION=20.04 -ARG UBUNTU_NAME=focal -ARG BUILD_THREADS=-j16 +ARG BASE_VERSION=11.7-slim +ARG BUILD_THREADS="-j16" -#1 -FROM ubuntu:${UBUNTU_VERSION} +FROM debian:${BASE_VERSION} # Dockerfile limitations force a repetition of global args -ARG UBUNTU_VERSION -ARG UBUNTU_NAME +ARG BUILD_THREADS # Install Packages -RUN apt-get update && apt-get install -y --no-install-recommends software-properties-common && \ - add-apt-repository "deb http://security.ubuntu.com/ubuntu ${UBUNTU_NAME}-security main" && \ - apt-get install -y --no-install-recommends apt-transport-https autoconf automake bison build-essential \ - bzip2 ca-certificates curl=7.68.0-1ubuntu2.18 ed flex g++ git gnupg-agent javacc libarchive-tools \ - libatlas-base-dev libavcodec-dev libavformat-dev libboost-all-dev libbz2-dev \ - libc-ares-dev libdc1394-22-dev libgflags-dev libgoogle-glog-dev libgtest-dev \ - libgtk-3-dev libgtk2.0-dev libhdf5-serial-dev libjpeg-dev libjpeg8-dev libjsoncpp-dev \ - libleveldb-dev liblmdb-dev liblz4-dev libopenblas-dev libopenmpi-dev \ - libpng-dev librdkafka-dev libsnappy-dev libssl-dev libswscale-dev libtbb-dev \ - libtbb2 libtiff-dev libtiff5-dev libtool mpich openjdk-11-jdk-headless \ - pkg-config python3-dev python3-pip unzip && \ +RUN apt-get update && apt-get install -y --no-install-suggests --no-install-recommends \ + apt-transport-https autoconf automake bison build-essential bzip2 ca-certificates \ + curl ed flex g++-9 gcc-9 git gnupg-agent javacc libarchive-tools libatlas-base-dev \ + libavcodec-dev libavformat-dev libboost-all-dev libbz2-dev libc-ares-dev libcurl4-openssl-dev \ + libdc1394-22-dev libgflags-dev libgoogle-glog-dev libgtest-dev libgtk-3-dev libgtk2.0-dev \ + libhdf5-dev libjpeg-dev libjpeg62-turbo-dev libjsoncpp-dev libleveldb-dev liblmdb-dev \ + liblz4-dev libopenblas-dev libopenmpi-dev libpng-dev librdkafka-dev libsnappy-dev libssl-dev \ + libswscale-dev libtbb-dev libtbb2 libtiff-dev libtiff5-dev libtool libzmq3-dev linux-libc-dev mpich \ + openjdk-11-jdk-headless pkg-config procps python3-dev python3-pip software-properties-common \ + swig unzip uuid-dev && \ + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 1 && \ + update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 1 && \ apt-get clean && rm -rf /var/lib/apt/lists/* && \ - update-alternatives --install /usr/bin/python python /usr/bin/python3 1 && \ - pip3 install --no-cache-dir "numpy>=1.23.2" "setuptools>=65.5.1" + ln -s /usr/bin/python3 /usr/bin/python # Pull and Install Dependencies +ENV CMAKE_VERSION="v3.26.4" \ + PROTOBUF_VERSION="3.20.3" \ + OPENCV_VERSION="4.5.5" \ + FAISS_VERSION="v1.7.3" \ + VALIJSON_VERSION="v0.6" \ + AWS_SDK_VERSION="1.11.0" \ + TILEDB_VERSION="2.14.1" + WORKDIR /dependencies -RUN git clone --branch v3.21.2 https://github.com/Kitware/CMake.git && \ - git clone --branch v4.0.2 https://github.com/swig/swig.git && \ - git clone --branch v1.7.1 https://github.com/facebookresearch/faiss.git && \ - git clone https://github.com/tonyzhang617/FLINNG.git && \ - git clone --recurse-submodules -b v1.40.0 https://github.com/grpc/grpc.git && \ - git clone --branch 4.5.3 https://github.com/opencv/opencv.git && \ - git clone --branch v0.6 https://github.com/tristanpenman/valijson.git && \ - curl -L -o /usr/share/java/json-simple-1.1.1.jar https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/json-simple/json-simple-1.1.1.jar && \ - curl -L -o /dependencies/1.3.1.tar.gz https://github.com/TileDB-Inc/TileDB/archive/refs/tags/1.3.1.tar.gz && \ - curl -L -o /dependencies/zlib-1.2.13.tar.gz http://zlib.net/zlib-1.2.13.tar.gz && \ - cd /dependencies/CMake && ./bootstrap && make ${BUILD_THREADS} && make install && \ - cd /dependencies/swig && ./autogen.sh && ./configure && make ${BUILD_THREADS} && make install && \ - cd /dependencies/faiss && mkdir build && cd build && cmake -DFAISS_ENABLE_GPU=OFF .. && make ${BUILD_THREADS} && make install && \ - cd /dependencies/FLINNG && mkdir build && cd build && cmake .. && make ${BUILD_THREADS} && make install && \ - cd /dependencies/grpc && pip3 install --no-cache-dir -r requirements.txt && GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip3 install --no-cache-dir . && \ - cd tools/distrib/python/grpcio_tools && python ../make_grpcio_tools.py && GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip3 install --no-cache-dir . && \ - cd /dependencies/grpc/third_party/zlib && mkdir build && cd build && cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE .. && make ${BUILD_THREADS} && make install && \ - cd /dependencies/grpc/third_party/protobuf/cmake && mkdir build && cd build && cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -Dprotobuf_BUILD_TESTS=OFF .. && make ${BUILD_THREADS} && make install && \ - cd ../../../abseil-cpp && mkdir build && cd build && cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE .. && make ${BUILD_THREADS} && make install && \ - cd ../../re2/ && mkdir build && cd build && cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE .. && make ${BUILD_THREADS} && make install && \ - cd /dependencies/grpc/cmake && mkdir build && cd build && cmake -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DgRPC_ABSL_PROVIDER=package \ - -DgRPC_CARES_PROVIDER=package -DgRPC_PROTOBUF_PROVIDER=package \ - -DgRPC_RE2_PROVIDER=package -DgRPC_SSL_PROVIDER=package \ - -DgRPC_ZLIB_PROVIDER=package -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ../.. && make ${BUILD_THREADS} && make install && \ - cd /dependencies/opencv && mkdir build && cd build && cmake -D BUILD_PERF_TESTS=OFF -D BUILD_TESTS=OFF .. && make ${BUILD_THREADS} && make install && \ - cd /dependencies/ && tar -xvzf zlib-1.2.13.tar.gz && cd zlib-1.2.13 && ./configure && make ${BUILD_THREADS} && make install && \ - cd /dependencies/ && tar -xvf 1.3.1.tar.gz && cd TileDB-1.3.1 && mkdir build && cd build && \ - ../bootstrap --prefix=/usr/local/ && make ${BUILD_THREADS} && make install-tiledb && \ +RUN pip install --no-cache-dir "numpy>=1.25.1" "protobuf==${PROTOBUF_VERSION}" "coverage>=7.2.7" && \ + git clone --branch ${CMAKE_VERSION} https://github.com/Kitware/CMake.git && \ + cd CMake && ./bootstrap && make ${BUILD_THREADS} && make install && \ cd /usr/src/gtest && cmake . && make ${BUILD_THREADS} && mv lib/libgtest* /usr/lib/ && \ - cd /dependencies/valijson && cp -r include/* /usr/local/include/ && \ - rm -rf /dependencies + git clone --branch ${FAISS_VERSION} https://github.com/facebookresearch/faiss.git /dependencies/faiss && \ + cd /dependencies/faiss && mkdir build && cd build && cmake -DFAISS_ENABLE_GPU=OFF .. && \ + make ${BUILD_THREADS} && make install && cd /dependencies/ && \ + git clone https://github.com/tonyzhang617/FLINNG.git && \ + cd /dependencies/FLINNG && mkdir build && cd build && cmake .. && make ${BUILD_THREADS} && make install && cd /dependencies && \ + curl -L -o /dependencies/${PROTOBUF_VERSION}.tar.gz \ + https://github.com/protocolbuffers/protobuf/archive/refs/tags/v${PROTOBUF_VERSION}.tar.gz && \ + cd /dependencies/ && tar -xvf ${PROTOBUF_VERSION}.tar.gz && \ + cd protobuf-${PROTOBUF_VERSION} && ./autogen.sh && ./configure && make -j$(nproc) && \ + make install && ldconfig && cd /dependencies && \ + git clone --branch ${OPENCV_VERSION} https://github.com/opencv/opencv.git && \ + cd opencv && mkdir build && cd build && cmake -D BUILD_PERF_TESTS=OFF -D BUILD_TESTS=OFF .. && \ + make ${BUILD_THREADS} && make install && cd /dependencies/ && \ + git clone --branch ${VALIJSON_VERSION} https://github.com/tristanpenman/valijson.git && \ + cd valijson && cp -r include/* /usr/local/include/ && cd /dependencies && \ + curl -L -o /dependencies/${TILEDB_VERSION}.tar.gz \ + https://github.com/TileDB-Inc/TileDB/archive/refs/tags/${TILEDB_VERSION}.tar.gz && \ + cd /dependencies/ && tar -xvf ${TILEDB_VERSION}.tar.gz && cd TileDB-${TILEDB_VERSION} && \ + mkdir build && cd build && ../bootstrap --prefix=/usr/local/ && make ${BUILD_THREADS} && \ + make install-tiledb && cd /dependencies && \ + git clone -b ${AWS_SDK_VERSION} --recurse-submodules https://github.com/aws/aws-sdk-cpp && \ + mkdir -p aws-sdk-cpp/build && cd aws-sdk-cpp/build && \ + cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local/ -DCMAKE_INSTALL_PREFIX=/usr/local/ \ + -DBUILD_ONLY="s3" -DCUSTOM_MEMORY_MANAGEMENT=OFF -DENABLE_TESTING=OFF && \ + make ${BUILD_THREADS} && make install && \ + rm -rf /dependencies /usr/local/share/doc /usr/local/share/man # VDMS WORKDIR /vdms -RUN git clone https://github.com/IntelLabs/vdms.git /vdms && cd /vdms && \ - git checkout develop && git submodule update --init --recursive && \ - mkdir build && cd build && cmake .. && make ${BUILD_THREADS} && \ +RUN git clone -b develop --recurse-submodules https://github.com/IntelLabs/vdms.git /vdms && \ + mkdir -p /vdms/build && cd /vdms/build && cmake .. && make ${BUILD_THREADS} && \ cp /vdms/config-vdms.json /vdms/build/ && \ echo '#!/bin/bash' > /start.sh && echo 'cd /vdms/build' >> /start.sh && \ echo './vdms' >> /start.sh && chmod 755 /start.sh diff --git a/ext/custom_vcl/CMakeLists.txt b/ext/custom_vcl/CMakeLists.txt index c43b6c20..ea543e85 100644 --- a/ext/custom_vcl/CMakeLists.txt +++ b/ext/custom_vcl/CMakeLists.txt @@ -1,7 +1,11 @@ -cmake_minimum_required (VERSION 3.10) +cmake_minimum_required (VERSION 3.17) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +set(CMAKE_CXX_STANDARD 17) project(custom_vcl_application) find_package( OpenCV REQUIRED ) +find_package(AWSSDK REQUIRED COMPONENTS s3) -include_directories(. ../../src ../../include/ ../../src/vcl /usr/include/jsoncpp ${OpenCV_INCLUDE_DIRS}) +link_directories(/usr/local/lib /usr/lib/x86_64-linux-gnu/) +include_directories(. ../../src ../../include/ ../../src/vcl /usr/include/jsoncpp ${OpenCV_INCLUDE_DIRS}) add_executable(custom_vcl custom_vcl_process.cc ) -target_link_libraries(custom_vcl vcl tiledb jsoncpp ${OpenCV_LIBS}) +target_link_libraries(custom_vcl vcl tbb tiledb jsoncpp ${OpenCV_LIBS} ${AWSSDK_LINK_LIBRARIES}) \ No newline at end of file diff --git a/ext/custom_vcl/custom_vcl_process.cc b/ext/custom_vcl/custom_vcl_process.cc index 55d04b04..fffdc91b 100644 --- a/ext/custom_vcl/custom_vcl_process.cc +++ b/ext/custom_vcl/custom_vcl_process.cc @@ -1,104 +1,124 @@ #include "vcl/CustomVCL.h" #include -int main(int argc, char* argv[]) -{ +int main(int argc, char *argv[]) { - //create IPC structures for communicating between processes - key_t key_ctl_host_remote; - key_ctl_host_remote = ftok("../../vdms", 60); - int msgid_ctl_host_remote = msgget(key_ctl_host_remote, 0666 | IPC_CREAT); - data_message message_ctl_host_remote; - //need size of data message excluding message_type field for msgsnd and msgrcv - size_t data_message_size = sizeof(message_ctl_host_remote.data_rows) + - sizeof(message_ctl_host_remote.data_cols) + - sizeof(message_ctl_host_remote.data_type) + - sizeof(message_ctl_host_remote.data_image_size) + - sizeof(message_ctl_host_remote.data_json_size); + // create IPC structures for communicating between processes + key_t key_ctl_host_remote; + key_ctl_host_remote = ftok("../../vdms", 60); + int msgid_ctl_host_remote = msgget(key_ctl_host_remote, 0666 | IPC_CREAT); + data_message message_ctl_host_remote; + // need size of data message excluding message_type field for msgsnd and + // msgrcv + size_t data_message_size = sizeof(message_ctl_host_remote.data_rows) + + sizeof(message_ctl_host_remote.data_cols) + + sizeof(message_ctl_host_remote.data_type) + + sizeof(message_ctl_host_remote.data_image_size) + + sizeof(message_ctl_host_remote.data_json_size); - key_t key_data_host_remote; - key_data_host_remote = ftok("../../vdms", 61); - int shmid_data_host_remote = shmget(key_data_host_remote,SHARED_IMAGE_BUFFER_SIZE,0666|IPC_CREAT); - uint8_t *image_buffer = (uint8_t*) shmat(shmid_data_host_remote,(void*)0,0); + key_t key_data_host_remote; + key_data_host_remote = ftok("../../vdms", 61); + int shmid_data_host_remote = + shmget(key_data_host_remote, SHARED_IMAGE_BUFFER_SIZE, 0666 | IPC_CREAT); + uint8_t *image_buffer = + (uint8_t *)shmat(shmid_data_host_remote, (void *)0, 0); - key_t key_ctl_remote_host; - key_ctl_remote_host = ftok("../../vdms", 62); - int msgid_ctl_remote_host = msgget(key_ctl_remote_host, 0666 | IPC_CREAT);; - data_message message_ctl_remote_host; + key_t key_ctl_remote_host; + key_ctl_remote_host = ftok("../../vdms", 62); + int msgid_ctl_remote_host = msgget(key_ctl_remote_host, 0666 | IPC_CREAT); + ; + data_message message_ctl_remote_host; - heartbeat_message message_hb_host_remote; - heartbeat_message message_hb_remote_host; - size_t heartbeat_message_size = sizeof(message_hb_host_remote.status); + heartbeat_message message_hb_host_remote; + heartbeat_message message_hb_remote_host; + size_t heartbeat_message_size = sizeof(message_hb_host_remote.status); - while(true) - { - //Handle handshake to indicate remote process is alive - int in_alive_msg_status = msgrcv(msgid_ctl_host_remote, &message_hb_host_remote, heartbeat_message_size, (long) vcl_message_type::VCL_MESSAGE_HEARTBEAT, 0); + while (true) { + // Handle handshake to indicate remote process is alive + int in_alive_msg_status = msgrcv( + msgid_ctl_host_remote, &message_hb_host_remote, heartbeat_message_size, + (long)vcl_message_type::VCL_MESSAGE_HEARTBEAT, 0); - message_hb_remote_host.message_type = (long) vcl_message_type::VCL_MESSAGE_HEARTBEAT; - message_hb_remote_host.status = 0; - int msg_send_result = msgsnd(msgid_ctl_remote_host, &message_hb_remote_host, heartbeat_message_size, 0); + message_hb_remote_host.message_type = + (long)vcl_message_type::VCL_MESSAGE_HEARTBEAT; + message_hb_remote_host.status = 0; + int msg_send_result = msgsnd(msgid_ctl_remote_host, &message_hb_remote_host, + heartbeat_message_size, 0); - int msg_status = msgrcv(msgid_ctl_host_remote, &message_ctl_host_remote, data_message_size, (long) vcl_message_type::VCL_MESSAGE_DATA, 0); - if(msg_status > 0) - { - //Read image from shared memory - cv::Mat* in_image = new cv::Mat(message_ctl_host_remote.data_rows, message_ctl_host_remote.data_cols, message_ctl_host_remote.data_type); - memcpy((uint8_t*) &(in_image->data[0]), image_buffer, message_ctl_host_remote.data_image_size); + int msg_status = + msgrcv(msgid_ctl_host_remote, &message_ctl_host_remote, + data_message_size, (long)vcl_message_type::VCL_MESSAGE_DATA, 0); + if (msg_status > 0) { + // Read image from shared memory + cv::Mat *in_image = new cv::Mat(message_ctl_host_remote.data_rows, + message_ctl_host_remote.data_cols, + message_ctl_host_remote.data_type); + memcpy((uint8_t *)&(in_image->data[0]), image_buffer, + message_ctl_host_remote.data_image_size); - //Read Json operands from shared memory and store into Json::Value - char* json_string_char = new char[message_ctl_host_remote.data_json_size]; - memcpy(&(json_string_char[0]), &(image_buffer[message_ctl_host_remote.data_image_size]), message_ctl_host_remote.data_json_size); - std::string* json_string = new std::string(json_string_char); - Json::Value vcl_op; - Json::Reader vcl_reader; - bool parse_flag = vcl_reader.parse( json_string->c_str(), vcl_op); - if(parse_flag) - { - //Manipulate Image - if(vcl_op.get("custom_function_type", 0).asString() == "hsv_threshold") - { - cv::cvtColor(*in_image, *in_image, cv::COLOR_RGB2HSV); - cv::inRange(*in_image, cv::Scalar(vcl_op.get("h0", -1).asInt(), vcl_op.get("s0", -1).asInt(), vcl_op.get("v0", -1).asInt()), cv::Scalar(vcl_op.get("h1", -1).asInt(),vcl_op.get("s1", -1).asInt(),vcl_op.get("v1", -1).asInt()), *in_image); + // Read Json operands from shared memory and store into Json::Value + char *json_string_char = new char[message_ctl_host_remote.data_json_size]; + memcpy(&(json_string_char[0]), + &(image_buffer[message_ctl_host_remote.data_image_size]), + message_ctl_host_remote.data_json_size); + std::string *json_string = new std::string(json_string_char); + Json::Value vcl_op; + Json::Reader vcl_reader; + bool parse_flag = vcl_reader.parse(json_string->c_str(), vcl_op); + if (parse_flag) { + // Manipulate Image + if (vcl_op.get("custom_function_type", 0).asString() == + "hsv_threshold") { + cv::cvtColor(*in_image, *in_image, cv::COLOR_RGB2HSV); + cv::inRange(*in_image, + cv::Scalar(vcl_op.get("h0", -1).asInt(), + vcl_op.get("s0", -1).asInt(), + vcl_op.get("v0", -1).asInt()), + cv::Scalar(vcl_op.get("h1", -1).asInt(), + vcl_op.get("s1", -1).asInt(), + vcl_op.get("v1", -1).asInt()), + *in_image); - size_t in_image_size = in_image->total() * in_image->elemSize(); - memcpy(&(image_buffer[0]), &(in_image->data[0]), in_image_size); + size_t in_image_size = in_image->total() * in_image->elemSize(); + memcpy(&(image_buffer[0]), &(in_image->data[0]), in_image_size); - //Send Response back to host - message_ctl_remote_host.message_type = (long) vcl_message_type::VCL_MESSAGE_DATA; - message_ctl_remote_host.data_rows = in_image->rows; - message_ctl_remote_host.data_cols = in_image->cols; - message_ctl_remote_host.data_type = in_image->type(); - message_ctl_remote_host.data_image_size = in_image_size; - message_ctl_remote_host.data_json_size = 0; + // Send Response back to host + message_ctl_remote_host.message_type = + (long)vcl_message_type::VCL_MESSAGE_DATA; + message_ctl_remote_host.data_rows = in_image->rows; + message_ctl_remote_host.data_cols = in_image->cols; + message_ctl_remote_host.data_type = in_image->type(); + message_ctl_remote_host.data_image_size = in_image_size; + message_ctl_remote_host.data_json_size = 0; - } - else - { - //Send Response back to host in event of error - message_ctl_remote_host.message_type = (long) vcl_message_type::VCL_MESSAGE_DATA; - message_ctl_remote_host.data_rows = 0; - message_ctl_remote_host.data_cols = 0; - message_ctl_remote_host.data_type = 0; - message_ctl_remote_host.data_image_size = 0; - message_ctl_remote_host.data_json_size = 0; - } - } + } else { + // Send Response back to host in event of error + message_ctl_remote_host.message_type = + (long)vcl_message_type::VCL_MESSAGE_DATA; + message_ctl_remote_host.data_rows = 0; + message_ctl_remote_host.data_cols = 0; + message_ctl_remote_host.data_type = 0; + message_ctl_remote_host.data_image_size = 0; + message_ctl_remote_host.data_json_size = 0; + } + } - int msg_send_result = msgsnd(msgid_ctl_remote_host, &message_ctl_remote_host, data_message_size, 0); - if(msg_send_result < 0) - { } + int msg_send_result = + msgsnd(msgid_ctl_remote_host, &message_ctl_remote_host, + data_message_size, 0); + if (msg_send_result < 0) { + } - //Free allocated memory - delete in_image; - delete[] json_string_char; - delete json_string; - } + // Free allocated memory + delete in_image; + delete[] json_string_char; + delete json_string; } + } - //Free shared IPC components - msgctl(msgid_ctl_host_remote, IPC_RMID, NULL); - shmdt(image_buffer); - shmctl(shmid_data_host_remote,IPC_RMID,NULL); - return 0; + // Free shared IPC components + msgctl(msgid_ctl_host_remote, IPC_RMID, NULL); + shmdt(image_buffer); + shmctl(shmid_data_host_remote, IPC_RMID, NULL); + return 0; } \ No newline at end of file diff --git a/ext/custom_vcl/sample_query/sample_query.py b/ext/custom_vcl/sample_query/sample_query.py index b7a426d6..4a2962bb 100644 --- a/ext/custom_vcl/sample_query/sample_query.py +++ b/ext/custom_vcl/sample_query/sample_query.py @@ -2,7 +2,7 @@ db = vdms.vdms() db.connect("localhost", 55555) -image_file = open('images/intel_logo.png', 'rb') +image_file = open("images/intel_logo.png", "rb") image_blob = image_file.read() addImage = {} addImage["format"] = "png" diff --git a/include/vcl/CustomVCL.h b/include/vcl/CustomVCL.h index 4106c2e4..069ea26b 100644 --- a/include/vcl/CustomVCL.h +++ b/include/vcl/CustomVCL.h @@ -7,35 +7,31 @@ #include #include -#include #include +#include #include -#include "Image.h" #include "../ExceptionsCommand.h" +#include "Image.h" #define SHARED_IMAGE_BUFFER_SIZE 134217728 -enum class vcl_message_type { - VCL_MESSAGE_HEARTBEAT = 1, - VCL_MESSAGE_DATA -}; +enum class vcl_message_type { VCL_MESSAGE_HEARTBEAT = 1, VCL_MESSAGE_DATA }; // structure for message queue -//first byte of message must be non negative long +// first byte of message must be non negative long typedef struct data_msg { - long message_type; - unsigned int data_rows; - unsigned int data_cols; - unsigned int data_type; - unsigned int data_image_size; - unsigned int data_json_size; + long message_type; + unsigned int data_rows; + unsigned int data_cols; + unsigned int data_type; + unsigned int data_image_size; + unsigned int data_json_size; } data_message; typedef struct hb_msg { - long message_type; - unsigned int status; + long message_type; + unsigned int status; } heartbeat_message; - -int custom_vcl_function(VCL::Image& img, const Json::Value& ops); +int custom_vcl_function(VCL::Image &img, const Json::Value &ops); diff --git a/include/vcl/DescriptorSet.h b/include/vcl/DescriptorSet.h index 61e5413b..9d1017e8 100644 --- a/include/vcl/DescriptorSet.h +++ b/include/vcl/DescriptorSet.h @@ -1,360 +1,372 @@ /** -* @file DescriptorSet.h -* -* @section LICENSE -* -* The MIT License -* -* @copyright Copyright (c) 2017 Intel Corporation -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), -* to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* @section DESCRIPTION -* -* This file declares the C++ API for DescriptorSet. -*/ + * @file DescriptorSet.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file declares the C++ API for DescriptorSet. + */ #pragma once -#include -#include -#include #include "DescriptorParams.h" #include "Exception.h" +#include "RemoteConnection.h" +#include "utils.h" +#include +#include +#include namespace VCL { - enum DescriptorSetEngine {FaissFlat, FaissIVFFlat, - TileDBDense, TileDBSparse, - Flinng}; - - enum DistanceMetric {L2, IP}; - - class DescriptorSet { - - public: - - typedef std::vector DescIdVector; - typedef std::vector LabelIdVector; - typedef std::vector DistanceVector; - typedef float* DescData; - typedef float* DescDataArray; - - class DescriptorSetData; - class DescriptorParams; - - private: - - DescriptorSetData* _set; - DescriptorSetEngine _eng; - - void write_set_info(); - void read_set_info(const std::string& set_path); - - public: - /** - * Loads an existing collection located at set_path - * - * @param set_path Full Path to the collection folder - */ - DescriptorSet(const std::string& set_path); - - /** - * Creates a new collection, if it does not exist - * - * @param set_path Full Path to the set folder - * @param dim Dimension of the descriptor - * @param eng DescriptorSet Engine (Default is FaissFlat) - * @param metric Metric for calculating distances (Default is L2) - */ - DescriptorSet(const std::string &set_path, unsigned dim, - DescriptorSetEngine eng = FaissFlat, - DistanceMetric metric = L2, - VCL::DescriptorParams *param = NULL); - - ~DescriptorSet(); - - // For now, we don't allow copy of objects. - // We will defined this behavoir later based on use-cases. - // Out use-cases now do not require copies, as the - // objects are besically used to access/operate the sets. - DescriptorSet(const DescriptorSetData&) = delete; - - /** - * Writes the DescriptorSet Index to the system. This will overwrite - * the original - */ - void store(); - - /** - * Writes the DescriptorSet Index to the system into a defined path. - * This will overwrite any other index under the same set_path. - */ - void store(std::string set_path); - - /* *********************** */ - /* CORE INTERFACE */ - /* *********************** */ - - /** - * Returns the path to the root directory where all the - * files are for the Set are stored - */ - std::string get_path(); - - /** - * Returns the number of dimensions of each descriptor in the set - */ - unsigned get_dimensions(); - - void finalize_index(); - - /** - * Returns the number of descriptors in the set - */ - long get_n_descriptors(); - - /** - * Inserts n descriptors and their labels into the set - * Both descriptors and labels must have the same number of elements, - * or labels can have no elements. - * If not labels are defined, -1 is assigned to signify "no label". - - * Note: Given the in-memory nature of the Faiss library, adding - * elements on a set using Faiss as engine will not persist the data - * until the store() method is call. This is contrary to the TileDB - * engines, where every add will return after persisting the data. - - * @param descriptors Buffer to descriptors (size n * dim) - * @param n Number of descriptors - * @param labels Array of labels, can be NULL. - */ - long add(DescDataArray descriptors, unsigned n, long* labels = NULL); - - long add_and_store(DescDataArray descriptors, unsigned n, long* labels = NULL); - - /** - * Search for the k closest neighborhs - * - * @param query Query descriptors buffer - * @param n Number of descriptors that will be queried - * @param k Number of maximun neighbors to be returned - * @return ids id of each neighbor (size n * k) (padded with -1) - * @return distances distances to each neighbor (size n * k). - (padded with -1) - */ - void search(DescDataArray queries, unsigned n, unsigned k, - long* ids, float* distances); - - void search(DescDataArray queries, unsigned n, unsigned k, - long* ids); - /** - * Search for neighborhs within a radius. - * - * Note: We only allow the radius search of a single - * element to avoid having to deal with results that are - * of different (unknown) sized for each query. - * We will work on it once we have a more clear use case for - * this call - * - * @param query Query vector - * @param radius Maximun distance allowed - * @param ids Array of ID of the descriptors - * @param distances Distances of each neighbor - */ - void radius_search(DescData query, float radius, - long* ids, float* distances); - - /** - * Find the label of the feature vector, based on the closest - * neighbors. - * - * @param descriptors Buffer to descriptors (size n * dim) - * @param n Number of descriptors in buffer - * @return labels Label Ids - * @param quorum Number of elements used for the classification vote. - */ - void classify(DescDataArray descriptors, unsigned n, long* labels, - unsigned quorum = 7); - - /** - * Get the descriptors by specifiying ids. - * This is an exact search by id. - * - * @param ids buffer with ids - * @param n number of ids to query - * @return descriptors pointer to descriptors buffer - size: (n * dim * sizeof(float)) - */ - void get_descriptors(long* ids, unsigned n, DescDataArray descriptors); - - /** - * Trains the index with the data present in the collection - * using the specified metric - */ - void train(); - - /** - * Trains the index using specified descriptors - * - * @param descriptors Reference Descriptors - * @param n Number of descriptors - */ - void train(DescDataArray descriptors, unsigned n); - - /** - * Returns true if the index is trained (train() method called), - * false otherwhise. - */ - bool is_trained(); - - /* *********************** */ - /* VECTOR-BASED INTERFACE */ - /* *********************** */ - - // This are all wrapper around the core-interface - // That are usually useful. - - /** - * Inserts several Descriptors and their labels into the collection - * Both Descriptors and labels must have the same length. - * - * @param descriptors Pointer to buffer containing the DescriptorSet - * @param n Number of elements per descriptor - * @param labels Vector of labels - * @return id of the first (sequential ids) - */ - long add(DescDataArray descriptors, unsigned n, LabelIdVector& labels); - - long add_and_store(DescDataArray descriptors, unsigned n, LabelIdVector& labels); - /** - * Search for the k closest neighborhs - * // Add comment on why we use k and n_queries. - * // We can also get rid of the - * - * @param query Query descriptors buffer - * @param n_queries Number of descriptors that will be queried - * @param k Number of maximun neighbors to be returned - * @return distances distances of each neighbor (size n * k). - * @return descriptors_ids distances of each neighbor (size n * k). - */ - void search(DescDataArray query, unsigned n, unsigned k, - DescIdVector& ids, DistanceVector& distances); - - void search(DescDataArray query, unsigned n, unsigned k, - DescIdVector& ids); - /** - * Find the label of the feature vector, based on the closest - * neighbors. - * - * @param query Query descriptors buffer - * @param n_queries Number of descriptors that will be classified - * @param quorum Number of elements used for the classification vote. - * @return Vector with LabelIds. - */ - LabelIdVector classify(DescDataArray descriptors, unsigned n, - unsigned quorum = 7); - - /** - * Get the label of the descriptors for the spcified ids. - * NOTE: This is a vector becase this is what we return. - * We can, make wrapper functions that recieve arrays as well. - * - * @param ids vector of ids of size n - * @param descriptors return pointer for the float values (n * d) - */ - void get_descriptors(DescIdVector& ids, DescDataArray descriptors); - - /* *********************** */ - /* STRING-LABELS SUPPORT */ - /* *********************** */ - - /** - * Set the matching between label id and the string corresponding - * to the label - * - * @param ids ids of the labels - * @param labels string for each label - */ - void set_labels_map(std::map& labels); - - /** - * Get the label of the descriptors for the spcified ids. - * NOTE: This is a vector becase this is what we return. - * We can, make wrapper functions that recieve arrays as well. - * - * @param ids vector of ids - * @return vector with the string labels - */ - std::map get_labels_map(); - - /** - * Set the matching between label id and the string corresponding - * to the label - * - * @param ids vector of ids of the labels - * @param labels vector of string for each label - */ - void set_labels_map(LabelIdVector& ids, - std::vector& labels); - - /** - * Get the label of the descriptors for the spcified ids. - * NOTE: This is a vector becase this is what we return. - * We can, make wrapper functions that recieve arrays as well. - * - * @param ids vector of descriptor's id - * @return vector with the string labels - */ - std::vector get_str_labels(DescIdVector& ids); - - /** - * Get the label of the descriptors for the spcified ids. - * NOTE: This is a vector becase this is what we return. - * We can, make wrapper functions that recieve arrays as well. - * - * @param ids vector of ids - * @return vector with the string labels - */ - std::vector label_id_to_string(LabelIdVector& l_id); - - /** - * Get the label of the descriptors for the spcified ids. - * NOTE: This is a vector becase this is what we return. - * We can, make wrapper functions that recieve arrays as well. - * - * @param ids vector of ids - * @return vector with the string labels - */ - std::vector get_str_labels(long* ids, unsigned n); - - - /** - * Get the label of the descriptors for the spcified ids. - * NOTE: This is a vector becase this is what we return. - * We can, make wrapper functions that recieve arrays as well. - * - * @param ids vector of ids - * @return vector with the string labels - */ - long get_label_id(const std::string& label); - }; +enum DescriptorSetEngine { + FaissFlat, + FaissIVFFlat, + TileDBDense, + TileDBSparse, + Flinng +}; + +enum DistanceMetric { L2, IP }; +// enum class Storage { LOCAL = 0, AWS = 1 }; + +class DescriptorSet { + +public: + typedef std::vector DescIdVector; + typedef std::vector LabelIdVector; + typedef std::vector DistanceVector; + typedef float *DescData; + typedef float *DescDataArray; + + class DescriptorSetData; + class DescriptorParams; + +private: + DescriptorSetData *_set; + DescriptorSetEngine _eng; + + RemoteConnection *_remote; + Storage _storage = Storage::LOCAL; + + void write_set_info(); + void read_set_info(const std::string &set_path); + +public: + /** + * Loads an existing collection located at set_path + * + * @param set_path Full Path to the collection folder + */ + DescriptorSet(const std::string &set_path); + + /** + * Creates a new collection, if it does not exist + * + * @param set_path Full Path to the set folder + * @param dim Dimension of the descriptor + * @param eng DescriptorSet Engine (Default is FaissFlat) + * @param metric Metric for calculating distances (Default is L2) + */ + DescriptorSet(const std::string &set_path, unsigned dim, + DescriptorSetEngine eng = FaissFlat, DistanceMetric metric = L2, + VCL::DescriptorParams *param = NULL); + + ~DescriptorSet(); + + // For now, we don't allow copy of objects. + // We will defined this behavoir later based on use-cases. + // Out use-cases now do not require copies, as the + // objects are besically used to access/operate the sets. + DescriptorSet(const DescriptorSetData &) = delete; + + /** + * Writes the DescriptorSet Index to the system. This will overwrite + * the original + */ + void store(); + + /** + * Writes the DescriptorSet Index to the system into a defined path. + * This will overwrite any other index under the same set_path. + */ + void store(std::string set_path); + + /* *********************** */ + /* CORE INTERFACE */ + /* *********************** */ + + /** + * Returns the path to the root directory where all the + * files are for the Set are stored + */ + std::string get_path(); + + /** + * Returns the number of dimensions of each descriptor in the set + */ + unsigned get_dimensions(); + + void finalize_index(); + + /** + * Returns the number of descriptors in the set + */ + long get_n_descriptors(); + + /** + * Inserts n descriptors and their labels into the set + * Both descriptors and labels must have the same number of elements, + * or labels can have no elements. + * If not labels are defined, -1 is assigned to signify "no label". + + * Note: Given the in-memory nature of the Faiss library, adding + * elements on a set using Faiss as engine will not persist the data + * until the store() method is call. This is contrary to the TileDB + * engines, where every add will return after persisting the data. + + * @param descriptors Buffer to descriptors (size n * dim) + * @param n Number of descriptors + * @param labels Array of labels, can be NULL. + */ + long add(DescDataArray descriptors, unsigned n, long *labels = NULL); + + long add_and_store(DescDataArray descriptors, unsigned n, + long *labels = NULL); + + /** + * Search for the k closest neighborhs + * + * @param query Query descriptors buffer + * @param n Number of descriptors that will be queried + * @param k Number of maximun neighbors to be returned + * @return ids id of each neighbor (size n * k) (padded with -1) + * @return distances distances to each neighbor (size n * k). + (padded with -1) + */ + void search(DescDataArray queries, unsigned n, unsigned k, long *ids, + float *distances); + + void search(DescDataArray queries, unsigned n, unsigned k, long *ids); + /** + * Search for neighborhs within a radius. + * + * Note: We only allow the radius search of a single + * element to avoid having to deal with results that are + * of different (unknown) sized for each query. + * We will work on it once we have a more clear use case for + * this call + * + * @param query Query vector + * @param radius Maximun distance allowed + * @param ids Array of ID of the descriptors + * @param distances Distances of each neighbor + */ + void radius_search(DescData query, float radius, long *ids, float *distances); + + /** + * Find the label of the feature vector, based on the closest + * neighbors. + * + * @param descriptors Buffer to descriptors (size n * dim) + * @param n Number of descriptors in buffer + * @return labels Label Ids + * @param quorum Number of elements used for the classification vote. + */ + void classify(DescDataArray descriptors, unsigned n, long *labels, + unsigned quorum = 7); + + /** + * Get the descriptors by specifiying ids. + * This is an exact search by id. + * + * @param ids buffer with ids + * @param n number of ids to query + * @return descriptors pointer to descriptors buffer + size: (n * dim * sizeof(float)) + */ + void get_descriptors(long *ids, unsigned n, DescDataArray descriptors); + + /** + * Trains the index with the data present in the collection + * using the specified metric + */ + void train(); + + /** + * Trains the index using specified descriptors + * + * @param descriptors Reference Descriptors + * @param n Number of descriptors + */ + void train(DescDataArray descriptors, unsigned n); + + /** + * Returns true if the index is trained (train() method called), + * false otherwhise. + */ + bool is_trained(); + + /* *********************** */ + /* VECTOR-BASED INTERFACE */ + /* *********************** */ + + // This are all wrapper around the core-interface + // That are usually useful. + + /** + * Inserts several Descriptors and their labels into the collection + * Both Descriptors and labels must have the same length. + * + * @param descriptors Pointer to buffer containing the DescriptorSet + * @param n Number of elements per descriptor + * @param labels Vector of labels + * @return id of the first (sequential ids) + */ + long add(DescDataArray descriptors, unsigned n, LabelIdVector &labels); + + long add_and_store(DescDataArray descriptors, unsigned n, + LabelIdVector &labels); + /** + * Search for the k closest neighborhs + * // Add comment on why we use k and n_queries. + * // We can also get rid of the + * + * @param query Query descriptors buffer + * @param n_queries Number of descriptors that will be queried + * @param k Number of maximun neighbors to be returned + * @return distances distances of each neighbor (size n * k). + * @return descriptors_ids distances of each neighbor (size n * k). + */ + void search(DescDataArray query, unsigned n, unsigned k, DescIdVector &ids, + DistanceVector &distances); + + void search(DescDataArray query, unsigned n, unsigned k, DescIdVector &ids); + /** + * Find the label of the feature vector, based on the closest + * neighbors. + * + * @param query Query descriptors buffer + * @param n_queries Number of descriptors that will be classified + * @param quorum Number of elements used for the classification vote. + * @return Vector with LabelIds. + */ + LabelIdVector classify(DescDataArray descriptors, unsigned n, + unsigned quorum = 7); + + /** + * Get the label of the descriptors for the spcified ids. + * NOTE: This is a vector becase this is what we return. + * We can, make wrapper functions that recieve arrays as well. + * + * @param ids vector of ids of size n + * @param descriptors return pointer for the float values (n * d) + */ + void get_descriptors(DescIdVector &ids, DescDataArray descriptors); + + /* *********************** */ + /* STRING-LABELS SUPPORT */ + /* *********************** */ + + /** + * Set the matching between label id and the string corresponding + * to the label + * + * @param ids ids of the labels + * @param labels string for each label + */ + void set_labels_map(std::map &labels); + + /** + * Get the label of the descriptors for the spcified ids. + * NOTE: This is a vector becase this is what we return. + * We can, make wrapper functions that recieve arrays as well. + * + * @param ids vector of ids + * @return vector with the string labels + */ + std::map get_labels_map(); + + /** + * Set the matching between label id and the string corresponding + * to the label + * + * @param ids vector of ids of the labels + * @param labels vector of string for each label + */ + void set_labels_map(LabelIdVector &ids, std::vector &labels); + + /** + * Get the label of the descriptors for the spcified ids. + * NOTE: This is a vector becase this is what we return. + * We can, make wrapper functions that recieve arrays as well. + * + * @param ids vector of descriptor's id + * @return vector with the string labels + */ + std::vector get_str_labels(DescIdVector &ids); + + /** + * Get the label of the descriptors for the spcified ids. + * NOTE: This is a vector becase this is what we return. + * We can, make wrapper functions that recieve arrays as well. + * + * @param ids vector of ids + * @return vector with the string labels + */ + std::vector label_id_to_string(LabelIdVector &l_id); + + /** + * Get the label of the descriptors for the spcified ids. + * NOTE: This is a vector becase this is what we return. + * We can, make wrapper functions that recieve arrays as well. + * + * @param ids vector of ids + * @return vector with the string labels + */ + std::vector get_str_labels(long *ids, unsigned n); + + /** + * Get the label of the descriptors for the spcified ids. + * NOTE: This is a vector becase this is what we return. + * We can, make wrapper functions that recieve arrays as well. + * + * @param ids vector of ids + * @return vector with the string labels + */ + long get_label_id(const std::string &label); + + /** + * Set the remote connection used to write to AWS + * + * @param remote pointer to RemoteConnection object + * @return void + */ + void set_connection(RemoteConnection *remote); }; +}; // namespace VCL diff --git a/include/vcl/Exception.h b/include/vcl/Exception.h index 98c0378a..eba12e66 100644 --- a/include/vcl/Exception.h +++ b/include/vcl/Exception.h @@ -34,73 +34,62 @@ #include namespace VCL { - enum ExceptionType { - UndefinedException, - - UnsupportedFormat, - UnsupportedOperation, - UnsupportedIndex, - - ObjectNotFound, - OpenFailed, - NotImplemented, - - ObjectEmpty, - - SizeMismatch, - OutOfBounds, - - TileDBNotFound, - TileDBError, - - OpenCVError, - - UnsupportedSystem, - SystemNotFound, - FFmpegInitFailed, - FFmpegParseFailed, - FFmpegDecodeFailed, - - }; - - struct Exception { - // Which exception - int num; ///< Exception number - const char *name; ///< Exception name - - // Additional information - std::string msg; - int errno_val; - - // Where it was thrown - const char *file; ///< Source file name - int line; ///< Source line number - - Exception(int exc, const char *exc_name, const char *f, int l) - : num(exc), name(exc_name), - msg(), errno_val(0), - file(f), line(l) - {} - - Exception(int exc, const char *exc_name, - const std::string &m, - const char *f, int l) - : num(exc), name(exc_name), - msg(m), errno_val(0), - file(f), line(l) - {} - - Exception(int exc, const char *exc_name, - int err, const std::string &m, - const char *f, int l) - : num(exc), name(exc_name), - msg(m), errno_val(err), - file(f), line(l) - {} - }; - -#define VCLException(name, ...) \ - VCL::Exception(VCL::name, #name, ##__VA_ARGS__, __FILE__, __LINE__) +enum ExceptionType { + UndefinedException, + + UnsupportedFormat, + UnsupportedOperation, + UnsupportedIndex, + + ObjectNotFound, + OpenFailed, + NotImplemented, + + ObjectEmpty, + + SizeMismatch, + OutOfBounds, + + TileDBNotFound, + TileDBError, + + OpenCVError, + + UnsupportedSystem, + SystemNotFound, + FFmpegInitFailed, + FFmpegParseFailed, + FFmpegDecodeFailed, + }; -extern void print_exception(const VCL::Exception &e, FILE *f= stdout); +struct Exception { + // Which exception + int num; ///< Exception number + const char *name; ///< Exception name + + // Additional information + std::string msg; + int errno_val; + + // Where it was thrown + const char *file; ///< Source file name + int line; ///< Source line number + + Exception(int exc, const char *exc_name, const char *f, int l) + : num(exc), name(exc_name), msg(), errno_val(0), file(f), line(l) {} + + Exception(int exc, const char *exc_name, const std::string &m, const char *f, + int l) + : num(exc), name(exc_name), msg(m), errno_val(0), file(f), line(l) {} + + Exception(int exc, const char *exc_name, int err, const std::string &m, + const char *f, int l) + : num(exc), name(exc_name), msg(m), errno_val(err), file(f), line(l) {} +}; + +#define VCLException(name, ...) \ + VCL::Exception(VCL::name, #name, ##__VA_ARGS__, __FILE__, __LINE__) +}; // namespace VCL + +extern void print_exception(const VCL::Exception &e, FILE *f = stdout); diff --git a/include/vcl/Image.h b/include/vcl/Image.h index e984ba05..a2a0febc 100644 --- a/include/vcl/Image.h +++ b/include/vcl/Image.h @@ -5,7 +5,7 @@ * * The MIT License * - * @copyright Copyright (c) 2017 Intel Corporation + * @copyright Copyright (c) 2023 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,732 +28,908 @@ * @section DESCRIPTION * * This file declares the C++ API for Image. NOTE: Operations on an Image are - * delayed until the data is actually requested (in a store operation, or a get_* - * operation such as get_cvmat) + * delayed until the data is actually requested (in a store operation, or a + * get_* operation such as get_cvmat) */ #pragma once -#include #include +#include #include #include +#include #include #include +#include #include "Exception.h" +#include "RemoteConnection.h" #include "TDBImage.h" #include "utils.h" +#include +#include +#include namespace VCL { +/** + * Uses the OpenCV Rect class to define an area in the image + * (starting x coordinate, starting y coordinate, height, width) + */ +typedef cv::Rect Rectangle; + +class Image { +public: + enum class Format { NONE_IMAGE = 0, JPG = 1, PNG = 2, TDB = 3, BIN = 4 }; + + // enum class Storage { LOCAL = 0, AWS = 1 }; + + /* *********************** */ + /* CONSTRUCTORS */ + /* *********************** */ + + /** + * Creates an Image object from the image id (where the + * image data can be found in the system). + * + * @param image_id The full path to the image + * @param bucket_name Optional parameter for bucket name if using AWS + * storage + */ + Image(const std::string &image_id, std::string bucket_name = ""); + + /** + * Creates an Image object from the OpenCV Mat + * + * @param cv_img An OpenCV Mat that contains an image + * @param copy Deep copy if true, shallow copy if false + */ + Image(const cv::Mat &cv_img, bool copy = true); + + /** + * Creates an OpenCV Image object from an encoded buffer + * + * @param buffer An encoded buffer that contains the image data + * @param size Size of the encoded buffer + * @param flags Flags specifying the color type of the encoded image, + * defaults to IMREAD_COLOR + * @see OpenCV documentation on imdecode for more information on flags + */ + Image(void *buffer, long size, char raw_binary_file = 0, + int flags = cv::IMREAD_ANYCOLOR); + + /** + * Creates a TDB Image object from a buffer of raw pixel data + * + * @param buffer A buffer that contains the image data + * @param dimensions An OpenCV Size object that contains the height + * and width of the image + * @param type The OpenCV type of the image + * @see OpenCV documentation for more information on type and Size + */ + Image(void *buffer, cv::Size dimensions, int cv_type); + + /** + * Creates a new Image object from an existing Image object + * + * @param img An existing Image object + * @param copy Makes a deep copy if true, a shallow copy otherwise + */ + Image(const Image &img, bool copy = true); + + /** + * Move constructor, needed to avoid copies of the arrays. + * noexcept is needed to let vectors grow and call the move + * instead of copy constructor. + * + * @param img An rvalue Image object + */ + Image(Image &&img) noexcept; + + /** + * Assigns an Image object to this Image object by performing a deep + * copy operation + * + * @param img An existing Image object + */ + Image &operator=(const Image &img); + + ~Image(); + + /* *********************** */ + /* GET FUNCTIONS */ + /* *********************** */ + /** + * Gets the full path to the Image object + * + * @return The string containing the full path to the Image + */ + std::string get_image_id() const; + + /** + * Gets the dimensions of the image in pixels (width, height) using + * an OpenCV Size object + * @param performOp Specify if operations should be performed first. Default + * is true. + * @return The dimension of the image in pixels as an OpenCV Size object + */ + cv::Size get_dimensions(bool performOp = true); + + /** + * Gets the format of the Image object + * + * @return The Format of the Image object + */ + VCL::Image::Format get_image_format() const; + + /** + * Gets the size of the image in pixels (height * width * channels) + * + * @return The size of the image in pixels + */ + long get_raw_data_size(); + + /** + * Gets the OpenCV type of the image + * + * @return The OpenCV type (CV_8UC3, etc) + * @see OpenCV documentation on types for more details + */ + int get_image_type() const; + + /** + * Gets a specific area of the image, indicated by the Rectangle + * parameters and returns a new Image object + * + * @param roi The region of interest (starting x coordinate, starting + * y coordinate, height, width) + * @param performOp Specify if operations should be performed first. Default + * is true. + * @return A new Image object that is only the requested area + */ + Image get_area(const Rectangle &roi, bool performOp = true) const; + + /** + * Gets an OpenCV Mat that contains the image data + * + * @param copy Specify if a deep copy of the cvmat will be made before + * returning the cvmat object. + * @param performOp Specify if operations should be performed first. Default + * is true. + * @return An OpenCV Mat + */ + cv::Mat get_cvmat(bool copy = true, bool performOp = true); + + /** + * Gets the raw image data + * + * @param buffer A buffer (of any type) that will contain the image + * data when the function ends + * @param performOp Specify if operations should be performed first. Default + * is true. + * @param buffer_size The pixel size of the image (length of + * the buffer, not bytes) + */ + void get_raw_data(void *buffer, long buffer_size, bool performOp = true); + + /** + * Gets encoded image data in a buffer + * + * @param format The Format the Image should be encoded as + * @param params Optional parameters + * @return A vector containing the encoded image + * @see OpenCV documentation for imencode for more details + +/** +* Gets encoded image data in a buffer +* +* @param format The Format the Image should be encoded as +* @param params Optional parameters +* @return A vector containing the encoded image +* @see OpenCV documentation for imencode for more details +*/ + std::vector + get_encoded_image(VCL::Image::Format format, + const std::vector ¶ms = std::vector()); + + /** + * Gets encoded image data in a buffer in a async way + * + * @param format The Format the Image should be encoded as + * @param params Optional parameters + * @param enc_img_vec Vector of operated images + * @return A vector containing the encoded image + * @see OpenCV documentation for imencode for more details + */ + std::vector + get_encoded_image_async(VCL::Image::Format format, + const std::vector ¶ms = std::vector()); + + /** + * Executes the operations in the operation vector + * + * @return -1 if operation should run on a separate thread otherwise 0 + */ + int execute_operation(); + + /** + * @return Size of the operations vector + */ + int get_enqueued_operation_count(); + + /** + * @return Number of operations completed + */ + int get_op_completed(); + + /** + * @return Parameters required to run a remote operation + */ + Json::Value get_remoteOp_params(); + + /* *********************** */ + /* SET FUNCTIONS */ + /* *********************** */ + + /** + * Sets the type of compression to be used when compressing. Currently + * applicable only to TileDB + * + * @param comp The compression type + */ + void set_compression(CompressionType comp); + + /** + * Sets the size of the image in pixels (width, height) using + * an OpenCV Size object + * + * @param dims The dimensions of the image in OpenCV Size format + * @see OpenCV documentation on Size for more details + */ + void set_dimensions(cv::Size dims); + + /** + * Sets the OpenCV type of the image + * + * @param The OpenCV type (CV_8UC3, etc) + * @see OpenCV documentation on types for more details + */ + void set_image_type(int cv_type); + + void set_minimum_dimension(int dimension); + + /** + * Updates the number of operations completed + */ + void update_op_completed(); + + /** + * Set parameters to run a remote operation + */ + void set_remoteOp_params(Json::Value options, std::string url); + + void set_connection(RemoteConnection *remote); + + /* *********************** */ + /* IMAGE INTERACTIONS */ + /* *********************** */ + + /** + * Writes the Image to the system at the given location and in + * the given format + * + * @param image_id Full path to where the image should be written + * @param image_format Format in which to write the image + * @param store_metadata Flag to indicate whether to store the + * image metadata. Defaults to true (assuming no other metadata + * storage) + */ + void store(const std::string &image_id, VCL::Image::Format image_format, + bool store_metadata = true); + + /** + * Resizes the Image to the given size. This operation is not + * performed until the data is needed (ie, store is called or + * one of the get_ functions such as get_cvmat) + * + * @param new_height Number of rows + * @param new_width Number of columns + */ + void resize(int new_height, int new_width); + + /** + * Crops the Image to the area specified. This operation is not + * performed until the data is needed (ie, store is called or + * one of the get_ functions such as get_cvmat) + * + * @param rect The region of interest (starting x coordinate, + * starting y coordinate, height, width) the image should be + * cropped to + */ + void crop(const Rectangle &rect); + + /** + * Performs a thresholding operation on the Image. Discards the pixel + * value if it is less than or equal to the threshold and sets that + * pixel to zero. This operation is not performed until the data + * is needed (ie, store is called or one of the get_ functions + * such as get_cvmat) + * + * @param value The threshold value + */ + void threshold(int value); + + /** + * Flips the image either vertically, horizontally, or both, depending + * on code, following OpenCV convention: + * 0 means flip vertically + * positive value means flip horizontally + * negative value means flip both vertically and horizontally + * + * @param code Specificies vertical, horizontal, or both. + */ + void flip(int code); + + /** + * Rotates the image following the angle provided as parameter. + * + * @param angle Specificies the angle of rotation + * @param keep_resize Specifies if the image will be resized after + * the rotation, or size will be kept. + */ + void rotate(float angle, bool keep_size); + + /** + * Performs a remote operation on the image. + * + * @param url Remote url + * @param options operation options + */ + void syncremoteOperation(std::string url, Json::Value options); + + /** + * Performs a remote operation on the image. + * + * @param url Remote url + * @param options operation options + */ + void remoteOperation(std::string url, Json::Value options); + + /** + * Performs a user defined operation on the image. + * + * @param options operation options + */ + void userOperation(Json::Value options); + + /** + * Checks to see if the Image has a depth associated with it. + * Currently returns false, as we do not support depth camera + * input yet. + */ + bool has_depth() { return false; }; + + /** + * Deletes the Image as well as removes file from system if + * it exists + */ + void delete_image(); + /* *********************** */ + /* COPY FUNCTIONS */ + /* *********************** */ + /** + * Copies (deep copy) an OpenCV Mat into the Image OpenCV Mat + * + * @param cv_img An existing OpenCV Mat + */ + void deep_copy_cv(const cv::Mat &cv_img); + + /** + * Copies (shallow copy) an OpenCV Mat into the Image OpenCV Mat + * + * @param cv_img An existing OpenCV Mat + */ + void shallow_copy_cv(const cv::Mat &cv_img); + + /** + * Copies the Image OpenCV Mat into a buffer + * + * @param buffer The buffer that will contain the image + * data + */ + template void copy_to_buffer(T *buffer); + + std::string format_to_string(Image::Format format); + +private: + /** + * Default constructor, creates an empty Image object. + * Used when reading from the file system + */ + Image(); + + // Forward declaration of Operation class, to be used of _operations + // list + class Operation; + + // Forward declaration of ImageTest class, that is used for the unit + // test to accesss private methods of this class + friend class ImageTest; + + /* *********************** */ + /* VARIABLES */ + /* *********************** */ + // Image height and width + uint _height, _width; + + // Type of image (OpenCV definition) and number of channels + int _cv_type, _channels; + + // Maintains order of operations requested + std::vector> _operations; + + // Count of operations executed + int _op_completed; + + // Parameters required for remote operations + Json::Value remoteOp_params; + + // Remote connection (if one exists) + RemoteConnection *_remote; + + // Image format and compression type + Format _format; + CompressionType _compress; + Storage _storage = Storage::LOCAL; + + // Full path to image + std::string _image_id; + + // Image data (OpenCV Mat or TDBImage) + cv::Mat _cv_img; + TDBImage *_tdb; + char *_bin; + long _bin_size; + + /* *********************** */ + /* UTIL FUNCTIONS */ + /* *********************** */ + + /** + * Performs the set of operations that have been requested + * on the Image + */ + void perform_operations(); + + /** + * Creates full path to Image with appropriate extension based + * on the Image::Format + * + * @param filename The path to the Image object + * @param format The Image::Format of the Image object + * @return Full path to the object including extension + */ + std::string create_fullpath(const std::string &filename, + Image::Format format); + + /* *********************** */ + /* OPERATION */ + /* *********************** */ + + enum class OperationType { + READ, + WRITE, + RESIZE, + CROP, + THRESHOLD, + FLIP, + ROTATE, + SYNCREMOTEOPERATION, + REMOTEOPERATION, + USEROPERATION + }; + + /** + * Provides a way to keep track of what operations should + * be performed on the data when it is needed + * + * Operation is the base class, it keeps track of the format + * of the image data, defines a way to convert Format to + * a string, and defines a virtual function that overloads the + * () operator + */ + class Operation { + protected: + /** The format of the image for this operation */ + Format _format; + + /** + * Constructor, sets the format + * + * @param format The format for the operation + * @see Image.h for more details on Format + */ + Operation(Format format) : _format(format){}; + + public: + /** + * Implemented by the specific operation, performs what + * the operation is supposed to do + * + * @param img A pointer to the current Image object + */ + virtual void operator()(Image *img) = 0; + + virtual OperationType get_type() const = 0; + }; + + /* *********************** */ + /* READ OPERATION */ + /* *********************** */ + /** + * Extends Operation, reads image from the file system + */ + class Read : public Operation { + private: + /** The full path to the object to read */ + std::string _fullpath; + + public: + /** + * Constructor, sets the format and path for reading + * + * @param filename The full path to read from + * @param format The format to read the image from + * @see Image.h for more details on ::Format + */ + Read(const std::string &filename, Format format); + + /** + * Reads an image from the file system (based on the format + * and file path indicated) + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::READ; }; + }; + + /* *********************** */ + /* WRITE OPERATION */ + /* *********************** */ + /** + * Extends Operation, writes to the file system in the specified + * format + */ + class Write : public Operation { + private: + /** The full path of where to write the image */ + std::string _fullpath; + /** The format the image used to be stored as */ + Format _old_format; + /** Whether to store the metadata */ + bool _metadata; + + public: + /** + * Constructor, sets the formats and path for writing + * + * @param filename The full path to write to + * @param format The format to store the image in + * @param old_format The format the image was stored in + * @see Image.h for more details on ::Format + */ + Write(const std::string &filename, Format format, Format old_format, + bool metadata); + /** + * Writes an image to the file system (based on the format + * and file path indicated) + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::WRITE; }; + }; + + /* *********************** */ + /* RESIZE OPERATION */ + /* *********************** */ + /** + * Extends Operation, resizes the image to the specified size + */ + class Resize : public Operation { + private: + /** Gives the height and width to resize the image to */ + Rectangle _rect; + + public: + /** + * Constructor, sets the size to resize to and the format + * + * @param rect Contains height and width to resize to + * @param format The current format of the image data + * @see Image.h for more details on ::Format and Rectangle + */ + Resize(const Rectangle &rect, Format format) + : Operation(format), _rect(rect){}; + + /** + * Resizes an image to the given dimensions + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::RESIZE; }; + }; + + /* *********************** */ + /* CROP OPERATION */ + /* *********************** */ + /** + * Extends Operation, crops the image to the specified area + */ + class Crop : public Operation { + private: + /** Gives the dimensions and coordinates of the desired area */ + Rectangle _rect; + + public: + /** + * Constructor, sets the area to crop to and the format + * + * @param rect Contains dimensions and coordinates of + * desired area + * @param format The current format of the image data + * @see Image.h for more details on ::Format and Rectangle + */ + Crop(const Rectangle &rect, Format format) + : Operation(format), _rect(rect){}; + + /** + * Crops the image to the given area + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::CROP; }; + }; + + /* *********************** */ + /* THRESHOLD OPERATION */ + /* *********************** */ + /** Extends Operation, performs a thresholding operation that + * discards the pixel value if it is less than or equal to the + * threshold and sets that pixel to 0 + */ + class Threshold : public Operation { + private: + /** Minimum value pixels should be */ + int _threshold; + + public: + /** + * Constructor, sets the threshold value and format + * + * @param value Minimum value pixels should be + * @param format The current format of the image data + * @see Image.h for more details on ::Format + */ + Threshold(const int value, Format format) + : Operation(format), _threshold(value){}; + + /** + * Performs the thresholding operation + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::THRESHOLD; }; + }; + + /* *********************** */ + /* FLIP OPERATION */ + /* *********************** */ + /** Extends Operation, performs a flip operation that + */ + class Flip : public Operation { + private: + /** Minimum value pixels should be */ + int _code; + + public: + /** + * Constructor, sets the flip code value. + * + * @param code Type of flipping operation + * @param format The current format of the image data + * @see Image.h for more details on ::Format + */ + Flip(const int code, Format format) : Operation(format), _code(code){}; + + /** + * Performs the flip operation + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::FLIP; }; + }; + + /* *********************** */ + /* ROTATE OPERATION */ + /* *********************** */ + /** Extends Operation, performs a flip operation that + */ + class Rotate : public Operation { + private: + /** Minimum value pixels should be */ + float _angle; + bool _keep_size; + + public: + /** + * Constructor, sets the flip code value. + * + * @param format The current format of the image data + * @see Image.h for more details on Format + */ + Rotate(float angle, bool keep_size, Format format) + : Operation(format), _angle(angle), _keep_size(keep_size){}; + + /** + * Performs the flip operation + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::ROTATE; }; + }; + + /* *********************** */ + /* SYNC OPERATION */ + /* *********************** */ + /** Extends Operation, performs a remote operation that + */ + class SyncRemoteOperation : public Operation { + private: + /** Minimum value pixels should be */ + std::string _url; + Json::Value _options; + + public: + /** + * Constructor, sets the flip code value. + * + * @param url The current format of the image data + * @param options + * @see Image.h for more details on Format + */ + SyncRemoteOperation(std::string url, Json::Value options, Format format) + : Operation(format), _url(url), _options(options){}; + /** - * Uses the OpenCV Rect class to define an area in the image - * (starting x coordinate, starting y coordinate, height, width) + * Performs the remote operation + * + * @param img A pointer to the current Image object */ - typedef cv::Rect Rectangle; - - class Image { - public: - - enum class Format { - NONE_IMAGE = 0, - JPG = 1, - PNG = 2, - TDB = 3, - BIN = 4 - }; - - /* *********************** */ - /* CONSTRUCTORS */ - /* *********************** */ - - /** - * Creates an Image object from the image id (where the - * image data can be found in the system). - * - * @param image_id The full path to the image - */ - Image(const std::string &image_id); - - /** - * Creates an Image object from the OpenCV Mat - * - * @param cv_img An OpenCV Mat that contains an image - * @param copy Deep copy if true, shallow copy if false - */ - Image(const cv::Mat &cv_img, bool copy=true); - - /** - * Creates an OpenCV Image object from an encoded buffer - * - * @param buffer An encoded buffer that contains the image data - * @param size Size of the encoded buffer - * @param flags Flags specifying the color type of the encoded image, - * defaults to IMREAD_COLOR - * @see OpenCV documentation on imdecode for more information on flags - */ - Image(void* buffer, long size, char raw_binary_file=0, int flags=cv::IMREAD_ANYCOLOR); - - /** - * Creates a TDB Image object from a buffer of raw pixel data - * - * @param buffer A buffer that contains the image data - * @param dimensions An OpenCV Size object that contains the height - * and width of the image - * @param type The OpenCV type of the image - * @see OpenCV documentation for more information on type and Size - */ - Image(void* buffer, cv::Size dimensions, int cv_type); - - /** - * Creates a new Image object from an existing Image object - * - * @param img An existing Image object - * @param copy Makes a deep copy if true, a shallow copy otherwise - */ - Image(const Image &img, bool copy=true); - - /** - * Move constructor, needed to avoid copies of the arrays. - * noexcept is needed to let vectors grow and call the move - * instead of copy constructor. - * - * @param img An rvalue Image object - */ - Image(Image &&img) noexcept; - - /** - * Assigns an Image object to this Image object by performing a deep - * copy operation - * - * @param img An existing Image object - */ - Image& operator=(const Image &img); - - ~Image(); - - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ - /** - * Gets the full path to the Image object - * - * @return The string containing the full path to the Image - */ - std::string get_image_id() const; - - /** - * Gets the dimensions of the image in pixels (width, height) using - * an OpenCV Size object - * @return The dimension of the image in pixels as an OpenCV Size object - */ - cv::Size get_dimensions(); - - /** - * Gets the format of the Image object - * - * @return The Format of the Image object - */ - VCL::Image::Format get_image_format() const; - - /** - * Gets the size of the image in pixels (height * width * channels) - * - * @return The size of the image in pixels - */ - long get_raw_data_size(); - - /** - * Gets the OpenCV type of the image - * - * @return The OpenCV type (CV_8UC3, etc) - * @see OpenCV documentation on types for more details - */ - int get_image_type() const; - - /** - * Gets a specific area of the image, indicated by the Rectangle - * parameters and returns a new Image object - * - * @param roi The region of interest (starting x coordinate, starting - * y coordinate, height, width) - * @return A new Image object that is only the requested area - */ - Image get_area(const Rectangle &roi) const; - - /** - * Gets an OpenCV Mat that contains the image data - * - * @param copy Specify if a deep copy of the cvmat will be made before - * returning the cvmat object. - * @return An OpenCV Mat - */ - cv::Mat get_cvmat(bool copy=true); - - /** - * Gets the raw image data - * - * @param buffer A buffer (of any type) that will contain the image - * data when the function ends - * @param buffer_size The pixel size of the image (length of - * the buffer, not bytes) - */ - void get_raw_data(void* buffer, long buffer_size); - - /** - * Gets encoded image data in a buffer - * - * @param format The Format the Image should be encoded as - * @param params Optional parameters - * @return A vector containing the encoded image - * @see OpenCV documentation for imencode for more details - */ - std::vector get_encoded_image(VCL::Image::Format format, - const std::vector& params=std::vector()); - - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ - - /** - * Sets the type of compression to be used when compressing. Currently - * applicable only to TileDB - * - * @param comp The compression type - */ - void set_compression(CompressionType comp); - - /** - * Sets the size of the image in pixels (width, height) using - * an OpenCV Size object - * - * @param dims The dimensions of the image in OpenCV Size format - * @see OpenCV documentation on Size for more details - */ - void set_dimensions(cv::Size dims); - - /** - * Sets the OpenCV type of the image - * - * @param The OpenCV type (CV_8UC3, etc) - * @see OpenCV documentation on types for more details - */ - void set_image_type(int cv_type); - - void set_minimum_dimension(int dimension); - - /* *********************** */ - /* IMAGE INTERACTIONS */ - /* *********************** */ - - /** - * Writes the Image to the system at the given location and in - * the given format - * - * @param image_id Full path to where the image should be written - * @param image_format Format in which to write the image - * @param store_metadata Flag to indicate whether to store the - * image metadata. Defaults to true (assuming no other metadata - * storage) - */ - void store(const std::string &image_id, VCL::Image::Format image_format, - bool store_metadata=true); - - /** - * Resizes the Image to the given size. This operation is not - * performed until the data is needed (ie, store is called or - * one of the get_ functions such as get_cvmat) - * - * @param new_height Number of rows - * @param new_width Number of columns - */ - void resize(int new_height, int new_width); - - /** - * Crops the Image to the area specified. This operation is not - * performed until the data is needed (ie, store is called or - * one of the get_ functions such as get_cvmat) - * - * @param rect The region of interest (starting x coordinate, - * starting y coordinate, height, width) the image should be - * cropped to - */ - void crop(const Rectangle &rect); - - /** - * Performs a thresholding operation on the Image. Discards the pixel - * value if it is less than or equal to the threshold and sets that - * pixel to zero. This operation is not performed until the data - * is needed (ie, store is called or one of the get_ functions - * such as get_cvmat) - * - * @param value The threshold value - */ - void threshold(int value); - - /** - * Flips the image either vertically, horizontally, or both, depending - * on code, following OpenCV convention: - * 0 means flip vertically - * positive value means flip horizontally - * negative value means flip both vertically and horizontally - * - * @param code Specificies vertical, horizontal, or both. - */ - void flip(int code); - - /** - * Rotates the image following the angle provided as parameter. - * - * @param angle Specificies the angle of rotation - * @param keep_resize Specifies if the image will be resized after - * the rotation, or size will be kept. - */ - void rotate(float angle, bool keep_size); - - /** - * Checks to see if the Image has a depth associated with it. - * Currently returns false, as we do not support depth camera - * input yet. - */ - bool has_depth() { return false; }; - - /** - * Deletes the Image as well as removes file from system if - * it exists - */ - void delete_image(); - /* *********************** */ - /* COPY FUNCTIONS */ - /* *********************** */ - /** - * Copies (deep copy) an OpenCV Mat into the Image OpenCV Mat - * - * @param cv_img An existing OpenCV Mat - */ - void deep_copy_cv(const cv::Mat &cv_img); - - /** - * Copies (shallow copy) an OpenCV Mat into the Image OpenCV Mat - * - * @param cv_img An existing OpenCV Mat - */ - void shallow_copy_cv(const cv::Mat &cv_img); - - /** - * Copies the Image OpenCV Mat into a buffer - * - * @param buffer The buffer that will contain the image - * data - */ - template void copy_to_buffer(T* buffer); - - private: - - /** - * Default constructor, creates an empty Image object. - * Used when reading from the file system - */ - Image(); - - // Forward declaration of Operation class, to be used of _operations - // list - class Operation; - - // Forward declaration of ImageTest class, that is used for the unit - // test to accesss private methods of this class - friend class ImageTest; - - /* *********************** */ - /* VARIABLES */ - /* *********************** */ - // Image height and width - uint _height, _width; - - // Type of image (OpenCV definition) and number of channels - int _cv_type, _channels; - - // Maintains order of operations requested - std::vector> _operations; - - // Image format and compression type - Format _format; - CompressionType _compress; - - // Full path to image - std::string _image_id; - - // Image data (OpenCV Mat or TDBImage) - cv::Mat _cv_img; - TDBImage *_tdb; - char* _bin; - long _bin_size; - - - - /* *********************** */ - /* UTIL FUNCTIONS */ - /* *********************** */ - - /** - * Performs the set of operations that have been requested - * on the Image - */ - void perform_operations(); - - std::string format_to_string(Image::Format format); - - /** - * Creates full path to Image with appropriate extension based - * on the Image::Format - * - * @param filename The path to the Image object - * @param format The Image::Format of the Image object - * @return Full path to the object including extension - */ - std::string create_fullpath(const std::string &filename, - Image::Format format); - - /* *********************** */ - /* OPERATION */ - /* *********************** */ - - enum class OperationType { - READ, - WRITE, - RESIZE, - CROP, - THRESHOLD, - FLIP, - ROTATE - }; - - /** - * Provides a way to keep track of what operations should - * be performed on the data when it is needed - * - * Operation is the base class, it keeps track of the format - * of the image data, defines a way to convert Format to - * a string, and defines a virtual function that overloads the - * () operator - */ - class Operation { - protected: - /** The format of the image for this operation */ - Format _format; - - /** - * Constructor, sets the format - * - * @param format The format for the operation - * @see Image.h for more details on Format - */ - Operation(Format format) - : _format(format) - { - }; - - public: - /** - * Implemented by the specific operation, performs what - * the operation is supposed to do - * - * @param img A pointer to the current Image object - */ - virtual void operator()(Image *img) = 0; - - virtual OperationType get_type() const = 0; - }; - - /* *********************** */ - /* READ OPERATION */ - /* *********************** */ - /** - * Extends Operation, reads image from the file system - */ - class Read : public Operation { - private: - /** The full path to the object to read */ - std::string _fullpath; - - public: - /** - * Constructor, sets the format and path for reading - * - * @param filename The full path to read from - * @param format The format to read the image from - * @see Image.h for more details on ::Format - */ - Read(const std::string& filename, Format format); - - /** - * Reads an image from the file system (based on the format - * and file path indicated) - * - * @param img A pointer to the current Image object - */ - void operator()(Image *img); - - - OperationType get_type() const { return OperationType::READ; }; - }; - - /* *********************** */ - /* WRITE OPERATION */ - /* *********************** */ - /** - * Extends Operation, writes to the file system in the specified - * format - */ - class Write : public Operation { - private: - /** The full path of where to write the image */ - std::string _fullpath; - /** The format the image used to be stored as */ - Format _old_format; - /** Whether to store the metadata */ - bool _metadata; - - public: - /** - * Constructor, sets the formats and path for writing - * - * @param filename The full path to write to - * @param format The format to store the image in - * @param old_format The format the image was stored in - * @see Image.h for more details on ::Format - */ - Write(const std::string& filename, Format format, - Format old_format, bool metadata); - /** - * Writes an image to the file system (based on the format - * and file path indicated) - * - * @param img A pointer to the current Image object - */ - void operator()(Image *img); - - OperationType get_type() const { return OperationType::WRITE; }; - }; - - /* *********************** */ - /* RESIZE OPERATION */ - /* *********************** */ - /** - * Extends Operation, resizes the image to the specified size - */ - class Resize : public Operation { - private: - /** Gives the height and width to resize the image to */ - Rectangle _rect; - - public: - /** - * Constructor, sets the size to resize to and the format - * - * @param rect Contains height and width to resize to - * @param format The current format of the image data - * @see Image.h for more details on ::Format and Rectangle - */ - Resize(const Rectangle &rect, Format format) - : Operation(format), - _rect(rect) - { - }; - - /** - * Resizes an image to the given dimensions - * - * @param img A pointer to the current Image object - */ - void operator()(Image *img); - - OperationType get_type() const { return OperationType::RESIZE; }; - }; - - /* *********************** */ - /* CROP OPERATION */ - /* *********************** */ - /** - * Extends Operation, crops the image to the specified area - */ - class Crop : public Operation { - private: - /** Gives the dimensions and coordinates of the desired area */ - Rectangle _rect; - - public: - /** - * Constructor, sets the area to crop to and the format - * - * @param rect Contains dimensions and coordinates of - * desired area - * @param format The current format of the image data - * @see Image.h for more details on ::Format and Rectangle - */ - Crop(const Rectangle &rect, Format format) - : Operation(format), - _rect(rect) - { - }; - - /** - * Crops the image to the given area - * - * @param img A pointer to the current Image object - */ - void operator()(Image *img); - - OperationType get_type() const { return OperationType::CROP; }; - }; - - /* *********************** */ - /* THRESHOLD OPERATION */ - /* *********************** */ - /** Extends Operation, performs a thresholding operation that - * discards the pixel value if it is less than or equal to the - * threshold and sets that pixel to 0 - */ - class Threshold : public Operation { - private: - /** Minimum value pixels should be */ - int _threshold; - - public: - /** - * Constructor, sets the threshold value and format - * - * @param value Minimum value pixels should be - * @param format The current format of the image data - * @see Image.h for more details on ::Format - */ - Threshold(const int value, Format format) - : Operation(format), - _threshold(value) - { - }; - - /** - * Performs the thresholding operation - * - * @param img A pointer to the current Image object - */ - void operator()(Image *img); - - OperationType get_type() const { return OperationType::THRESHOLD; }; - }; - - /* *********************** */ - /* FLIP OPERATION */ - /* *********************** */ - /** Extends Operation, performs a flip operation that - */ - class Flip : public Operation { - private: - /** Minimum value pixels should be */ - int _code; - - public: - /** - * Constructor, sets the flip code value. - * - * @param code Type of flipping operation - * @param format The current format of the image data - * @see Image.h for more details on ::Format - */ - Flip(const int code, Format format) - : Operation(format), - _code(code) - { - }; - - /** - * Performs the flip operation - * - * @param img A pointer to the current Image object - */ - void operator()(Image *img); - - OperationType get_type() const { return OperationType::FLIP; }; - }; - - /* *********************** */ - /* ROTATE OPERATION */ - /* *********************** */ - /** Extends Operation, performs a flip operation that - */ - class Rotate : public Operation { - private: - /** Minimum value pixels should be */ - float _angle; - bool _keep_size; - - public: - /** - * Constructor, sets the flip code value. - * - * @param format The current format of the image data - * @see Image.h for more details on Format - */ - Rotate(float angle, bool keep_size, Format format) - : Operation(format), - _angle(angle), - _keep_size(keep_size) - { - }; - - /** - * Performs the flip operation - * - * @param img A pointer to the current Image object - */ - void operator()(Image *img); - - OperationType get_type() const { return OperationType::ROTATE; }; - }; - - /* *********************** */ - /* IMAGE INTERACTIONS */ - /* *********************** */ - - /** - * Stores a Read Operation in the list of operations - * to perform - * - * @param image_id The full path to the image to be read - */ - void read(const std::string &image_id); - - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ - - /** - * Sets the Image object to contain raw pixel data - * from a buffer of raw pixel data (stored in a TDB object) - * - * @param buffer The buffer containing the raw pixel data - * @param size The size of the buffer - */ - void set_data_from_raw(void* buffer, long size); - - /** - * Sets the Image object to contain raw pixel data - * from an encoded image buffer (stored in a CV Mat) - * - * @param buffer The buffer containing the encoded pixel data - */ - void set_data_from_encoded(void *buffer, long size, - char raw_binary_file=0, int flags=cv::IMREAD_ANYCOLOR); - - /** - * Sets the format of the Image object - * - * @param extension A string containing the file system - * extension corresponding to the desired Image::Format - * @see Image.h for more details on Image::Format - */ - void set_format(const std::string &extension); + void operator()(Image *img); + + OperationType get_type() const { + return OperationType::SYNCREMOTEOPERATION; }; + }; + + /* *********************** */ + /* REMOTE OPERATION */ + /* *********************** */ + /** Extends Operation, performs a remote operation that + */ + class RemoteOperation : public Operation { + private: + /** Minimum value pixels should be */ + std::string _url; + Json::Value _options; + + public: + /** + * Constructor, sets the flip code value. + * + * @param url The current format of the image data + * @param options + * @see Image.h for more details on Format + */ + RemoteOperation(std::string url, Json::Value options, Format format) + : Operation(format), _url(url), _options(options){}; + + /** + * Performs the remote operation + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::REMOTEOPERATION; }; + }; + + /* *********************** */ + /* USER OPERATION */ + /* *********************** */ + /** Extends Operation, performs a user operation that + */ + class UserOperation : public Operation { + private: + /** Minimum value pixels should be */ + Json::Value _options; + + public: + /** + * Constructor, sets the flip code value. + * + * @param options + * @see Image.h for more details on Format + */ + UserOperation(Json::Value options, Format format) + : Operation(format), _options(options){}; + + /** + * Performs the user operation + * + * @param img A pointer to the current Image object + */ + void operator()(Image *img); + + OperationType get_type() const { return OperationType::USEROPERATION; }; + }; + + /* *********************** */ + /* IMAGE INTERACTIONS */ + /* *********************** */ + + /** + * Stores a Read Operation in the list of operations + * to perform + * + * @param image_id The full path to the image to be read + */ + void read(const std::string &image_id); + + /* *********************** */ + /* SET FUNCTIONS */ + /* *********************** */ + + /** + * Sets the Image object to contain raw pixel data + * from a buffer of raw pixel data (stored in a TDB object) + * + * @param buffer The buffer containing the raw pixel data + * @param size The size of the buffer + */ + void set_data_from_raw(void *buffer, long size); + + /** + * Sets the Image object to contain raw pixel data + * from an encoded image buffer (stored in a CV Mat) + * + * @param buffer The buffer containing the encoded pixel data + */ + void set_data_from_encoded(void *buffer, long size, char raw_binary_file = 0, + int flags = cv::IMREAD_ANYCOLOR); + + /** + * Sets the format of the Image object + * + * @param extension A string containing the file system + * extension corresponding to the desired Image::Format + * @see Image.h for more details on Image::Format + */ + void set_format(const std::string &extension); }; +}; // namespace VCL diff --git a/include/vcl/KeyFrame.h b/include/vcl/KeyFrame.h index 5072de9f..c665c629 100644 --- a/include/vcl/KeyFrame.h +++ b/include/vcl/KeyFrame.h @@ -36,115 +36,112 @@ #include "Exception.h" -extern "C" -{ +extern "C" { #include #include } namespace VCL { - struct KeyFrame { - unsigned idx; - int64_t base; - }; - - typedef std::vector KeyFrameList; - typedef std::vector EncodedFrameList; - - class KeyFrameOp { - protected: - struct FormatContext { - AVFormatContext* fmt_context; - - // For now, we only process videos with a SINGLE video stream. - AVStream* video_stream; // Pointer to the video stream in the ctx - unsigned video_stream_idx; // Index to the video stream in the ctx - }; - - FormatContext _fctx; - std::string _filename; - - int64_t _time_base; - int64_t _nb_frames; - - int init_stream(void); - std::string error_msg(int errnum, const std::string& opt = ""); - - public: - KeyFrameOp(std::string filename); - virtual ~KeyFrameOp(); - }; - - /* *********************** */ - /* KEY_FRAME_PARSER */ - /* *********************** */ - class KeyFrameParser : public KeyFrameOp { - private: - KeyFrameList _frame_list; - - int fill_frame_list(void) noexcept; - - public: - KeyFrameParser(std::string filename) : KeyFrameOp(filename) {}; - ~KeyFrameParser() override {}; - - const KeyFrameList& parse(void); - }; - - /* *********************** */ - /* KEY_FRAME_DECODER */ - /* *********************** */ - class KeyFrameDecoder : public KeyFrameOp { - private: - enum class H264Format { - AVCC = 0, - AnnexB = 1 - }; - - struct DecoderContext { - AVBSFContext* bsf_context; - AVCodecContext* video_codec_context; - AVCodecContext* frame_codec_context; - SwsContext* sws_context; - H264Format byte_stream_format; - - DecoderContext() : bsf_context(NULL), video_codec_context(NULL), - frame_codec_context(NULL), sws_context(NULL), - byte_stream_format(H264Format::AVCC) {}; - }; - - struct FrameInterval { - KeyFrame start; - KeyFrame end; - }; - - struct DecodedFrame { - AVFrame* frame; - unsigned idx; - }; - - std::vector>> _interval_map; - std::vector _frame_list; - EncodedFrameList _enc_frame_list; - DecoderContext _ctx; - int64_t _last_consumed_frame; - - int init_decoder(void) noexcept; - int init_bsf(void) noexcept; - void clear(void); - - int decode_interval(const KeyFrame& start, const KeyFrame& end, - const std::vector& frames); - int populate_intervals(const KeyFrameList& key_frames); - int populate_interval_map(const std::vector& frames); - int encode_frames(void); - - public: - KeyFrameDecoder(std::string filename); - ~KeyFrameDecoder() override; - - void set_key_frames(const KeyFrameList& key_frames); - EncodedFrameList& decode(const std::vector& frames); - }; -} +struct KeyFrame { + unsigned idx; + int64_t base; +}; + +typedef std::vector KeyFrameList; +typedef std::vector EncodedFrameList; + +class KeyFrameOp { +protected: + struct FormatContext { + AVFormatContext *fmt_context; + + // For now, we only process videos with a SINGLE video stream. + AVStream *video_stream; // Pointer to the video stream in the ctx + unsigned video_stream_idx; // Index to the video stream in the ctx + }; + + FormatContext _fctx; + std::string _filename; + + int64_t _time_base; + int64_t _nb_frames; + + int init_stream(void); + std::string error_msg(int errnum, const std::string &opt = ""); + +public: + KeyFrameOp(std::string filename); + virtual ~KeyFrameOp(); +}; + +/* *********************** */ +/* KEY_FRAME_PARSER */ +/* *********************** */ +class KeyFrameParser : public KeyFrameOp { +private: + KeyFrameList _frame_list; + + int fill_frame_list(void) noexcept; + +public: + KeyFrameParser(std::string filename) : KeyFrameOp(filename){}; + ~KeyFrameParser() override{}; + + const KeyFrameList &parse(void); +}; + +/* *********************** */ +/* KEY_FRAME_DECODER */ +/* *********************** */ +class KeyFrameDecoder : public KeyFrameOp { +private: + enum class H264Format { AVCC = 0, AnnexB = 1 }; + + struct DecoderContext { + AVBSFContext *bsf_context; + AVCodecContext *video_codec_context; + AVCodecContext *frame_codec_context; + SwsContext *sws_context; + H264Format byte_stream_format; + + DecoderContext() + : bsf_context(NULL), video_codec_context(NULL), + frame_codec_context(NULL), sws_context(NULL), + byte_stream_format(H264Format::AVCC){}; + }; + + struct FrameInterval { + KeyFrame start; + KeyFrame end; + }; + + struct DecodedFrame { + AVFrame *frame; + unsigned idx; + }; + + std::vector>> _interval_map; + std::vector _frame_list; + EncodedFrameList _enc_frame_list; + DecoderContext _ctx; + int64_t _last_consumed_frame; + + int init_decoder(void) noexcept; + int init_bsf(void) noexcept; + void clear(void); + + int decode_interval(const KeyFrame &start, const KeyFrame &end, + const std::vector &frames); + int populate_intervals(const KeyFrameList &key_frames); + int populate_interval_map(const std::vector &frames); + int encode_frames(void); + +public: + KeyFrameDecoder(std::string filename); + ~KeyFrameDecoder() override; + + void set_key_frames(const KeyFrameList &key_frames); + EncodedFrameList &decode(const std::vector &frames); +}; +} // namespace VCL diff --git a/include/vcl/RemoteConnection.h b/include/vcl/RemoteConnection.h new file mode 100644 index 00000000..642f3ef0 --- /dev/null +++ b/include/vcl/RemoteConnection.h @@ -0,0 +1,86 @@ +/** + * @file RemoteConnection.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file declares the C++ API for RemoteConnection, which allows users to + * connect to different file systems. At the moment, S3 is enabled. + */ + +#pragma once + +#include +#include + +#include "Exception.h" + +#include +#include +#include +#include +#include +#include + +namespace VCL { + +class RemoteConnection { +public: + RemoteConnection(); + ~RemoteConnection(); + + void Write(const std::string &path, std::vector data); + void Write(const std::string &filename); + std::vector Read(const std::string &path); + void RetrieveFile(const std::string &filename); + std::vector ListFilesInFolder(const std::string &folder_name); + void Read_Video(const std::string &path); + void Remove_Object(const std::string &path); + void start(); + void end(); + bool connected() { return _remote_connected; }; + + Aws::String _bucket_name; + +private: + bool _remote_connected = false; + + Aws::SDKOptions *_aws_sdk_options; + Aws::S3::S3Client *_aws_client; + + void ConfigureAws(); + // void SetLogLevelDebug(); + void ShutdownAws(); + void write_s3(const std::string &path, std::vector data); + void write_s3(const std::string &filename); + std::vector read_s3(const std::string &path); + void retrieve_file(const std::string &filename); + std::vector get_file_list(const std::string &path); + void read_s3_video(const std::string &file_path); + void remove_s3_object(const std::string &file_path); + // void LogEntry(std::string functionName); +}; +} // namespace VCL diff --git a/include/vcl/VCL.h b/include/vcl/VCL.h index b4bb0fa3..3d8780d5 100644 --- a/include/vcl/VCL.h +++ b/include/vcl/VCL.h @@ -31,7 +31,7 @@ #pragma once +#include "DescriptorSet.h" #include "Exception.h" #include "Image.h" #include "Video.h" -#include "DescriptorSet.h" diff --git a/include/vcl/Video.h b/include/vcl/Video.h index b97a746d..4544a264 100644 --- a/include/vcl/Video.h +++ b/include/vcl/Video.h @@ -36,645 +36,620 @@ #include #include -#include #include #include +#include -#include "vcl/Image.h" #include "KeyFrame.h" +#include "vcl/Image.h" #include "Exception.h" #include "utils.h" namespace VCL { - typedef cv::Rect Rectangle; // spcifiy an ROI inside a video - - class Video { - - public: - - enum Codec { NOCODEC = 0, - MJPG, - XVID, - H263, - H264, - AVC1 }; - - struct VideoSize { unsigned width; - unsigned height; - unsigned frame_count; }; - - enum Unit { FRAMES = 0, SECONDS = 1 }; - - enum OperationType { READ, WRITE, RESIZE, CROP, THRESHOLD, INTERVAL }; - - enum OperationResult { PASS, CONTINUE, BREAK }; - - /* *********************** */ - /* CONSTRUCTORS */ - /* *********************** */ - - /** - * Default constructor, creates an empty Video object. - * Used when reading from the file system - */ - Video(); - - /** - * Creates an Video object from the filename - * - * @param video_id A string indicating where the Video is on disk - */ - Video(const std::string &video_id); - - /** - * Creates an Video object from an existing Video object - * - * @param video A reference to an existing Video object - */ - Video(const Video &video); - - /** - * Creates an Video object from buffer - * - * A path must be specified for the video to be written in disk - * before reading the buffer. - * This is because OpenCV does not offer API for encoding/decoding - * from/to memory. - */ - Video(void* buffer, long size); - - /** - * Sets an Video object equal to another Video object - * - * @param video A copy of an existing Video object. The parameter - * is passed by value to exploit copy-and-swap idiom - * to reduce code duplication (copy-constructor) and - * safer exception handling - */ - Video& operator=(Video video); - - ~Video(); - - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ - - /** - * Gets the path set on the Video object - * - * @return The string containing the path to the Video object - */ - std::string get_video_id() const; - - /** - * Gets the codec used. - * - * @return Codec - */ - Codec get_codec() const; - - /** - * Gets the size of the Video in pixels (height * width * channels) - * - * @return The size of the Video in pixels - */ - VideoSize get_size(); - - /** - * Gets the dimensions (height and width) of the Video - * - * @return The height and width of the Video as an OpenCV Size object - */ - cv::Size get_frame_size(); - - /** - * Gets number of frames in the video - * - * @return Number of frames in the video - */ - long get_frame_count(); - - /** - * Gets frames per second. - * - * @return Frames per second - */ - float get_fps(); - - /** - * Gets one specific frame from the video - * - * If key frame information is stored for this video, both this - * function and key_frames() performs partial decoding on the video - * to exploit key frame information. - * - * @return cv::Mat with the specified frame - */ - cv::Mat get_frame(unsigned frame_num); - - /** - * Gets mutiple frames from the video - * - * @return cv::Mat with the specified frame - */ - std::vector get_frames(std::vector frame_list); - - /** - * Gets encoded Video data in a buffer - * Before calling this method, the store method must be called, - * as OpenCV only offers interfaces from encoding/decoding - * from/to files. - * - */ - std::vector get_encoded(); - - /** - * Invokes key-frame generation on the video, if the video is encoded - * with a H264 encoder. Index, and byte offset/length of each key - * frame is stored. This operation is independent of other prior - * visual operations that may have been applied. - * - * @return List of KeyFrame objects - */ - const KeyFrameList& get_key_frame_list(); - - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ - - /** - * Sets the file system location of where the Video - * can be found - * - * @param Video_id The full path to the Video location, including extension (container) - */ - void set_video_id(const std::string &video_id); - - /** - * Sets the codec used for writing the video to file. - * - * @param codec supported codec - */ - void set_codec(Codec codec); - - /** - * Sets the height and width of the Video - * - * @param dimensions The height and width of the Video - * @see OpenCV documentation for more details on Size - */ - void set_dimensions(const cv::Size& dimensions); - - /** - * Set key frame information associated with the underlying video - * stream. - * - * @param[in] key_frames list of key frames - */ - void set_key_frame_list(KeyFrameList& key_frames); - - /* *********************** */ - /* Video INTERACTIONS */ - /* *********************** */ +typedef cv::Rect Rectangle; // spcifiy an ROI inside a video + +class Video { + +public: + enum Codec { NOCODEC = 0, MJPG, XVID, H263, H264, AVC1 }; + + // enum class Storage { LOCAL = 0, AWS = 1 }; + + struct VideoSize { + unsigned width; + unsigned height; + unsigned frame_count; + }; + + enum Unit { FRAMES = 0, SECONDS = 1 }; + + enum OperationType { READ, WRITE, RESIZE, CROP, THRESHOLD, INTERVAL }; + + enum OperationResult { PASS, CONTINUE, BREAK }; + + RemoteConnection *_remote; // Remote connection (if one exists) + + /* *********************** */ + /* CONSTRUCTORS */ + /* *********************** */ + + /** + * Default constructor, creates an empty Video object. + * Used when reading from the file system + */ + Video(); + + /** + * Creates an Video object from the filename + * + * @param video_id A string indicating where the Video is on disk + */ + Video(const std::string &video_id); + + /** + * Creates an Video object from an existing Video object + * + * @param video A reference to an existing Video object + */ + Video(const Video &video); + + /** + * Creates an Video object from buffer + * + * A path must be specified for the video to be written in disk + * before reading the buffer. + * This is because OpenCV does not offer API for encoding/decoding + * from/to memory. + */ + Video(void *buffer, long size); + + /** + * Sets an Video object equal to another Video object + * + * @param video A copy of an existing Video object. The parameter + * is passed by value to exploit copy-and-swap idiom + * to reduce code duplication (copy-constructor) and + * safer exception handling + */ + Video &operator=(Video video); + + ~Video(); + + /* *********************** */ + /* GET FUNCTIONS */ + /* *********************** */ + + /** + * Gets the path set on the Video object + * + * @return The string containing the path to the Video object + */ + std::string get_video_id() const; + + /** + * Gets the codec used. + * + * @return Codec + */ + Codec get_codec() const; + + /** + * Gets the size of the Video in pixels (height * width * channels) + * + * @return The size of the Video in pixels + */ + VideoSize get_size(); + + /** + * Gets the dimensions (height and width) of the Video + * + * @return The height and width of the Video as an OpenCV Size object + */ + cv::Size get_frame_size(); + + /** + * Gets number of frames in the video + * + * @return Number of frames in the video + */ + long get_frame_count(); + + /** + * Gets frames per second. + * + * @return Frames per second + */ + float get_fps(); + + /** + * Gets one specific frame from the video + * + * If key frame information is stored for this video, both this + * function and key_frames() performs partial decoding on the video + * to exploit key frame information. + * + * @return cv::Mat with the specified frame + */ + cv::Mat get_frame(unsigned frame_num); + + /** + * Gets mutiple frames from the video + * + * @return cv::Mat with the specified frame + */ + std::vector get_frames(std::vector frame_list); + + /** + * Gets encoded Video data in a buffer + * Before calling this method, the store method must be called, + * as OpenCV only offers interfaces from encoding/decoding + * from/to files. + * + */ + std::vector get_encoded(); + + /** + * Invokes key-frame generation on the video, if the video is encoded + * with a H264 encoder. Index, and byte offset/length of each key + * frame is stored. This operation is independent of other prior + * visual operations that may have been applied. + * + * @return List of KeyFrame objects + */ + const KeyFrameList &get_key_frame_list(); + + /* *********************** */ + /* SET FUNCTIONS */ + /* *********************** */ + + /** + * Sets the file system location of where the Video + * can be found + * + * @param Video_id The full path to the Video location, including extension + * (container) + */ + void set_video_id(const std::string &video_id); + + /** + * Sets the codec used for writing the video to file. + * + * @param codec supported codec + */ + void set_codec(Codec codec); + + /** + * Sets the height and width of the Video + * + * @param dimensions The height and width of the Video + * @see OpenCV documentation for more details on Size + */ + void set_dimensions(const cv::Size &dimensions); + + /** + * Set key frame information associated with the underlying video + * stream. + * + * @param[in] key_frames list of key frames + */ + void set_key_frame_list(KeyFrameList &key_frames); + + /** + * Sets the RemoteConnection if AWS storage is being used + * + */ + void set_connection(RemoteConnection *remote); + + /* *********************** */ + /* Video INTERACTIONS */ + /* *********************** */ + + /** + * Resizes the Video to the given size. This operation is not + * performed until the data is needed (ie, store is called or + * one of the get_ functions such as get_cvmat) + * + * @param width Number of columns + * @param height Number of rows + */ + void resize(int width, int height); + + /** + * Crops the Video to the area specified. This operation is not + * performed until the data is needed (ie, store is called or + * one of the get_ functions such as get_cvmat) + * + * @param rect The region of interest (starting x coordinate, + * starting y coordinate, height, width) the video should be + * cropped to + */ + void crop(const Rectangle &rect); + + /** + * Performs a thresholding operation on the Video. Discards the pixel + * value if it is less than or equal to the threshold and sets that + * pixel to zero. This operation is not performed until the data + * is needed (ie, store is called or one of the get_ functions + * such as get_cvmat) + * + * @param value The threshold value + */ + void threshold(int value); + + /** + * Modifies the number of frames in the video. + * Frames 0 to start-1 are dropped. + * Frames stop to last are dropped. + * Step-1 frames are dropped in between. + * Note: Only FRAMES as united is supported. + * + * @param unit Unit used for specifying rest of params + * @param start New Starting frame + * @param stop New End frame + * @param step Decimation for frames + */ + void interval(Unit u, int start, int stop, int step = 1); + + /** + * Writes the Video to the system at the given location and in + * the given format + * + * @param video_id Full path to where the video should be written + * @param video_codec Codec in which to write the video + */ + void store(const std::string &video_id, Codec video_codec); + + /** + * Stores a Write Operation in the list of operations, performs the + * operations that are already in the list, and finally writes the + * video to the disk. + * This method will used when the video_id and codec are already defined. + */ + void store(); + + /** + * Deletes the Video file + */ + void delete_video(); + + /** + * Read a frame from the video file. + * To improve the performance, if we read multiple frames, we should + * read from the smallest index to the largest index. + * + * @param index The index of the frame within the video. + * @return The pointer to the frame if it succeeds and NULL if it fails + */ + VCL::Image *read_frame(int index); + +private: + class Operation; + class Read; + + // Forward declaration of VideoTest class, that is used for the unit + // test to accesss private methods of this class + friend class VideoTest; + + // Full path to the video file. + // It is called _video_id to keep it consistent with VCL::Image + std::string _video_id; + + bool _flag_stored; // Flag to avoid unnecessary read/write + + std::shared_ptr _video_read; + + VideoSize _size; + + float _fps; + + Codec _codec; // (h.264, etc). + + // Pointer to key frame decoder object, allocated when key frames + // are set, and used whenever frames are decoded using key-frame + // information + std::unique_ptr _key_frame_decoder; + + // List of key frames, filled only when KeyFrames operation is applied + KeyFrameList _key_frame_list; + + std::list> _operations; + + Storage _storage = Storage::LOCAL; + + /* *********************** */ + /* OPERATION */ + /* *********************** */ + + /** + * Provides a way to keep track of what operations should + * be performed on the data when it is needed + * + * Operation is the base class, it keeps track of the format + * of the Video data, defines a way to convert Format to + * a string, and defines a virtual function that overloads the + * () operator + */ + class Operation { + protected: + // Pointer to the video object to be handled + Video *_video; + + public: + Operation(Video *video) : _video(video) {} /** - * Resizes the Video to the given size. This operation is not - * performed until the data is needed (ie, store is called or - * one of the get_ functions such as get_cvmat) + * Implemented by the specific operation, performs what + * the operation is supposed to do + * This function should be executed for every frame * - * @param width Number of columns - * @param height Number of rows + * @param index The index of frame to be processed + * @return PASS the frame should be passed to the next operation object + * CONTINUE Abort the current frame operation + * BREAK Abort the whole video operation */ - void resize(int width, int height); + virtual OperationResult operator()(int index) = 0; + + virtual OperationType get_type() = 0; /** - * Crops the Video to the area specified. This operation is not - * performed until the data is needed (ie, store is called or - * one of the get_ functions such as get_cvmat) + * This function is called after the video operation, to tell the + * Operation object to release the resources and update video metadata. * - * @param rect The region of interest (starting x coordinate, - * starting y coordinate, height, width) the video should be - * cropped to */ - void crop(const Rectangle &rect); - + virtual void finalize() {} + }; + + /* *********************** */ + /* READ OPERATION */ + /* *********************** */ + + /** + * Extends Operation, reads Video from the file system + */ + class Read : public Operation, public std::enable_shared_from_this { + + // The currently opened video file + cv::VideoCapture _inputVideo; + // The cached frames + std::vector _frames; + // The range of cached frames + int _frame_index_starting, _frame_index_ending; + // The path of the currently opened video file + std::string _video_id; + + Video::Codec read_codec(char *fourcc); + + // Open the video file and initialize VideoCapture handler + void open(); + + // Reopen the VideoCapture handler, this happens if + // * the video file changes + // * we want to read the frames all over again + void reopen(); + + public: /** - * Performs a thresholding operation on the Video. Discards the pixel - * value if it is less than or equal to the threshold and sets that - * pixel to zero. This operation is not performed until the data - * is needed (ie, store is called or one of the get_ functions - * such as get_cvmat) + * Reads an Video from the file system (based on specified path) * - * @param value The threshold value */ - void threshold(int value); + Read(Video *video) + : Operation(video), _frame_index_starting(0), _frame_index_ending(0), + _video_id(video->_video_id){ + + }; + + OperationResult operator()(int index); + + void finalize(); + + OperationType get_type() { return READ; }; + + // Reset or close the VideoCapture handler + void reset(); /** - * Modifies the number of frames in the video. - * Frames 0 to start-1 are dropped. - * Frames stop to last are dropped. - * Step-1 frames are dropped in between. - * Note: Only FRAMES as united is supported. + * Read a frame from the video file. + * To improve the performance, if we read multiple frames, we should + * read from the smallest index to the largest index. * - * @param unit Unit used for specifying rest of params - * @param start New Starting frame - * @param stop New End frame - * @param step Decimation for frames + * @param index The index of the frame within the video. + * @return The pointer to the frame if it succeeds and NULL if it fails */ - void interval(Unit u, int start, int stop, int step = 1); + VCL::Image *read_frame(int index); + + ~Read(); + }; + + /* *********************** */ + /* WRITE OPERATION */ + /* *********************** */ + /** + * Extends Operation, writes to the file system in the specified + * format + */ + class Write : public Operation { + private: + cv::VideoWriter _outputVideo; + std::string _outname; + Video::Codec _codec; + int _frame_count; + int _last_write; + + int get_fourcc(); + + public: + Write(Video *video, std::string outname, Video::Codec codec) + : Operation(video), _outname(outname), _codec(codec), _frame_count(0), + _last_write(-1){}; /** - * Writes the Video to the system at the given location and in - * the given format + * Writes an Video to the file system. * - * @param video_id Full path to where the video should be written - * @param video_codec Codec in which to write the video */ - void store(const std::string &video_id, Codec video_codec); + OperationResult operator()(int index); + + OperationType get_type() { return WRITE; }; + + void finalize(); + + ~Write(); + }; + /* *********************** */ + /* RESIZE OPERATION */ + /* *********************** */ + /** + * Extends Operation, resizes the Video to the specified size + */ + class Resize : public Operation { + private: + /** Gives the height and width to resize the Video to */ + cv::Size _size; + + public: /** - * Stores a Write Operation in the list of operations, performs the - * operations that are already in the list, and finally writes the - * video to the disk. - * This method will used when the video_id and codec are already defined. + * Constructor, sets the size to resize to and the format + * + * @param size Struct that contains w and h */ - void store(); + Resize(Video *video, const cv::Size &size) + : Operation(video), _size(size){}; /** - * Deletes the Video file + * Resizes an Video to the given dimensions + * + * @param video A pointer to the current Video object */ - void delete_video(); + OperationResult operator()(int index); + + OperationType get_type() { return RESIZE; }; + }; + + /* *********************** */ + /* INTERVAL OPERATION */ + /* *********************** */ + class Interval : public Operation { + private: + int _start; + int _stop; + int _step; + Video::Unit _u; + bool _fps_updated; + + void update_fps(); + + public: /** - * Read a frame from the video file. - * To improve the performance, if we read multiple frames, we should - * read from the smallest index to the largest index. + * Constructor, sets the size to resize to and the format * - * @param index The index of the frame within the video. - * @return The pointer to the frame if it succeeds and NULL if it fails + * @param u Unit used for interval operation + * @param start First frame + * @param stop Last frame + * @param step Number of frames to be skipped in between. */ - VCL::Image* read_frame(int index); + Interval(Video *video, Video::Unit u, const int start, const int stop, + int step) + : Operation(video), _u(u), _start(start), _stop(stop), _step(step), + _fps_updated(false){}; - private: + /** + * Resizes an Video to the given dimensions + * + * @param video A pointer to the current Video object + */ + OperationResult operator()(int index); - class Operation; - class Read; + OperationType get_type() { return INTERVAL; }; + }; - // Forward declaration of VideoTest class, that is used for the unit - // test to accesss private methods of this class - friend class VideoTest; + /* *********************** */ + /* CROP OPERATION */ + /* *********************** */ - // Full path to the video file. - // It is called _video_id to keep it consistent with VCL::Image - std::string _video_id; + /** + * Extends Operation, crops the Video to the specified area + */ + class Crop : public Operation { + private: + /** Gives the dimensions and coordinates of the desired area */ + Rectangle _rect; - bool _flag_stored; // Flag to avoid unnecessary read/write + public: + /** + * Constructor, sets the area to crop to and the format + * + * @param rect Contains dimensions and coordinates of + * desired area + */ + Crop(Video *video, const Rectangle &rect) : Operation(video), _rect(rect){}; - std::shared_ptr _video_read; + /** + * Crops the Video to the given area + * + * @param video A pointer to the current Video object + */ + OperationResult operator()(int index); - VideoSize _size; - - float _fps; - - Codec _codec; // (h.264, etc). - - // Pointer to key frame decoder object, allocated when key frames - // are set, and used whenever frames are decoded using key-frame - // information - std::unique_ptr _key_frame_decoder; + OperationType get_type() { return CROP; }; + }; - // List of key frames, filled only when KeyFrames operation is applied - KeyFrameList _key_frame_list; + /* *********************** */ + /* THRESHOLD OPERATION */ + /* *********************** */ - std::list> _operations; + /** Extends Operation, performs a thresholding operation that + * discards the pixel value if it is less than or equal to the + * threshold and sets that pixel to 0 + */ + class Threshold : public Operation { + private: + /** Minimum value pixels should be */ + int _threshold; - /* *********************** */ - /* OPERATION */ - /* *********************** */ + public: + /** + * Constructor, sets the threshold value and format + * + * @param value Minimum value pixels should be + */ + Threshold(Video *video, const int value) + : Operation(video), _threshold(value){}; - /** - * Provides a way to keep track of what operations should - * be performed on the data when it is needed - * - * Operation is the base class, it keeps track of the format - * of the Video data, defines a way to convert Format to - * a string, and defines a virtual function that overloads the - * () operator - */ - class Operation { - protected: - // Pointer to the video object to be handled - Video* _video; - - public: - - Operation(Video* video): - _video(video) - { - - } - - /** - * Implemented by the specific operation, performs what - * the operation is supposed to do - * This function should be executed for every frame - * - * @param index The index of frame to be processed - * @return PASS the frame should be passed to the next operation object - * CONTINUE Abort the current frame operation - * BREAK Abort the whole video operation - */ - virtual OperationResult operator()(int index) = 0; - - virtual OperationType get_type() = 0; - - /** - * This function is called after the video operation, to tell the Operation - * object to release the resources and update video metadata. - * - */ - virtual void finalize() { } - }; - - /* *********************** */ - /* READ OPERATION */ - /* *********************** */ - - /** - * Extends Operation, reads Video from the file system - */ - class Read : public Operation, public std::enable_shared_from_this { - - // The currently opened video file - cv::VideoCapture _inputVideo; - // The cached frames - std::vector _frames; - // The range of cached frames - int _frame_index_starting, _frame_index_ending; - // The path of the currently opened video file - std::string _video_id; - - - Video::Codec read_codec(char* fourcc); - - // Open the video file and initialize VideoCapture handler - void open(); - - // Reopen the VideoCapture handler, this happens if - // * the video file changes - // * we want to read the frames all over again - void reopen(); - - public: - - /** - * Reads an Video from the file system (based on specified path) - * - */ - Read(Video* video) - : Operation(video), - _frame_index_starting(0), - _frame_index_ending(0), - _video_id(video->_video_id) - { - - }; - - OperationResult operator()(int index); - - void finalize(); - - OperationType get_type() { return READ; }; - - // Reset or close the VideoCapture handler - void reset(); - - /** - * Read a frame from the video file. - * To improve the performance, if we read multiple frames, we should - * read from the smallest index to the largest index. - * - * @param index The index of the frame within the video. - * @return The pointer to the frame if it succeeds and NULL if it fails - */ - VCL::Image* read_frame(int index); - - ~Read(); - }; - - /* *********************** */ - /* WRITE OPERATION */ - /* *********************** */ - /** - * Extends Operation, writes to the file system in the specified - * format - */ - class Write : public Operation { - private: - cv::VideoWriter _outputVideo; - std::string _outname; - Video::Codec _codec; - int _frame_count; - int _last_write; - - int get_fourcc(); - - public: - - Write(Video* video, std::string outname, Video::Codec codec) - : Operation(video), - _outname(outname), - _codec(codec), - _frame_count(0), - _last_write(-1) - { - }; - - /** - * Writes an Video to the file system. - * - */ - OperationResult operator()(int index); - - OperationType get_type() { return WRITE; }; - - void finalize(); - - ~Write(); - }; - - /* *********************** */ - /* RESIZE OPERATION */ - /* *********************** */ - /** - * Extends Operation, resizes the Video to the specified size - */ - class Resize : public Operation { - private: - /** Gives the height and width to resize the Video to */ - cv::Size _size; - - public: - /** - * Constructor, sets the size to resize to and the format - * - * @param size Struct that contains w and h - */ - Resize(Video* video, const cv::Size &size) - : Operation(video), - _size(size) - { - }; - - /** - * Resizes an Video to the given dimensions - * - * @param video A pointer to the current Video object - */ - OperationResult operator()(int index); - - OperationType get_type() { return RESIZE; }; - }; - - /* *********************** */ - /* INTERVAL OPERATION */ - /* *********************** */ - - class Interval : public Operation { - private: - int _start; - int _stop; - int _step; - Video::Unit _u; - bool _fps_updated; - - void update_fps(); - - public: - /** - * Constructor, sets the size to resize to and the format - * - * @param u Unit used for interval operation - * @param start First frame - * @param stop Last frame - * @param step Number of frames to be skipped in between. - */ - Interval(Video* video, Video::Unit u, const int start , const int stop, int step) - : Operation(video), - _u(u), - _start(start), - _stop(stop), - _step(step), - _fps_updated(false) - { - }; - - /** - * Resizes an Video to the given dimensions - * - * @param video A pointer to the current Video object - */ - OperationResult operator()(int index); - - OperationType get_type() { return INTERVAL; }; - - }; - - /* *********************** */ - /* CROP OPERATION */ - /* *********************** */ - - /** - * Extends Operation, crops the Video to the specified area - */ - class Crop : public Operation { - private: - /** Gives the dimensions and coordinates of the desired area */ - Rectangle _rect; - - public: - /** - * Constructor, sets the area to crop to and the format - * - * @param rect Contains dimensions and coordinates of - * desired area - */ - Crop(Video* video, const Rectangle &rect ) - : Operation(video), - _rect(rect) - { - }; - - /** - * Crops the Video to the given area - * - * @param video A pointer to the current Video object - */ - OperationResult operator()(int index); - - OperationType get_type() { return CROP; }; - }; - - /* *********************** */ - /* THRESHOLD OPERATION */ - /* *********************** */ - - /** Extends Operation, performs a thresholding operation that - * discards the pixel value if it is less than or equal to the - * threshold and sets that pixel to 0 - */ - class Threshold : public Operation { - private: - /** Minimum value pixels should be */ - int _threshold; - - public: - /** - * Constructor, sets the threshold value and format - * - * @param value Minimum value pixels should be - */ - Threshold(Video* video, const int value) - : Operation(video), - _threshold(value) - { - }; - - /** - * Performs the thresholding operation - * - * @param img A pointer to the current Video object - */ - OperationResult operator()(int index); - - OperationType get_type() { return THRESHOLD; }; - }; - - protected: - /* *********************** */ - /* UTILITIES */ - /* *********************** */ - /** - * Checks whether the video pointed by the current video_id has - * already been read. - * - * @return true if video was read, false otherwise - */ - // bool is_read(void); - - /** - * Performs the set of operations that have been requested - * on the Video - */ - void perform_operations(); - - /** - * Swaps members of two Video objects, to be used by assignment - * operator. - */ - void swap(Video& rhs) noexcept; + /** + * Performs the thresholding operation + * + * @param img A pointer to the current Video object + */ + OperationResult operator()(int index); + + OperationType get_type() { return THRESHOLD; }; + }; + +protected: + /* *********************** */ + /* UTILITIES */ + /* *********************** */ + /** + * Checks whether the video pointed by the current video_id has + * already been read. + * + * @return true if video was read, false otherwise + */ + // bool is_read(void); + + /** + * Performs the set of operations that have been requested + * on the Video + */ + void perform_operations(); + + /** + * Swaps members of two Video objects, to be used by assignment + * operator. + */ + void swap(Video &rhs) noexcept; }; - } // namespace VCL diff --git a/include/vcl/utils.h b/include/vcl/utils.h index eed5f284..f29ceee2 100644 --- a/include/vcl/utils.h +++ b/include/vcl/utils.h @@ -34,54 +34,58 @@ namespace VCL { - typedef std::vector cv_buffer; +typedef std::vector cv_buffer; - /* *********************** */ - /* ENUMS */ - /* *********************** */ - /** - * Determines what kind of compression to use - */ +/* *********************** */ +/* ENUMS */ +/* *********************** */ +/** + * Determines what kind of compression to use + */ - enum class CompressionType { - NOCOMPRESSION = 0, - GZIP = 1, - ZSTD = 2, - LZ4 = 3, - BLOSC = 4, - BLZ4 = 5, - BLZ4HC = 6, - BSNAPPY = 7, - BZLIB = 8, - BZSTD = 9, - RLE = 10 - }; +enum class CompressionType { + NOCOMPRESSION = 0, + GZIP = 1, + ZSTD = 2, + LZ4 = 3, + BLOSC = 4, + BLZ4 = 5, + BLZ4HC = 6, + BSNAPPY = 7, + BZLIB = 8, + BZSTD = 9, + RLE = 10 +}; - static const struct init_rand_t { init_rand_t() { srand(time(NULL)); } } init_rand; +enum class Storage { LOCAL = 0, AWS = 1 }; - uint64_t rdrand(); +static const struct init_rand_t { + init_rand_t() { srand(time(NULL)); } +} init_rand; - bool supports_rdrand(); +uint64_t rdrand(); - uint64_t get_uint64(); +bool supports_rdrand(); - /** - * Gets the extension of a filename - * - * @param filename The path to the file - * @return The string containing the extension - */ - std::string get_extension(const std::string &filename); +uint64_t get_uint64(); - /** - * Checks to see if the file name is unique by attempting - * to open the file - * - * @param name Full path to the theoretically unique ID - * @return True if the file does not exist, false if it does - */ - bool exists(const std::string &name); +/** + * Gets the extension of a filename + * + * @param filename The path to the file + * @return The string containing the extension + */ +std::string get_extension(const std::string &filename); - std::string create_unique(const std::string& path, - const std::string& extension); -}; +/** + * Checks to see if the file name is unique by attempting + * to open the file + * + * @param name Full path to the theoretically unique ID + * @return True if the file does not exist, false if it does + */ +bool exists(const std::string &name); + +std::string create_unique(const std::string &path, + const std::string &extension); +}; // namespace VCL diff --git a/remote_function/README.md b/remote_function/README.md new file mode 100644 index 00000000..9a4b7273 --- /dev/null +++ b/remote_function/README.md @@ -0,0 +1,146 @@ +# Remote Operations in VDMS +This submodule is required to execute VDMS operation on a remote server using Flask APIs (Support only available for images). Although shipped with VDMS, this submodule can be run independently and interacts with VDMS using http APIs. + +## Requirements +- Python 3 or higher +- Following python libraries + - flask + - cv2 + - numpy + - skvideo.io + - imutils + +## Operation Definition +Any operation can be added to the module by creating a python file of the same name as the operation and adding it to the `functions` folder. Any operaion file should follow the following setup to define a `run` function that the endpoint will use; +``` +def run(ipfilename, format, options): + + # ipfilename: Name of the input file to be read from + # format: Format of the input file + # options: Any inputs that the UDF will require from the client + + ### + Operation logic here + ### + + # Return OpenCV Matrix +``` + +## Setup +1. Copy the `remote_function` directory on the machine you want to run the remote server. Can be run on any location, independent of where VDMS is running. However, the location should be reachable from the machine that is running VDMS. You can also use `sparse-checkout` to only retrieve the `remote_function` directory from the VDMS repo. +2. Create the operation scripts as python scripts and place them in the `remote_function/functions` directory. +4. Follow the following steps to run the remote on port . + +``` +cd remote_function +python3 -m venv venv +source venv/bin/activate +python3 -m pip install pip --upgrade +python3 -m pip install wheel +python3 -m pip install -r requirements.txt +python3 udf_server.py +``` + +## Client Query + +The client query should contain the following three parameters: + ++ `type`: Should always be `remoteOp` for remote operation ++ `url`: URL for the API endpoint ++ `options`: Any parameter that is required by the operation. The following two parameters are important: + + `id`: A mandatory parameter. It specifies the operation to be executed and should be same as the file name used by the python script on the remote server. For instance, if the filename is `facedetect.py`, then the `id` should be `facedetect`. + + `format`: Optional, but specifies the format in which the image is required. Default is `jpg`. + +``` +"FindImage": { + "format": "png", + "constraints": { + "category": ["==", "faces"] + }, + "operations": [ + { + "type": "remoteOp", + "url": "http:///image", + "options": { + "id": "facedetect", + "format": "png" + } + } + ] +} +``` + +## Detailed Instructions for new remote operation +We now provide an example to add a new operation `cardetect` as a remote operation that would work with VDMS. The `cardetect` operation detects cars in an image and creates a rectangle around all cars. This operation requires a pretrained model available in the form of `xml` file online. + +1. Copy `remote_function` directory to your remote server machine. Say the address is `my.remote.server` and you copy the folder in the `home` directory. The folder structure you have now will look something like this; +``` +~/ +|__remote_function + |__functions + | |__files + | | |__haarcascade_frontalface_default.xml + | |__facedetect.py + |__README.md + |__requirements.txt + |__udf_server.py +``` +2. Download/Copy the `cars.xml` file to the `~/remote_function/functions/files`. +3. Create the `cardetect.py` file in `~/remote_function/functions`. +``` +import time +import cv2 +from PIL import Image +import numpy as np + +car_cascade_src = 'functions/files/cars.xml' + +def run(ipfilename, format, options): + + global car_cascade_src + + img = cv2.imread(ipfilename) + + # These lines + # represent the + # code logic + + return img +``` +4. The final directory structure would be as follows; +``` +~/ +|__remote_function + |__functions + | |__files + | | |__haarcascade_frontalface_default.xml + | | |__cars.xml + | |__facedetect.py + | |__cardetect.py + |__README.md + |__requirements.txt + |__udf_server.py +``` +5. Now start the remote server at port `5010` by running; +``` +python3 udf_server.py 5010 +``` +6. Say VDMS has a database of car images that have the property `category` set as `cars`. Then you can run the `cardetect` operation on these images using the following query; +``` +"FindImage": { + "format": "png", + "constraints": { + "category": ["==", "cars"] + }, + "operations": [ + { + "type": "remoteOp", + "url": "http://my.remote.server:5010/image", + "options": { + "id": "cardetect", + "format": "png" + } + } + ] +} +``` \ No newline at end of file diff --git a/remote_function/functions/facedetect.py b/remote_function/functions/facedetect.py new file mode 100644 index 00000000..c3dbce69 --- /dev/null +++ b/remote_function/functions/facedetect.py @@ -0,0 +1,20 @@ +import cv2 + +face_cascade = cv2.CascadeClassifier( + # This file is available from OpenCV 'data' directory at + # https://github.com/opencv/opencv/blob/4.x/data/haarcascades/haarcascade_frontalface_default.xml + "functions/files/haarcascade_frontalface_default.xml" +) + + +def run(ipfilename, format, options): + global face_cascade + + img = cv2.imread(ipfilename) + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + faces = face_cascade.detectMultiScale(gray, 1.1, 4) + + for x, y, w, h in faces: + cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) + + return img diff --git a/remote_function/functions/files/haarcascade_frontalface_default.xml b/remote_function/functions/files/haarcascade_frontalface_default.xml new file mode 100644 index 00000000..cbd1aa89 --- /dev/null +++ b/remote_function/functions/files/haarcascade_frontalface_default.xml @@ -0,0 +1,33314 @@ + + + +BOOST + HAAR + 24 + 24 + + 211 + + 0 + 25 + + <_> + 9 + -5.0425500869750977e+00 + + <_> + + 0 -1 0 -3.1511999666690826e-02 + + 2.0875380039215088e+00 -2.2172100543975830e+00 + <_> + + 0 -1 1 1.2396000325679779e-02 + + -1.8633940219879150e+00 1.3272049427032471e+00 + <_> + + 0 -1 2 2.1927999332547188e-02 + + -1.5105249881744385e+00 1.0625729560852051e+00 + <_> + + 0 -1 3 5.7529998011887074e-03 + + -8.7463897466659546e-01 1.1760339736938477e+00 + <_> + + 0 -1 4 1.5014000236988068e-02 + + -7.7945697307586670e-01 1.2608419656753540e+00 + <_> + + 0 -1 5 9.9371001124382019e-02 + + 5.5751299858093262e-01 -1.8743000030517578e+00 + <_> + + 0 -1 6 2.7340000960975885e-03 + + -1.6911929845809937e+00 4.4009700417518616e-01 + <_> + + 0 -1 7 -1.8859000876545906e-02 + + -1.4769539833068848e+00 4.4350099563598633e-01 + <_> + + 0 -1 8 5.9739998541772366e-03 + + -8.5909199714660645e-01 8.5255599021911621e-01 + <_> + 16 + -4.9842400550842285e+00 + + <_> + + 0 -1 9 -2.1110000088810921e-02 + + 1.2435649633407593e+00 -1.5713009834289551e+00 + <_> + + 0 -1 10 2.0355999469757080e-02 + + -1.6204780340194702e+00 1.1817760467529297e+00 + <_> + + 0 -1 11 2.1308999508619308e-02 + + -1.9415930509567261e+00 7.0069098472595215e-01 + <_> + + 0 -1 12 9.1660000383853912e-02 + + -5.5670100450515747e-01 1.7284419536590576e+00 + <_> + + 0 -1 13 3.6288000643253326e-02 + + 2.6763799786567688e-01 -2.1831810474395752e+00 + <_> + + 0 -1 14 -1.9109999760985374e-02 + + -2.6730210781097412e+00 4.5670801401138306e-01 + <_> + + 0 -1 15 8.2539999857544899e-03 + + -1.0852910280227661e+00 5.3564202785491943e-01 + <_> + + 0 -1 16 1.8355000764131546e-02 + + -3.5200199484825134e-01 9.3339198827743530e-01 + <_> + + 0 -1 17 -7.0569999516010284e-03 + + 9.2782098054885864e-01 -6.6349899768829346e-01 + <_> + + 0 -1 18 -9.8770000040531158e-03 + + 1.1577470302581787e+00 -2.9774799942970276e-01 + <_> + + 0 -1 19 1.5814000740647316e-02 + + -4.1960600018501282e-01 1.3576040267944336e+00 + <_> + + 0 -1 20 -2.0700000226497650e-02 + + 1.4590020179748535e+00 -1.9739399850368500e-01 + <_> + + 0 -1 21 -1.3760800659656525e-01 + + 1.1186759471893311e+00 -5.2915501594543457e-01 + <_> + + 0 -1 22 1.4318999834358692e-02 + + -3.5127198696136475e-01 1.1440860033035278e+00 + <_> + + 0 -1 23 1.0253000073134899e-02 + + -6.0850602388381958e-01 7.7098500728607178e-01 + <_> + + 0 -1 24 9.1508001089096069e-02 + + 3.8817799091339111e-01 -1.5122940540313721e+00 + <_> + 27 + -4.6551899909973145e+00 + + <_> + + 0 -1 25 6.9747000932693481e-02 + + -1.0130879878997803e+00 1.4687349796295166e+00 + <_> + + 0 -1 26 3.1502999365329742e-02 + + -1.6463639736175537e+00 1.0000629425048828e+00 + <_> + + 0 -1 27 1.4260999858379364e-02 + + 4.6480301022529602e-01 -1.5959889888763428e+00 + <_> + + 0 -1 28 1.4453000389039516e-02 + + -6.5511900186538696e-01 8.3021801710128784e-01 + <_> + + 0 -1 29 -3.0509999487549067e-03 + + -1.3982310295104980e+00 4.2550599575042725e-01 + <_> + + 0 -1 30 3.2722998410463333e-02 + + -5.0702601671218872e-01 1.0526109933853149e+00 + <_> + + 0 -1 31 -7.2960001416504383e-03 + + 3.6356899142265320e-01 -1.3464889526367188e+00 + <_> + + 0 -1 32 5.0425000488758087e-02 + + -3.0461400747299194e-01 1.4504129886627197e+00 + <_> + + 0 -1 33 4.6879000961780548e-02 + + -4.0286201238632202e-01 1.2145609855651855e+00 + <_> + + 0 -1 34 -6.9358997046947479e-02 + + 1.0539360046386719e+00 -4.5719701051712036e-01 + <_> + + 0 -1 35 -4.9033999443054199e-02 + + -1.6253089904785156e+00 1.5378999710083008e-01 + <_> + + 0 -1 36 8.4827996790409088e-02 + + 2.8402999043464661e-01 -1.5662059783935547e+00 + <_> + + 0 -1 37 -1.7229999648407102e-03 + + -1.0147459506988525e+00 2.3294800519943237e-01 + <_> + + 0 -1 38 1.1562199890613556e-01 + + -1.6732899844646454e-01 1.2804069519042969e+00 + <_> + + 0 -1 39 -5.1279999315738678e-02 + + 1.5162390470504761e+00 -3.0271100997924805e-01 + <_> + + 0 -1 40 -4.2706999927759171e-02 + + 1.7631920576095581e+00 -5.1832001656293869e-02 + <_> + + 0 -1 41 3.7178099155426025e-01 + + -3.1389200687408447e-01 1.5357979536056519e+00 + <_> + + 0 -1 42 1.9412999972701073e-02 + + -1.0017599910497665e-01 9.3655401468276978e-01 + <_> + + 0 -1 43 1.7439000308513641e-02 + + -4.0379899740219116e-01 9.6293002367019653e-01 + <_> + + 0 -1 44 3.9638999849557877e-02 + + 1.7039099335670471e-01 -2.9602990150451660e+00 + <_> + + 0 -1 45 -9.1469995677471161e-03 + + 8.8786798715591431e-01 -4.3818700313568115e-01 + <_> + + 0 -1 46 1.7219999572262168e-03 + + -3.7218600511550903e-01 4.0018901228904724e-01 + <_> + + 0 -1 47 3.0231000855565071e-02 + + 6.5924003720283508e-02 -2.6469180583953857e+00 + <_> + + 0 -1 48 -7.8795999288558960e-02 + + -1.7491459846496582e+00 2.8475299477577209e-01 + <_> + + 0 -1 49 2.1110000088810921e-03 + + -9.3908101320266724e-01 2.3205199837684631e-01 + <_> + + 0 -1 50 2.7091000229120255e-02 + + -5.2664000540971756e-02 1.0756820440292358e+00 + <_> + + 0 -1 51 -4.4964998960494995e-02 + + -1.8294479846954346e+00 9.9561996757984161e-02 + <_> + 32 + -4.4531588554382324e+00 + + <_> + + 0 -1 52 -6.5701000392436981e-02 + + 1.1558510065078735e+00 -1.0716359615325928e+00 + <_> + + 0 -1 53 1.5839999541640282e-02 + + -1.5634720325469971e+00 7.6877099275588989e-01 + <_> + + 0 -1 54 1.4570899307727814e-01 + + -5.7450097799301147e-01 1.3808720111846924e+00 + <_> + + 0 -1 55 6.1389999464154243e-03 + + -1.4570560455322266e+00 5.1610302925109863e-01 + <_> + + 0 -1 56 6.7179999314248562e-03 + + -8.3533602952957153e-01 5.8522200584411621e-01 + <_> + + 0 -1 57 1.8518000841140747e-02 + + -3.1312099099159241e-01 1.1696679592132568e+00 + <_> + + 0 -1 58 1.9958000630140305e-02 + + -4.3442600965499878e-01 9.5446902513504028e-01 + <_> + + 0 -1 59 -2.7755001187324524e-01 + + 1.4906179904937744e+00 -1.3815900683403015e-01 + <_> + + 0 -1 60 9.1859996318817139e-03 + + -9.6361500024795532e-01 2.7665498852729797e-01 + <_> + + 0 -1 61 -3.7737999111413956e-02 + + -2.4464108943939209e+00 2.3619599640369415e-01 + <_> + + 0 -1 62 1.8463000655174255e-02 + + 1.7539200186729431e-01 -1.3423130512237549e+00 + <_> + + 0 -1 63 -1.1114999651908875e-02 + + 4.8710799217224121e-01 -8.9851897954940796e-01 + <_> + + 0 -1 64 3.3927999436855316e-02 + + 1.7874200642108917e-01 -1.6342279911041260e+00 + <_> + + 0 -1 65 -3.5649001598358154e-02 + + -1.9607399702072144e+00 1.8102499842643738e-01 + <_> + + 0 -1 66 -1.1438000015914440e-02 + + 9.9010699987411499e-01 -3.8103199005126953e-01 + <_> + + 0 -1 67 -6.5236002206802368e-02 + + -2.5794160366058350e+00 2.4753600358963013e-01 + <_> + + 0 -1 68 -4.2272001504898071e-02 + + 1.4411840438842773e+00 -2.9508298635482788e-01 + <_> + + 0 -1 69 1.9219999667257071e-03 + + -4.9608600139617920e-01 6.3173598051071167e-01 + <_> + + 0 -1 70 -1.2921799719333649e-01 + + -2.3314270973205566e+00 5.4496999830007553e-02 + <_> + + 0 -1 71 2.2931000217795372e-02 + + -8.4447097778320312e-01 3.8738098740577698e-01 + <_> + + 0 -1 72 -3.4120000898838043e-02 + + -1.4431500434875488e+00 9.8422996699810028e-02 + <_> + + 0 -1 73 2.6223000138998032e-02 + + 1.8223099410533905e-01 -1.2586519718170166e+00 + <_> + + 0 -1 74 2.2236999124288559e-02 + + 6.9807998836040497e-02 -2.3820950984954834e+00 + <_> + + 0 -1 75 -5.8240001089870930e-03 + + 3.9332500100135803e-01 -2.7542799711227417e-01 + <_> + + 0 -1 76 4.3653000146150589e-02 + + 1.4832699298858643e-01 -1.1368780136108398e+00 + <_> + + 0 -1 77 5.7266999036073685e-02 + + 2.4628099799156189e-01 -1.2687400579452515e+00 + <_> + + 0 -1 78 2.3409998975694180e-03 + + -7.5448900461196899e-01 2.7163800597190857e-01 + <_> + + 0 -1 79 1.2996000237762928e-02 + + -3.6394900083541870e-01 7.0959198474884033e-01 + <_> + + 0 -1 80 -2.6517000049352646e-02 + + -2.3221859931945801e+00 3.5744000226259232e-02 + <_> + + 0 -1 81 -5.8400002308189869e-03 + + 4.2194300889968872e-01 -4.8184998333454132e-02 + <_> + + 0 -1 82 -1.6568999737501144e-02 + + 1.1099940538406372e+00 -3.4849700331687927e-01 + <_> + + 0 -1 83 -6.8157002329826355e-02 + + -3.3269989490509033e+00 2.1299000084400177e-01 + <_> + 52 + -4.3864588737487793e+00 + + <_> + + 0 -1 84 3.9974000304937363e-02 + + -1.2173449993133545e+00 1.0826710462570190e+00 + <_> + + 0 -1 85 1.8819500505924225e-01 + + -4.8289400339126587e-01 1.4045250415802002e+00 + <_> + + 0 -1 86 7.8027002513408661e-02 + + -1.0782150030136108e+00 7.4040299654006958e-01 + <_> + + 0 -1 87 1.1899999663000926e-04 + + -1.2019979953765869e+00 3.7749201059341431e-01 + <_> + + 0 -1 88 8.5056997835636139e-02 + + -4.3939098715782166e-01 1.2647340297698975e+00 + <_> + + 0 -1 89 8.9720003306865692e-03 + + -1.8440499901771545e-01 4.5726400613784790e-01 + <_> + + 0 -1 90 8.8120000436902046e-03 + + 3.0396699905395508e-01 -9.5991098880767822e-01 + <_> + + 0 -1 91 -2.3507999256253242e-02 + + 1.2487529516220093e+00 4.6227999031543732e-02 + <_> + + 0 -1 92 7.0039997808635235e-03 + + -5.9442102909088135e-01 5.3963297605514526e-01 + <_> + + 0 -1 93 3.3851999789476395e-02 + + 2.8496098518371582e-01 -1.4895249605178833e+00 + <_> + + 0 -1 94 -3.2530000898987055e-03 + + 4.8120799660682678e-01 -5.2712398767471313e-01 + <_> + + 0 -1 95 2.9097000136971474e-02 + + 2.6743900775909424e-01 -1.6007850170135498e+00 + <_> + + 0 -1 96 -8.4790000692009926e-03 + + -1.3107639551162720e+00 1.5243099629878998e-01 + <_> + + 0 -1 97 -1.0795000009238720e-02 + + 4.5613598823547363e-01 -7.2050899267196655e-01 + <_> + + 0 -1 98 -2.4620000272989273e-02 + + -1.7320619821548462e+00 6.8363003432750702e-02 + <_> + + 0 -1 99 3.7380000576376915e-03 + + -1.9303299486637115e-01 6.8243497610092163e-01 + <_> + + 0 -1 100 -1.2264000251889229e-02 + + -1.6095290184020996e+00 7.5268000364303589e-02 + <_> + + 0 -1 101 -4.8670000396668911e-03 + + 7.4286502599716187e-01 -2.1510200202465057e-01 + <_> + + 0 -1 102 7.6725997030735016e-02 + + -2.6835098862648010e-01 1.3094140291213989e+00 + <_> + + 0 -1 103 2.8578000143170357e-02 + + -5.8793000876903534e-02 1.2196329832077026e+00 + <_> + + 0 -1 104 1.9694000482559204e-02 + + -3.5142898559570312e-01 8.4926998615264893e-01 + <_> + + 0 -1 105 -2.9093999415636063e-02 + + -1.0507299900054932e+00 2.9806300997734070e-01 + <_> + + 0 -1 106 -2.9144000262022018e-02 + + 8.2547801733016968e-01 -3.2687199115753174e-01 + <_> + + 0 -1 107 1.9741000607609749e-02 + + 2.0452600717544556e-01 -8.3760201930999756e-01 + <_> + + 0 -1 108 4.3299999088048935e-03 + + 2.0577900111675262e-01 -6.6829800605773926e-01 + <_> + + 0 -1 109 -3.5500999540090561e-02 + + -1.2969900369644165e+00 1.3897499442100525e-01 + <_> + + 0 -1 110 -1.6172999516129494e-02 + + -1.3110569715499878e+00 7.5751997530460358e-02 + <_> + + 0 -1 111 -2.2151000797748566e-02 + + -1.0524389743804932e+00 1.9241100549697876e-01 + <_> + + 0 -1 112 -2.2707000374794006e-02 + + -1.3735309839248657e+00 6.6780999302864075e-02 + <_> + + 0 -1 113 1.6607999801635742e-02 + + -3.7135999649763107e-02 7.7846401929855347e-01 + <_> + + 0 -1 114 -1.3309000059962273e-02 + + -9.9850702285766602e-01 1.2248100340366364e-01 + <_> + + 0 -1 115 -3.3732000738382339e-02 + + 1.4461359977722168e+00 1.3151999562978745e-02 + <_> + + 0 -1 116 1.6935000196099281e-02 + + -3.7121298909187317e-01 5.2842199802398682e-01 + <_> + + 0 -1 117 3.3259999472647905e-03 + + -5.7568502426147461e-01 3.9261901378631592e-01 + <_> + + 0 -1 118 8.3644002676010132e-02 + + 1.6116000711917877e-02 -2.1173279285430908e+00 + <_> + + 0 -1 119 2.5785198807716370e-01 + + -8.1609003245830536e-02 9.8782497644424438e-01 + <_> + + 0 -1 120 -3.6566998809576035e-02 + + -1.1512110233306885e+00 9.6459001302719116e-02 + <_> + + 0 -1 121 -1.6445999965071678e-02 + + 3.7315499782562256e-01 -1.4585399627685547e-01 + <_> + + 0 -1 122 -3.7519999314099550e-03 + + 2.6179298758506775e-01 -5.8156698942184448e-01 + <_> + + 0 -1 123 -6.3660000450909138e-03 + + 7.5477397441864014e-01 -1.7055200040340424e-01 + <_> + + 0 -1 124 -3.8499999791383743e-03 + + 2.2653999924659729e-01 -6.3876402378082275e-01 + <_> + + 0 -1 125 -4.5494001358747482e-02 + + -1.2640299797058105e+00 2.5260698795318604e-01 + <_> + + 0 -1 126 -2.3941000923514366e-02 + + 8.7068402767181396e-01 -2.7104699611663818e-01 + <_> + + 0 -1 127 -7.7558003365993500e-02 + + -1.3901610374450684e+00 2.3612299561500549e-01 + <_> + + 0 -1 128 2.3614000529050827e-02 + + 6.6140003502368927e-02 -1.2645419836044312e+00 + <_> + + 0 -1 129 -2.5750000495463610e-03 + + -5.3841698169708252e-01 3.0379098653793335e-01 + <_> + + 0 -1 130 1.2010800093412399e-01 + + -3.5343000292778015e-01 5.2866202592849731e-01 + <_> + + 0 -1 131 2.2899999748915434e-03 + + -5.8701997995376587e-01 2.4061000347137451e-01 + <_> + + 0 -1 132 6.9716997444629669e-02 + + -3.3348900079727173e-01 5.1916301250457764e-01 + <_> + + 0 -1 133 -4.6670001000165939e-02 + + 6.9795399904251099e-01 -1.4895999804139137e-02 + <_> + + 0 -1 134 -5.0129000097513199e-02 + + 8.6146199703216553e-01 -2.5986000895500183e-01 + <_> + + 0 -1 135 3.0147999525070190e-02 + + 1.9332799315452576e-01 -5.9131097793579102e-01 + <_> + 53 + -4.1299300193786621e+00 + + <_> + + 0 -1 136 9.1085001826286316e-02 + + -8.9233100414276123e-01 1.0434230566024780e+00 + <_> + + 0 -1 137 1.2818999588489532e-02 + + -1.2597670555114746e+00 5.5317097902297974e-01 + <_> + + 0 -1 138 1.5931999310851097e-02 + + -8.6254400014877319e-01 6.3731801509857178e-01 + <_> + + 0 -1 139 2.2780001163482666e-03 + + -7.4639201164245605e-01 5.3155601024627686e-01 + <_> + + 0 -1 140 3.1840998679399490e-02 + + -1.2650489807128906e+00 3.6153900623321533e-01 + <_> + + 0 -1 141 2.6960000395774841e-03 + + -9.8290401697158813e-01 3.6013001203536987e-01 + <_> + + 0 -1 142 -1.2055000290274620e-02 + + 6.4068400859832764e-01 -5.0125002861022949e-01 + <_> + + 0 -1 143 2.1324999630451202e-02 + + -2.4034999310970306e-01 8.5448002815246582e-01 + <_> + + 0 -1 144 3.0486000701785088e-02 + + -3.4273600578308105e-01 1.1428849697113037e+00 + <_> + + 0 -1 145 -4.5079998672008514e-02 + + 1.0976949930191040e+00 -1.7974600195884705e-01 + <_> + + 0 -1 146 -7.1700997650623322e-02 + + 1.5735000371932983e+00 -3.1433498859405518e-01 + <_> + + 0 -1 147 5.9218000620603561e-02 + + -2.7582401037216187e-01 1.0448570251464844e+00 + <_> + + 0 -1 148 6.7010000348091125e-03 + + -1.0974019765853882e+00 1.9801199436187744e-01 + <_> + + 0 -1 149 4.1046999394893646e-02 + + 3.0547699332237244e-01 -1.3287999629974365e+00 + <_> + + 0 -1 150 -8.5499999113380909e-04 + + 2.5807100534439087e-01 -7.0052897930145264e-01 + <_> + + 0 -1 151 -3.0360000208020210e-02 + + -1.2306419610977173e+00 2.2609399259090424e-01 + <_> + + 0 -1 152 -1.2930000200867653e-02 + + 4.0758600831031799e-01 -5.1234501600265503e-01 + <_> + + 0 -1 153 3.7367999553680420e-02 + + -9.4755001366138458e-02 6.1765098571777344e-01 + <_> + + 0 -1 154 2.4434000253677368e-02 + + -4.1100600361824036e-01 4.7630500793457031e-01 + <_> + + 0 -1 155 5.7007998228073120e-02 + + 2.5249299407005310e-01 -6.8669801950454712e-01 + <_> + + 0 -1 156 -1.6313999891281128e-02 + + -9.3928402662277222e-01 1.1448100209236145e-01 + <_> + + 0 -1 157 -1.7648899555206299e-01 + + 1.2451089620590210e+00 -5.6519001722335815e-02 + <_> + + 0 -1 158 1.7614600062370300e-01 + + -3.2528200745582581e-01 8.2791501283645630e-01 + <_> + + 0 -1 159 -7.3910001665353775e-03 + + 3.4783700108528137e-01 -1.7929099500179291e-01 + <_> + + 0 -1 160 6.0890998691320419e-02 + + 5.5098000913858414e-02 -1.5480779409408569e+00 + <_> + + 0 -1 161 -2.9123000800609589e-02 + + -1.0255639553070068e+00 2.4106900393962860e-01 + <_> + + 0 -1 162 -4.5648999512195587e-02 + + 1.0301599502563477e+00 -3.1672099232673645e-01 + <_> + + 0 -1 163 3.7333000451326370e-02 + + 2.1620599925518036e-01 -8.2589900493621826e-01 + <_> + + 0 -1 164 -2.4411000311374664e-02 + + -1.5957959890365601e+00 5.1139000803232193e-02 + <_> + + 0 -1 165 -5.9806998819112778e-02 + + -1.0312290191650391e+00 1.3092300295829773e-01 + <_> + + 0 -1 166 -3.0106000602245331e-02 + + -1.4781630039215088e+00 3.7211999297142029e-02 + <_> + + 0 -1 167 7.4209999293088913e-03 + + -2.4024100601673126e-01 4.9333998560905457e-01 + <_> + + 0 -1 168 -2.1909999195486307e-03 + + 2.8941500186920166e-01 -5.7259601354598999e-01 + <_> + + 0 -1 169 2.0860999822616577e-02 + + -2.3148399591445923e-01 6.3765901327133179e-01 + <_> + + 0 -1 170 -6.6990000195801258e-03 + + -1.2107750177383423e+00 6.4018003642559052e-02 + <_> + + 0 -1 171 1.8758000805974007e-02 + + 2.4461300671100616e-01 -9.9786698818206787e-01 + <_> + + 0 -1 172 -4.4323001056909561e-02 + + -1.3699189424514771e+00 3.6051999777555466e-02 + <_> + + 0 -1 173 2.2859999909996986e-02 + + 2.1288399398326874e-01 -1.0397620201110840e+00 + <_> + + 0 -1 174 -9.8600005730986595e-04 + + 3.2443600893020630e-01 -5.4291802644729614e-01 + <_> + + 0 -1 175 1.7239000648260117e-02 + + -2.8323900699615479e-01 4.4468200206756592e-01 + <_> + + 0 -1 176 -3.4531001001596451e-02 + + -2.3107020854949951e+00 -3.1399999279528856e-03 + <_> + + 0 -1 177 6.7006997764110565e-02 + + 2.8715699911117554e-01 -6.4481002092361450e-01 + <_> + + 0 -1 178 2.3776899278163910e-01 + + -2.7174800634384155e-01 8.0219101905822754e-01 + <_> + + 0 -1 179 -1.2903000228106976e-02 + + -1.5317620038986206e+00 2.1423600614070892e-01 + <_> + + 0 -1 180 1.0514999739825726e-02 + + 7.7037997543811798e-02 -1.0581140518188477e+00 + <_> + + 0 -1 181 1.6969000920653343e-02 + + 1.4306700229644775e-01 -8.5828399658203125e-01 + <_> + + 0 -1 182 -7.2460002265870571e-03 + + -1.1020129919052124e+00 6.4906999468803406e-02 + <_> + + 0 -1 183 1.0556999593973160e-02 + + 1.3964000158011913e-02 6.3601499795913696e-01 + <_> + + 0 -1 184 6.1380001716315746e-03 + + -3.4545901417732239e-01 5.6296801567077637e-01 + <_> + + 0 -1 185 1.3158000074326992e-02 + + 1.9927300512790680e-01 -1.5040320158004761e+00 + <_> + + 0 -1 186 3.1310000922530890e-03 + + -4.0903699398040771e-01 3.7796398997306824e-01 + <_> + + 0 -1 187 -1.0920699685811996e-01 + + -2.2227079868316650e+00 1.2178199738264084e-01 + <_> + + 0 -1 188 8.1820003688335419e-03 + + -2.8652000427246094e-01 6.7890799045562744e-01 + <_> + 62 + -4.0218091011047363e+00 + + <_> + + 0 -1 189 3.1346999108791351e-02 + + -8.8884598016738892e-01 9.4936800003051758e-01 + <_> + + 0 -1 190 3.1918000429868698e-02 + + -1.1146880388259888e+00 4.8888999223709106e-01 + <_> + + 0 -1 191 6.5939999185502529e-03 + + -1.0097689628601074e+00 4.9723801016807556e-01 + <_> + + 0 -1 192 2.6148000732064247e-02 + + 2.5991299748420715e-01 -1.2537480592727661e+00 + <_> + + 0 -1 193 1.2845000252127647e-02 + + -5.7138597965240479e-01 5.9659498929977417e-01 + <_> + + 0 -1 194 2.6344999670982361e-02 + + -5.5203199386596680e-01 3.0217400193214417e-01 + <_> + + 0 -1 195 -1.5083000063896179e-02 + + -1.2871240377426147e+00 2.2354200482368469e-01 + <_> + + 0 -1 196 -3.8887001574039459e-02 + + 1.7425049543380737e+00 -9.9747002124786377e-02 + <_> + + 0 -1 197 -5.7029998861253262e-03 + + -1.0523240566253662e+00 1.8362599611282349e-01 + <_> + + 0 -1 198 -1.4860000228509307e-03 + + 5.6784200668334961e-01 -4.6742001175880432e-01 + <_> + + 0 -1 199 -2.8486000373959541e-02 + + 1.3082909584045410e+00 -2.6460900902748108e-01 + <_> + + 0 -1 200 6.6224999725818634e-02 + + -4.6210700273513794e-01 4.1749599575996399e-01 + <_> + + 0 -1 201 8.8569996878504753e-03 + + -4.1474899649620056e-01 5.9204798936843872e-01 + <_> + + 0 -1 202 1.1355999857187271e-02 + + 3.6103099584579468e-01 -4.5781201124191284e-01 + <_> + + 0 -1 203 -2.7679998893290758e-03 + + -8.9238899946212769e-01 1.4199000597000122e-01 + <_> + + 0 -1 204 1.1246999725699425e-02 + + 2.9353401064872742e-01 -9.7330600023269653e-01 + <_> + + 0 -1 205 7.1970000863075256e-03 + + -7.9334902763366699e-01 1.8313400447368622e-01 + <_> + + 0 -1 206 3.1768999993801117e-02 + + 1.5523099899291992e-01 -1.3245639801025391e+00 + <_> + + 0 -1 207 2.5173999369144440e-02 + + 3.4214999526739120e-02 -2.0948131084442139e+00 + <_> + + 0 -1 208 7.5360001064836979e-03 + + -3.9450600743293762e-01 5.1333999633789062e-01 + <_> + + 0 -1 209 3.2873000949621201e-02 + + 8.8372997939586639e-02 -1.2814120054244995e+00 + <_> + + 0 -1 210 -2.7379998937249184e-03 + + 5.5286502838134766e-01 -4.6384999155998230e-01 + <_> + + 0 -1 211 -3.8075000047683716e-02 + + -1.8497270345687866e+00 4.5944001525640488e-02 + <_> + + 0 -1 212 -3.8984000682830811e-02 + + -4.8223701119422913e-01 3.4760600328445435e-01 + <_> + + 0 -1 213 2.8029999230057001e-03 + + -4.5154699683189392e-01 4.2806300520896912e-01 + <_> + + 0 -1 214 -5.4145999252796173e-02 + + -8.4520798921585083e-01 1.6674900054931641e-01 + <_> + + 0 -1 215 -8.3280000835657120e-03 + + 3.5348299145698547e-01 -4.7163200378417969e-01 + <_> + + 0 -1 216 3.3778000622987747e-02 + + 1.8463100492954254e-01 -1.6686669588088989e+00 + <_> + + 0 -1 217 -1.1238099634647369e-01 + + -1.2521569728851318e+00 3.5992000252008438e-02 + <_> + + 0 -1 218 -1.0408000089228153e-02 + + -8.1620401144027710e-01 2.3428599536418915e-01 + <_> + + 0 -1 219 -4.9439999274909496e-03 + + -9.2584699392318726e-01 1.0034800320863724e-01 + <_> + + 0 -1 220 -9.3029998242855072e-03 + + 5.6499302387237549e-01 -1.8881900608539581e-01 + <_> + + 0 -1 221 -1.1749999597668648e-02 + + 8.0302399396896362e-01 -3.8277000188827515e-01 + <_> + + 0 -1 222 -2.3217000067234039e-02 + + -8.4926998615264893e-01 1.9671200215816498e-01 + <_> + + 0 -1 223 1.6866000369191170e-02 + + -4.0591898560523987e-01 5.0695300102233887e-01 + <_> + + 0 -1 224 -2.4031000211834908e-02 + + -1.5297520160675049e+00 2.3344999551773071e-01 + <_> + + 0 -1 225 -3.6945998668670654e-02 + + 6.3007700443267822e-01 -3.1780400872230530e-01 + <_> + + 0 -1 226 -6.1563998460769653e-02 + + 5.8627897500991821e-01 -1.2107999995350838e-02 + <_> + + 0 -1 227 2.1661000326275826e-02 + + -2.5623700022697449e-01 1.0409849882125854e+00 + <_> + + 0 -1 228 -3.6710000131279230e-03 + + 2.9171100258827209e-01 -8.3287298679351807e-01 + <_> + + 0 -1 229 4.4849000871181488e-02 + + -3.9633199572563171e-01 4.5662000775337219e-01 + <_> + + 0 -1 230 5.7195000350475311e-02 + + 2.1023899316787720e-01 -1.5004800558090210e+00 + <_> + + 0 -1 231 -1.1342000216245651e-02 + + 4.4071298837661743e-01 -3.8653799891471863e-01 + <_> + + 0 -1 232 -1.2004000134766102e-02 + + 9.3954598903656006e-01 -1.0589499771595001e-01 + <_> + + 0 -1 233 2.2515999153256416e-02 + + 9.4480002298951149e-03 -1.6799509525299072e+00 + <_> + + 0 -1 234 -1.9809000194072723e-02 + + -1.0133639574050903e+00 2.4146600067615509e-01 + <_> + + 0 -1 235 1.5891000628471375e-02 + + -3.7507599592208862e-01 4.6614098548889160e-01 + <_> + + 0 -1 236 -9.1420002281665802e-03 + + -8.0484098196029663e-01 1.7816999554634094e-01 + <_> + + 0 -1 237 -4.4740000739693642e-03 + + -1.0562069416046143e+00 7.3305003345012665e-02 + <_> + + 0 -1 238 1.2742500007152557e-01 + + 2.0165599882602692e-01 -1.5467929840087891e+00 + <_> + + 0 -1 239 4.7703001648187637e-02 + + -3.7937799096107483e-01 3.7885999679565430e-01 + <_> + + 0 -1 240 5.3608000278472900e-02 + + 2.1220499277114868e-01 -1.2399710416793823e+00 + <_> + + 0 -1 241 -3.9680998772382736e-02 + + -1.0257550477981567e+00 5.1282998174428940e-02 + <_> + + 0 -1 242 -6.7327000200748444e-02 + + -1.0304750204086304e+00 2.3005299270153046e-01 + <_> + + 0 -1 243 1.3337600231170654e-01 + + -2.0869000256061554e-01 1.2272510528564453e+00 + <_> + + 0 -1 244 -2.0919300615787506e-01 + + 8.7929898500442505e-01 -4.4254999607801437e-02 + <_> + + 0 -1 245 -6.5589003264904022e-02 + + 1.0443429946899414e+00 -2.1682099997997284e-01 + <_> + + 0 -1 246 6.1882998794317245e-02 + + 1.3798199594020844e-01 -1.9009059667587280e+00 + <_> + + 0 -1 247 -2.5578999891877174e-02 + + -1.6607600450515747e+00 5.8439997956156731e-03 + <_> + + 0 -1 248 -3.4827001392841339e-02 + + 7.9940402507781982e-01 -8.2406997680664062e-02 + <_> + + 0 -1 249 -1.8209999427199364e-02 + + -9.6073997020721436e-01 6.6320002079010010e-02 + <_> + + 0 -1 250 1.5070999972522259e-02 + + 1.9899399578571320e-01 -7.6433002948760986e-01 + <_> + 72 + -3.8832089900970459e+00 + + <_> + + 0 -1 251 4.6324998140335083e-02 + + -1.0362670421600342e+00 8.2201498746871948e-01 + <_> + + 0 -1 252 1.5406999737024307e-02 + + -1.2327589988708496e+00 2.9647698998451233e-01 + <_> + + 0 -1 253 1.2808999978005886e-02 + + -7.5852298736572266e-01 5.7985502481460571e-01 + <_> + + 0 -1 254 4.9150999635457993e-02 + + -3.8983899354934692e-01 8.9680302143096924e-01 + <_> + + 0 -1 255 1.2621000409126282e-02 + + -7.1799302101135254e-01 5.0440901517868042e-01 + <_> + + 0 -1 256 -1.8768999725580215e-02 + + 5.5147600173950195e-01 -7.0555400848388672e-01 + <_> + + 0 -1 257 4.1965000331401825e-02 + + -4.4782099127769470e-01 7.0985502004623413e-01 + <_> + + 0 -1 258 -5.1401998847723007e-02 + + -1.0932120084762573e+00 2.6701900362968445e-01 + <_> + + 0 -1 259 -7.0960998535156250e-02 + + 8.3618402481079102e-01 -3.8318100571632385e-01 + <_> + + 0 -1 260 1.6745999455451965e-02 + + -2.5733101367950439e-01 2.5966501235961914e-01 + <_> + + 0 -1 261 -6.2400000169873238e-03 + + 3.1631499528884888e-01 -5.8796900510787964e-01 + <_> + + 0 -1 262 -3.9397999644279480e-02 + + -1.0491210222244263e+00 1.6822400689125061e-01 + <_> + + 0 -1 263 0. + + 1.6144199669361115e-01 -8.7876898050308228e-01 + <_> + + 0 -1 264 -2.2307999432086945e-02 + + -6.9053500890731812e-01 2.3607000708580017e-01 + <_> + + 0 -1 265 1.8919999711215496e-03 + + 2.4989199638366699e-01 -5.6583297252655029e-01 + <_> + + 0 -1 266 1.0730000212788582e-03 + + -5.0415802001953125e-01 3.8374501466751099e-01 + <_> + + 0 -1 267 3.9230998605489731e-02 + + 4.2619001120328903e-02 -1.3875889778137207e+00 + <_> + + 0 -1 268 6.2238000333309174e-02 + + 1.4119400084018707e-01 -1.0688860416412354e+00 + <_> + + 0 -1 269 2.1399999968707561e-03 + + -8.9622402191162109e-01 1.9796399772167206e-01 + <_> + + 0 -1 270 9.1800000518560410e-04 + + -4.5337298512458801e-01 4.3532699346542358e-01 + <_> + + 0 -1 271 -6.9169998168945312e-03 + + 3.3822798728942871e-01 -4.4793000817298889e-01 + <_> + + 0 -1 272 -2.3866999894380569e-02 + + -7.8908598423004150e-01 2.2511799633502960e-01 + <_> + + 0 -1 273 -1.0262800008058548e-01 + + -2.2831439971923828e+00 -5.3960001096129417e-03 + <_> + + 0 -1 274 -9.5239998772740364e-03 + + 3.9346700906753540e-01 -5.2242201566696167e-01 + <_> + + 0 -1 275 3.9877001196146011e-02 + + 3.2799001783132553e-02 -1.5079489946365356e+00 + <_> + + 0 -1 276 -1.3144999742507935e-02 + + -1.0839990377426147e+00 1.8482400476932526e-01 + <_> + + 0 -1 277 -5.0590999424457550e-02 + + -1.8822289705276489e+00 -2.2199999075382948e-03 + <_> + + 0 -1 278 2.4917000904679298e-02 + + 1.4593400061130524e-01 -2.2196519374847412e+00 + <_> + + 0 -1 279 -7.6370001770555973e-03 + + -1.0164569616317749e+00 5.8797001838684082e-02 + <_> + + 0 -1 280 4.2911998927593231e-02 + + 1.5443000197410583e-01 -1.1843889951705933e+00 + <_> + + 0 -1 281 2.3000000510364771e-04 + + -7.7305799722671509e-01 1.2189900130033493e-01 + <_> + + 0 -1 282 9.0929996222257614e-03 + + -1.1450099945068359e-01 7.1091300249099731e-01 + <_> + + 0 -1 283 1.1145000346004963e-02 + + 7.0000998675823212e-02 -1.0534820556640625e+00 + <_> + + 0 -1 284 -5.2453000098466873e-02 + + -1.7594360113143921e+00 1.9523799419403076e-01 + <_> + + 0 -1 285 -2.3020699620246887e-01 + + 9.5840299129486084e-01 -2.5045698881149292e-01 + <_> + + 0 -1 286 -1.6365999355912209e-02 + + 4.6731901168823242e-01 -2.1108399331569672e-01 + <_> + + 0 -1 287 -1.7208000645041466e-02 + + 7.0835697650909424e-01 -2.8018298745155334e-01 + <_> + + 0 -1 288 -3.6648001521825790e-02 + + -1.1013339757919312e+00 2.4341100454330444e-01 + <_> + + 0 -1 289 -1.0304999537765980e-02 + + -1.0933129787445068e+00 5.6258998811244965e-02 + <_> + + 0 -1 290 -1.3713000342249870e-02 + + -2.6438099145889282e-01 1.9821000099182129e-01 + <_> + + 0 -1 291 2.9308000579476357e-02 + + -2.2142399847507477e-01 1.0525950193405151e+00 + <_> + + 0 -1 292 2.4077000096440315e-02 + + 1.8485699594020844e-01 -1.7203969955444336e+00 + <_> + + 0 -1 293 6.1280000954866409e-03 + + -9.2721498012542725e-01 5.8752998709678650e-02 + <_> + + 0 -1 294 -2.2377999499440193e-02 + + 1.9646559953689575e+00 2.7785999700427055e-02 + <_> + + 0 -1 295 -7.0440000854432583e-03 + + 2.1427600085735321e-01 -4.8407599329948425e-01 + <_> + + 0 -1 296 -4.0603000670671463e-02 + + -1.1754349470138550e+00 1.6061200201511383e-01 + <_> + + 0 -1 297 -2.4466000497341156e-02 + + -1.1239900588989258e+00 4.1110001504421234e-02 + <_> + + 0 -1 298 2.5309999473392963e-03 + + -1.7169700562953949e-01 3.2178801298141479e-01 + <_> + + 0 -1 299 -1.9588999450206757e-02 + + 8.2720202207565308e-01 -2.6376700401306152e-01 + <_> + + 0 -1 300 -2.9635999351739883e-02 + + -1.1524770259857178e+00 1.4999300241470337e-01 + <_> + + 0 -1 301 -1.5030000358819962e-02 + + -1.0491830110549927e+00 4.0160998702049255e-02 + <_> + + 0 -1 302 -6.0715001076459885e-02 + + -1.0903840065002441e+00 1.5330800414085388e-01 + <_> + + 0 -1 303 -1.2790000066161156e-02 + + 4.2248600721359253e-01 -4.2399200797080994e-01 + <_> + + 0 -1 304 -2.0247999578714371e-02 + + -9.1866999864578247e-01 1.8485699594020844e-01 + <_> + + 0 -1 305 -3.0683999881148338e-02 + + -1.5958670377731323e+00 2.5760000571608543e-03 + <_> + + 0 -1 306 -2.0718000829219818e-02 + + -6.6299998760223389e-01 3.1037199497222900e-01 + <_> + + 0 -1 307 -1.7290000105276704e-03 + + 1.9183400273323059e-01 -6.5084999799728394e-01 + <_> + + 0 -1 308 -3.1394001096487045e-02 + + -6.3643002510070801e-01 1.5408399701118469e-01 + <_> + + 0 -1 309 1.9003000110387802e-02 + + -1.8919399380683899e-01 1.5294510126113892e+00 + <_> + + 0 -1 310 6.1769997701048851e-03 + + -1.0597900301218033e-01 6.4859598875045776e-01 + <_> + + 0 -1 311 -1.0165999643504620e-02 + + -1.0802700519561768e+00 3.7176001816987991e-02 + <_> + + 0 -1 312 -1.4169999631121755e-03 + + 3.4157499670982361e-01 -9.7737997770309448e-02 + <_> + + 0 -1 313 -4.0799998678267002e-03 + + 4.7624599933624268e-01 -3.4366300702095032e-01 + <_> + + 0 -1 314 -4.4096998870372772e-02 + + 9.7634297609329224e-01 -1.9173000007867813e-02 + <_> + + 0 -1 315 -6.0669999569654465e-02 + + -2.1752851009368896e+00 -2.8925999999046326e-02 + <_> + + 0 -1 316 -3.2931998372077942e-02 + + -6.4383101463317871e-01 1.6494099795818329e-01 + <_> + + 0 -1 317 -1.4722800254821777e-01 + + -1.4745830297470093e+00 2.5839998852461576e-03 + <_> + + 0 -1 318 -1.1930000036954880e-02 + + 4.2441400885581970e-01 -1.7712600529193878e-01 + <_> + + 0 -1 319 1.4517900347709656e-01 + + 2.5444999337196350e-02 -1.2779400348663330e+00 + <_> + + 0 -1 320 5.1447998732328415e-02 + + 1.5678399801254272e-01 -1.5188430547714233e+00 + <_> + + 0 -1 321 3.1479999888688326e-03 + + -4.0424400568008423e-01 3.2429701089859009e-01 + <_> + + 0 -1 322 -4.3600000441074371e-02 + + -1.9932260513305664e+00 1.5018600225448608e-01 + <_> + 83 + -3.8424909114837646e+00 + + <_> + + 0 -1 323 1.2899599969387054e-01 + + -6.2161999940872192e-01 1.1116520166397095e+00 + <_> + + 0 -1 324 -9.1261997818946838e-02 + + 1.0143059492111206e+00 -6.1335200071334839e-01 + <_> + + 0 -1 325 1.4271999709308147e-02 + + -1.0261659622192383e+00 3.9779999852180481e-01 + <_> + + 0 -1 326 3.2889999449253082e-02 + + -1.1386079788208008e+00 2.8690800070762634e-01 + <_> + + 0 -1 327 1.2590000405907631e-02 + + -5.6645601987838745e-01 4.5172399282455444e-01 + <_> + + 0 -1 328 1.4661000110208988e-02 + + 3.0505999922752380e-01 -6.8129599094390869e-01 + <_> + + 0 -1 329 -3.3555999398231506e-02 + + -1.7208939790725708e+00 6.1439000070095062e-02 + <_> + + 0 -1 330 1.4252699911594391e-01 + + 2.3192200064659119e-01 -1.7297149896621704e+00 + <_> + + 0 -1 331 -6.2079997733235359e-03 + + -1.2163300514221191e+00 1.2160199880599976e-01 + <_> + + 0 -1 332 1.8178999423980713e-02 + + 3.2553699612617493e-01 -8.1003999710083008e-01 + <_> + + 0 -1 333 2.5036999955773354e-02 + + -3.1698799133300781e-01 6.7361402511596680e-01 + <_> + + 0 -1 334 4.6560999006032944e-02 + + -1.1089800298213959e-01 8.4082502126693726e-01 + <_> + + 0 -1 335 -8.9999996125698090e-03 + + 3.9574500918388367e-01 -4.7624599933624268e-01 + <_> + + 0 -1 336 4.0805999189615250e-02 + + -1.8000000272877514e-04 9.4570702314376831e-01 + <_> + + 0 -1 337 -3.4221999347209930e-02 + + 7.5206297636032104e-01 -3.1531500816345215e-01 + <_> + + 0 -1 338 -3.9716001600027084e-02 + + -8.3139598369598389e-01 1.7744399607181549e-01 + <_> + + 0 -1 339 2.5170000735670328e-03 + + -5.9377998113632202e-01 2.4657000601291656e-01 + <_> + + 0 -1 340 2.7428999543190002e-02 + + 1.5998399257659912e-01 -4.2781999707221985e-01 + <_> + + 0 -1 341 3.4986000508069992e-02 + + 3.5055998712778091e-02 -1.5988600254058838e+00 + <_> + + 0 -1 342 4.4970000162720680e-03 + + -5.2034300565719604e-01 3.7828299403190613e-01 + <_> + + 0 -1 343 2.7699999045580626e-03 + + -5.3182601928710938e-01 2.4951000511646271e-01 + <_> + + 0 -1 344 3.5174001008272171e-02 + + 1.9983400404453278e-01 -1.4446129798889160e+00 + <_> + + 0 -1 345 2.5970999151468277e-02 + + 4.4426999986171722e-02 -1.3622980117797852e+00 + <_> + + 0 -1 346 -1.5783999115228653e-02 + + -9.1020399332046509e-01 2.7190300822257996e-01 + <_> + + 0 -1 347 -7.5880000367760658e-03 + + 9.2064999043941498e-02 -8.1628900766372681e-01 + <_> + + 0 -1 348 2.0754000172019005e-02 + + 2.1185700595378876e-01 -7.4729001522064209e-01 + <_> + + 0 -1 349 5.9829000383615494e-02 + + -2.7301099896430969e-01 8.0923300981521606e-01 + <_> + + 0 -1 350 3.9039000868797302e-02 + + -1.0432299971580505e-01 8.6226201057434082e-01 + <_> + + 0 -1 351 2.1665999665856361e-02 + + 6.2709003686904907e-02 -9.8894298076629639e-01 + <_> + + 0 -1 352 -2.7496999129652977e-02 + + -9.2690998315811157e-01 1.5586300194263458e-01 + <_> + + 0 -1 353 1.0462000034749508e-02 + + 1.3418099284172058e-01 -7.0386397838592529e-01 + <_> + + 0 -1 354 2.4870999157428741e-02 + + 1.9706700742244720e-01 -4.0263301134109497e-01 + <_> + + 0 -1 355 -1.6036000102758408e-02 + + -1.1409829854965210e+00 7.3997996747493744e-02 + <_> + + 0 -1 356 4.8627000302076340e-02 + + 1.6990399360656738e-01 -7.2152197360992432e-01 + <_> + + 0 -1 357 1.2619999470189214e-03 + + -4.7389799356460571e-01 2.6254999637603760e-01 + <_> + + 0 -1 358 -8.8035002350807190e-02 + + -2.1606519222259521e+00 1.4554800093173981e-01 + <_> + + 0 -1 359 1.8356999382376671e-02 + + 4.4750999659299850e-02 -1.0766370296478271e+00 + <_> + + 0 -1 360 3.5275001078844070e-02 + + -3.2919000834226608e-02 1.2153890132904053e+00 + <_> + + 0 -1 361 -2.0392900705337524e-01 + + -1.3187999725341797e+00 1.5503999777138233e-02 + <_> + + 0 -1 362 -1.6619000583887100e-02 + + 3.6850199103355408e-01 -1.5283699333667755e-01 + <_> + + 0 -1 363 3.7739001214504242e-02 + + -2.5727799534797668e-01 7.0655298233032227e-01 + <_> + + 0 -1 364 2.2720000706613064e-03 + + -7.7602997422218323e-02 3.3367800712585449e-01 + <_> + + 0 -1 365 -1.4802999794483185e-02 + + -7.8524798154830933e-01 7.6934002339839935e-02 + <_> + + 0 -1 366 -4.8319000750780106e-02 + + 1.7022320032119751e+00 4.9722000956535339e-02 + <_> + + 0 -1 367 -2.9539000242948532e-02 + + 7.7670699357986450e-01 -2.4534299969673157e-01 + <_> + + 0 -1 368 -4.6169001609086990e-02 + + -1.4922779798507690e+00 1.2340000271797180e-01 + <_> + + 0 -1 369 -2.8064999729394913e-02 + + -2.1345369815826416e+00 -2.5797000154852867e-02 + <_> + + 0 -1 370 -5.7339998893439770e-03 + + 5.6982600688934326e-01 -1.2056600302457809e-01 + <_> + + 0 -1 371 -1.0111000388860703e-02 + + 6.7911398410797119e-01 -2.6638001203536987e-01 + <_> + + 0 -1 372 1.1359999887645245e-02 + + 2.4789799749851227e-01 -6.4493000507354736e-01 + <_> + + 0 -1 373 5.1809001713991165e-02 + + 1.4716000296175480e-02 -1.2395579814910889e+00 + <_> + + 0 -1 374 3.3291999250650406e-02 + + -8.2559995353221893e-03 1.0168470144271851e+00 + <_> + + 0 -1 375 -1.4494000002741814e-02 + + 4.5066800713539124e-01 -3.6250999569892883e-01 + <_> + + 0 -1 376 -3.4221999347209930e-02 + + -9.5292502641677856e-01 2.0684599876403809e-01 + <_> + + 0 -1 377 -8.0654002726078033e-02 + + -2.0139501094818115e+00 -2.3084999993443489e-02 + <_> + + 0 -1 378 -8.9399999706074595e-04 + + 3.9572000503540039e-01 -2.9351300001144409e-01 + <_> + + 0 -1 379 9.7162000834941864e-02 + + -2.4980300664901733e-01 1.0859220027923584e+00 + <_> + + 0 -1 380 3.6614000797271729e-02 + + -5.7844001799821854e-02 1.2162159681320190e+00 + <_> + + 0 -1 381 5.1693998277187347e-02 + + 4.3062999844551086e-02 -1.0636160373687744e+00 + <_> + + 0 -1 382 -2.4557000026106834e-02 + + -4.8946800827980042e-01 1.7182900011539459e-01 + <_> + + 0 -1 383 3.2736799120903015e-01 + + -2.9688599705696106e-01 5.1798301935195923e-01 + <_> + + 0 -1 384 7.6959999278187752e-03 + + -5.9805899858474731e-01 2.4803200364112854e-01 + <_> + + 0 -1 385 1.6172200441360474e-01 + + -2.9613999649882317e-02 -2.3162529468536377e+00 + <_> + + 0 -1 386 -4.7889999113976955e-03 + + 3.7457901239395142e-01 -3.2779198884963989e-01 + <_> + + 0 -1 387 -1.8402999266982079e-02 + + -9.9692702293395996e-01 7.2948001325130463e-02 + <_> + + 0 -1 388 7.7665001153945923e-02 + + 1.4175699651241302e-01 -1.7238730192184448e+00 + <_> + + 0 -1 389 1.8921000882983208e-02 + + -2.1273100376129150e-01 1.0165189504623413e+00 + <_> + + 0 -1 390 -7.9397998750209808e-02 + + -1.3164349794387817e+00 1.4981999993324280e-01 + <_> + + 0 -1 391 -6.8037003278732300e-02 + + 4.9421998858451843e-01 -2.9091000556945801e-01 + <_> + + 0 -1 392 -6.1010001227259636e-03 + + 4.2430499196052551e-01 -3.3899301290512085e-01 + <_> + + 0 -1 393 3.1927000731229782e-02 + + -3.1046999618411064e-02 -2.3459999561309814e+00 + <_> + + 0 -1 394 -2.9843999072909355e-02 + + -7.8989601135253906e-01 1.5417699515819550e-01 + <_> + + 0 -1 395 -8.0541998147964478e-02 + + -2.2509229183197021e+00 -3.0906999483704567e-02 + <_> + + 0 -1 396 3.8109999150037766e-03 + + -2.5577300786972046e-01 2.3785500228404999e-01 + <_> + + 0 -1 397 3.3647000789642334e-02 + + -2.2541399300098419e-01 9.2307400703430176e-01 + <_> + + 0 -1 398 8.2809999585151672e-03 + + -2.8896200656890869e-01 3.1046199798583984e-01 + <_> + + 0 -1 399 1.0104399919509888e-01 + + -3.4864000976085663e-02 -2.7102620601654053e+00 + <_> + + 0 -1 400 -1.0009000077843666e-02 + + 5.9715402126312256e-01 -3.3831000328063965e-02 + <_> + + 0 -1 401 7.1919998154044151e-03 + + -4.7738000750541687e-01 2.2686000168323517e-01 + <_> + + 0 -1 402 2.4969000369310379e-02 + + 2.2877700626850128e-01 -1.0435529947280884e+00 + <_> + + 0 -1 403 2.7908000349998474e-01 + + -2.5818100571632385e-01 7.6780498027801514e-01 + <_> + + 0 -1 404 -4.4213000684976578e-02 + + -5.9798002243041992e-01 2.8039899468421936e-01 + <_> + + 0 -1 405 -1.4136999845504761e-02 + + 7.0987302064895630e-01 -2.5645199418067932e-01 + <_> + 91 + -3.6478610038757324e+00 + + <_> + + 0 -1 406 1.3771200180053711e-01 + + -5.5870598554611206e-01 1.0953769683837891e+00 + <_> + + 0 -1 407 3.4460999071598053e-02 + + -7.1171897649765015e-01 5.2899599075317383e-01 + <_> + + 0 -1 408 1.8580000847578049e-02 + + -1.1157519817352295e+00 4.0593999624252319e-01 + <_> + + 0 -1 409 2.5041999295353889e-02 + + -4.0892499685287476e-01 7.4129998683929443e-01 + <_> + + 0 -1 410 5.7179000228643417e-02 + + -3.8054299354553223e-01 7.3647701740264893e-01 + <_> + + 0 -1 411 1.4932000078260899e-02 + + -6.9945502281188965e-01 3.7950998544692993e-01 + <_> + + 0 -1 412 8.8900001719594002e-03 + + -5.4558598995208740e-01 3.6332499980926514e-01 + <_> + + 0 -1 413 3.0435999855399132e-02 + + -1.0124599933624268e-01 7.9585897922515869e-01 + <_> + + 0 -1 414 -4.4160000979900360e-02 + + 8.4410899877548218e-01 -3.2976400852203369e-01 + <_> + + 0 -1 415 1.8461000174283981e-02 + + 2.6326599717140198e-01 -9.6736502647399902e-01 + <_> + + 0 -1 416 1.0614999569952488e-02 + + 1.5251900255680084e-01 -1.0589870214462280e+00 + <_> + + 0 -1 417 -4.5974001288414001e-02 + + -1.9918340444564819e+00 1.3629099726676941e-01 + <_> + + 0 -1 418 8.2900002598762512e-02 + + -3.2037198543548584e-01 6.0304200649261475e-01 + <_> + + 0 -1 419 -8.9130001142621040e-03 + + 5.9586602449417114e-01 -2.1139599382877350e-01 + <_> + + 0 -1 420 4.2814001441001892e-02 + + 2.2925000637769699e-02 -1.4679330587387085e+00 + <_> + + 0 -1 421 -8.7139997631311417e-03 + + -4.3989500403404236e-01 2.0439699292182922e-01 + <_> + + 0 -1 422 -4.3390002101659775e-03 + + -8.9066797494888306e-01 1.0469999909400940e-01 + <_> + + 0 -1 423 8.0749997869133949e-03 + + 2.1164199709892273e-01 -4.0231600403785706e-01 + <_> + + 0 -1 424 9.6739001572132111e-02 + + 1.3319999910891056e-02 -1.6085360050201416e+00 + <_> + + 0 -1 425 -3.0536999925971031e-02 + + 1.0063740015029907e+00 -1.3413299620151520e-01 + <_> + + 0 -1 426 -6.0855999588966370e-02 + + -1.4689979553222656e+00 9.4240000471472740e-03 + <_> + + 0 -1 427 -3.8162000477313995e-02 + + -8.1636399030685425e-01 2.6171201467514038e-01 + <_> + + 0 -1 428 -9.6960002556443214e-03 + + 1.1561699956655502e-01 -7.1693199872970581e-01 + <_> + + 0 -1 429 4.8902999609708786e-02 + + 1.3050499558448792e-01 -1.6448370218276978e+00 + <_> + + 0 -1 430 -4.1611999273300171e-02 + + -1.1795840263366699e+00 2.5017000734806061e-02 + <_> + + 0 -1 431 -2.0188000053167343e-02 + + 6.3188201189041138e-01 -1.0490400344133377e-01 + <_> + + 0 -1 432 -9.7900000400841236e-04 + + 1.8507799506187439e-01 -5.3565901517868042e-01 + <_> + + 0 -1 433 -3.3622000366449356e-02 + + -9.3127602338790894e-01 2.0071500539779663e-01 + <_> + + 0 -1 434 1.9455999135971069e-02 + + 3.8029000163078308e-02 -1.0112210512161255e+00 + <_> + + 0 -1 435 -3.1800000579096377e-04 + + 3.6457699537277222e-01 -2.7610900998115540e-01 + <_> + + 0 -1 436 -3.8899999344721437e-04 + + 1.9665899872779846e-01 -5.3410500288009644e-01 + <_> + + 0 -1 437 -9.3496002256870270e-02 + + -1.6772350072860718e+00 2.0727099478244781e-01 + <_> + + 0 -1 438 -7.7877998352050781e-02 + + -3.0760629177093506e+00 -3.5803999751806259e-02 + <_> + + 0 -1 439 1.6947999596595764e-02 + + 2.1447399258613586e-01 -7.1376299858093262e-01 + <_> + + 0 -1 440 -2.1459000185132027e-02 + + -1.1468060016632080e+00 1.5855999663472176e-02 + <_> + + 0 -1 441 -1.2865999713540077e-02 + + 8.3812397718429565e-01 -6.5944001078605652e-02 + <_> + + 0 -1 442 7.8220004215836525e-03 + + -2.8026801347732544e-01 7.9376900196075439e-01 + <_> + + 0 -1 443 1.0294400155544281e-01 + + 1.7832300066947937e-01 -6.8412202596664429e-01 + <_> + + 0 -1 444 -3.7487998604774475e-02 + + 9.6189999580383301e-01 -2.1735599637031555e-01 + <_> + + 0 -1 445 2.5505999103188515e-02 + + 1.0103999637067318e-02 1.2461110353469849e+00 + <_> + + 0 -1 446 6.6700001480057836e-04 + + -5.3488200902938843e-01 1.4746299386024475e-01 + <_> + + 0 -1 447 -2.8867900371551514e-01 + + 8.2172799110412598e-01 -1.4948000200092793e-02 + <_> + + 0 -1 448 9.1294996440410614e-02 + + -1.9605399668216705e-01 1.0803170204162598e+00 + <_> + + 0 -1 449 1.2056600302457809e-01 + + -2.3848999291658401e-02 1.1392610073089600e+00 + <_> + + 0 -1 450 -7.3775000870227814e-02 + + -1.3583840131759644e+00 -4.2039998807013035e-03 + <_> + + 0 -1 451 -3.3128000795841217e-02 + + -6.4483201503753662e-01 2.4142199754714966e-01 + <_> + + 0 -1 452 -4.3937001377344131e-02 + + 8.4285402297973633e-01 -2.0624800026416779e-01 + <_> + + 0 -1 453 1.8110199272632599e-01 + + 1.9212099909782410e-01 -1.2222139835357666e+00 + <_> + + 0 -1 454 -1.1850999668240547e-02 + + -7.2677397727966309e-01 5.2687998861074448e-02 + <_> + + 0 -1 455 4.5920000411570072e-03 + + -3.6305201053619385e-01 2.9223799705505371e-01 + <_> + + 0 -1 456 7.0620002225041389e-03 + + 5.8116000145673752e-02 -6.7161601781845093e-01 + <_> + + 0 -1 457 -2.3715000599622726e-02 + + 4.7142100334167480e-01 1.8580000847578049e-02 + <_> + + 0 -1 458 -6.7171998322010040e-02 + + -1.1331889629364014e+00 2.3780999705195427e-02 + <_> + + 0 -1 459 -6.5310001373291016e-02 + + 9.8253500461578369e-01 2.8362000361084938e-02 + <_> + + 0 -1 460 2.2791000083088875e-02 + + -2.8213700652122498e-01 5.8993399143218994e-01 + <_> + + 0 -1 461 -1.9037999212741852e-02 + + -6.3711500167846680e-01 2.6514598727226257e-01 + <_> + + 0 -1 462 -6.8689999170601368e-03 + + 3.7487301230430603e-01 -3.3232098817825317e-01 + <_> + + 0 -1 463 -4.0146000683307648e-02 + + -1.3048729896545410e+00 1.5724299848079681e-01 + <_> + + 0 -1 464 -4.0530998259782791e-02 + + -2.0458049774169922e+00 -2.6925999671220779e-02 + <_> + + 0 -1 465 -1.2253999710083008e-02 + + 7.7649402618408203e-01 -4.2971000075340271e-02 + <_> + + 0 -1 466 -2.7219999581575394e-02 + + 1.7424400150775909e-01 -4.4600901007652283e-01 + <_> + + 0 -1 467 -8.8366001844406128e-02 + + -1.5036419630050659e+00 1.4289900660514832e-01 + <_> + + 0 -1 468 -7.9159997403621674e-03 + + 2.8666698932647705e-01 -3.7923699617385864e-01 + <_> + + 0 -1 469 -4.1960000991821289e-02 + + 1.3846950531005859e+00 6.5026998519897461e-02 + <_> + + 0 -1 470 4.5662999153137207e-02 + + -2.2452299296855927e-01 7.9521000385284424e-01 + <_> + + 0 -1 471 -1.4090600609779358e-01 + + -1.5879319906234741e+00 1.1359000205993652e-01 + <_> + + 0 -1 472 -5.9216000139713287e-02 + + -1.1945960521697998e+00 -7.1640000678598881e-03 + <_> + + 0 -1 473 4.3390002101659775e-03 + + -1.5528699755668640e-01 4.0664499998092651e-01 + <_> + + 0 -1 474 -2.0369999110698700e-03 + + 2.5927901268005371e-01 -3.8368299603462219e-01 + <_> + + 0 -1 475 2.7516499161720276e-01 + + -8.8497996330261230e-02 7.6787501573562622e-01 + <_> + + 0 -1 476 -2.6601999998092651e-02 + + 7.5024497509002686e-01 -2.2621999680995941e-01 + <_> + + 0 -1 477 4.0906000882387161e-02 + + 1.2158600240945816e-01 -1.4566910266876221e+00 + <_> + + 0 -1 478 5.5320002138614655e-03 + + -3.6611500382423401e-01 2.5968599319458008e-01 + <_> + + 0 -1 479 3.1879000365734100e-02 + + -7.5019001960754395e-02 4.8484799265861511e-01 + <_> + + 0 -1 480 -4.1482001543045044e-02 + + 7.8220397233963013e-01 -2.1992200613021851e-01 + <_> + + 0 -1 481 -9.6130996942520142e-02 + + -8.9456301927566528e-01 1.4680700004100800e-01 + <_> + + 0 -1 482 -1.1568999849259853e-02 + + 8.2714098691940308e-01 -2.0275600254535675e-01 + <_> + + 0 -1 483 1.8312999978661537e-02 + + 1.6367999836802483e-02 2.7306801080703735e-01 + <_> + + 0 -1 484 -3.4166000783443451e-02 + + 1.1307320594787598e+00 -1.8810899555683136e-01 + <_> + + 0 -1 485 -2.4476999416947365e-02 + + -5.7791298627853394e-01 1.5812499821186066e-01 + <_> + + 0 -1 486 4.8957001417875290e-02 + + -2.2564999759197235e-02 -1.6373280286788940e+00 + <_> + + 0 -1 487 -2.0702999085187912e-02 + + -5.4512101411819458e-01 2.4086999893188477e-01 + <_> + + 0 -1 488 -2.3002000525593758e-02 + + -1.2236540317535400e+00 -7.3440000414848328e-03 + <_> + + 0 -1 489 6.4585000276565552e-02 + + 1.4695599675178528e-01 -4.4967499375343323e-01 + <_> + + 0 -1 490 1.2666000053286552e-02 + + -2.7873900532722473e-01 4.3876600265502930e-01 + <_> + + 0 -1 491 -1.2002999894320965e-02 + + -2.4289099872112274e-01 2.5350099802017212e-01 + <_> + + 0 -1 492 -2.6443999260663986e-02 + + -8.5864800214767456e-01 2.6025999337434769e-02 + <_> + + 0 -1 493 -2.5547999888658524e-02 + + 6.9287902116775513e-01 -2.1160000469535589e-03 + <_> + + 0 -1 494 3.9115000516176224e-02 + + -1.6589100658893585e-01 1.5209139585494995e+00 + <_> + + 0 -1 495 -6.0330000706017017e-03 + + 4.3856900930404663e-01 -2.1613700687885284e-01 + <_> + + 0 -1 496 -3.3936999738216400e-02 + + -9.7998398542404175e-01 2.2133000195026398e-02 + <_> + 99 + -3.8700489997863770e+00 + + <_> + + 0 -1 497 4.0672998875379562e-02 + + -9.0474700927734375e-01 6.4410597085952759e-01 + <_> + + 0 -1 498 2.5609999895095825e-02 + + -7.9216998815536499e-01 5.7489997148513794e-01 + <_> + + 0 -1 499 1.9959500432014465e-01 + + -3.0099600553512573e-01 1.3143850564956665e+00 + <_> + + 0 -1 500 1.2404999695718288e-02 + + -8.9882999658584595e-01 2.9205799102783203e-01 + <_> + + 0 -1 501 3.9207998663187027e-02 + + -4.1955199837684631e-01 5.3463298082351685e-01 + <_> + + 0 -1 502 -3.0843999236822128e-02 + + 4.5793399214744568e-01 -4.4629099965095520e-01 + <_> + + 0 -1 503 -3.5523001104593277e-02 + + 9.1310501098632812e-01 -2.7373200654983521e-01 + <_> + + 0 -1 504 -6.1650000512599945e-02 + + -1.4697799682617188e+00 2.0364099740982056e-01 + <_> + + 0 -1 505 -1.1739999987185001e-02 + + -1.0482879877090454e+00 6.7801997065544128e-02 + <_> + + 0 -1 506 6.6933996975421906e-02 + + 2.9274499416351318e-01 -5.2282899618148804e-01 + <_> + + 0 -1 507 -2.0631000399589539e-02 + + -1.2855139970779419e+00 4.4550999999046326e-02 + <_> + + 0 -1 508 -2.2357000038027763e-02 + + -8.5753798484802246e-01 1.8434000015258789e-01 + <_> + + 0 -1 509 1.1500000255182385e-03 + + 1.6405500471591949e-01 -6.9125002622604370e-01 + <_> + + 0 -1 510 3.5872999578714371e-02 + + 1.5756499767303467e-01 -8.4262597560882568e-01 + <_> + + 0 -1 511 3.0659999698400497e-02 + + 2.1637000143527985e-02 -1.3634690046310425e+00 + <_> + + 0 -1 512 5.5559999309480190e-03 + + -1.6737000644207001e-01 2.5888401269912720e-01 + <_> + + 0 -1 513 -6.1160000041127205e-03 + + -9.7271800041198730e-01 6.6100001335144043e-02 + <_> + + 0 -1 514 -3.0316999182105064e-02 + + 9.8474198579788208e-01 -1.6448000445961952e-02 + <_> + + 0 -1 515 -9.7200004383921623e-03 + + 4.7604700922966003e-01 -3.2516700029373169e-01 + <_> + + 0 -1 516 -5.7126998901367188e-02 + + -9.5920699834823608e-01 1.9938200712203979e-01 + <_> + + 0 -1 517 4.0059997700154781e-03 + + -5.2612501382827759e-01 2.2428700327873230e-01 + <_> + + 0 -1 518 3.3734001219272614e-02 + + 1.7070099711418152e-01 -1.0737580060958862e+00 + <_> + + 0 -1 519 -3.4641999751329422e-02 + + -1.1343129873275757e+00 3.6540001630783081e-02 + <_> + + 0 -1 520 4.6923000365495682e-02 + + 2.5832301378250122e-01 -7.1535801887512207e-01 + <_> + + 0 -1 521 -8.7660001590847969e-03 + + 1.9640900194644928e-01 -5.3355097770690918e-01 + <_> + + 0 -1 522 6.5627999603748322e-02 + + -5.1194999366998672e-02 9.7610700130462646e-01 + <_> + + 0 -1 523 -4.4165000319480896e-02 + + 1.0631920099258423e+00 -2.3462599515914917e-01 + <_> + + 0 -1 524 1.7304999753832817e-02 + + -1.8582899868488312e-01 4.5889899134635925e-01 + <_> + + 0 -1 525 3.3135998994112015e-02 + + -2.9381999745965004e-02 -2.6651329994201660e+00 + <_> + + 0 -1 526 -2.1029999479651451e-02 + + 9.9979901313781738e-01 2.4937000125646591e-02 + <_> + + 0 -1 527 2.9783999547362328e-02 + + -2.9605999588966370e-02 -2.1695868968963623e+00 + <_> + + 0 -1 528 5.5291999131441116e-02 + + -7.5599999399855733e-04 7.4651998281478882e-01 + <_> + + 0 -1 529 -3.3597998321056366e-02 + + -1.5274159908294678e+00 1.1060000397264957e-02 + <_> + + 0 -1 530 1.9602999091148376e-02 + + 3.3574998378753662e-02 9.9526202678680420e-01 + <_> + + 0 -1 531 -2.0787000656127930e-02 + + 7.6612901687622070e-01 -2.4670800566673279e-01 + <_> + + 0 -1 532 3.2536000013351440e-02 + + 1.6263400018215179e-01 -6.1134302616119385e-01 + <_> + + 0 -1 533 -1.0788000188767910e-02 + + -9.7839701175689697e-01 2.8969999402761459e-02 + <_> + + 0 -1 534 -9.9560003727674484e-03 + + 4.6145799756050110e-01 -1.3510499894618988e-01 + <_> + + 0 -1 535 -3.7489999085664749e-03 + + 2.5458198785781860e-01 -5.1955598592758179e-01 + <_> + + 0 -1 536 -4.1779998689889908e-02 + + -8.0565100908279419e-01 1.5208500623703003e-01 + <_> + + 0 -1 537 -3.4221000969409943e-02 + + -1.3137799501419067e+00 -3.5800000187009573e-03 + <_> + + 0 -1 538 1.0130000300705433e-02 + + 2.0175799727439880e-01 -6.1339598894119263e-01 + <_> + + 0 -1 539 -8.9849002659320831e-02 + + 9.7632801532745361e-01 -2.0884799957275391e-01 + <_> + + 0 -1 540 2.6097999885678291e-02 + + -1.8807999789714813e-01 4.7705799341201782e-01 + <_> + + 0 -1 541 -3.7539999466389418e-03 + + -6.7980402708053589e-01 1.1288800090551376e-01 + <_> + + 0 -1 542 3.1973000615835190e-02 + + 1.8951700627803802e-01 -1.4967479705810547e+00 + <_> + + 0 -1 543 1.9332999363541603e-02 + + -2.3609900474548340e-01 8.1320500373840332e-01 + <_> + + 0 -1 544 1.9490000559017062e-03 + + 2.4830399453639984e-01 -6.9211997091770172e-02 + <_> + + 0 -1 545 -4.4146999716758728e-02 + + -1.0418920516967773e+00 4.8053000122308731e-02 + <_> + + 0 -1 546 -4.4681999832391739e-02 + + 5.1346302032470703e-01 -7.3799998499453068e-03 + <_> + + 0 -1 547 -1.0757499933242798e-01 + + 1.6202019453048706e+00 -1.8667599558830261e-01 + <_> + + 0 -1 548 -1.2846800684928894e-01 + + 2.9869480133056641e+00 9.5427997410297394e-02 + <_> + + 0 -1 549 -4.4757999479770660e-02 + + 6.0405302047729492e-01 -2.7058699727058411e-01 + <_> + + 0 -1 550 -4.3990999460220337e-02 + + -6.1790502071380615e-01 1.5997199714183807e-01 + <_> + + 0 -1 551 -1.2268999963998795e-01 + + 6.6327202320098877e-01 -2.3636999726295471e-01 + <_> + + 0 -1 552 -1.9982999190688133e-02 + + -1.1228660345077515e+00 1.9616700708866119e-01 + <_> + + 0 -1 553 -1.5527999959886074e-02 + + -1.0770269632339478e+00 2.0693000406026840e-02 + <_> + + 0 -1 554 -4.8971001058816910e-02 + + 8.1168299913406372e-01 -1.7252000048756599e-02 + <_> + + 0 -1 555 5.5975999683141708e-02 + + -2.2529000416398048e-02 -1.7356760501861572e+00 + <_> + + 0 -1 556 -9.8580000922083855e-03 + + 6.7881399393081665e-01 -5.8180000633001328e-02 + <_> + + 0 -1 557 1.3481000438332558e-02 + + 5.7847999036312103e-02 -7.7255302667617798e-01 + <_> + + 0 -1 558 6.5609999001026154e-03 + + -1.3146899640560150e-01 6.7055797576904297e-01 + <_> + + 0 -1 559 7.1149999275803566e-03 + + -3.7880599498748779e-01 3.0978998541831970e-01 + <_> + + 0 -1 560 4.8159998841583729e-03 + + -5.8470398187637329e-01 2.5602099299430847e-01 + <_> + + 0 -1 561 9.5319999381899834e-03 + + -3.0217000842094421e-01 4.1253298521041870e-01 + <_> + + 0 -1 562 -2.7474999427795410e-02 + + 5.9154701232910156e-01 1.7963999882340431e-02 + <_> + + 0 -1 563 -3.9519999176263809e-02 + + 9.6913498640060425e-01 -2.1020300686359406e-01 + <_> + + 0 -1 564 -3.0658999457955360e-02 + + 9.1155898571014404e-01 4.0550000965595245e-02 + <_> + + 0 -1 565 -1.4680000022053719e-03 + + -6.0489797592163086e-01 1.6960899531841278e-01 + <_> + + 0 -1 566 1.9077600538730621e-01 + + 4.3515000492334366e-02 8.1892901659011841e-01 + <_> + + 0 -1 567 5.1790000870823860e-03 + + -9.3617302179336548e-01 2.4937000125646591e-02 + <_> + + 0 -1 568 2.4126000702381134e-02 + + 1.8175500631332397e-01 -3.4185901284217834e-01 + <_> + + 0 -1 569 -2.6383999735116959e-02 + + -1.2912579774856567e+00 -3.4280000254511833e-03 + <_> + + 0 -1 570 5.4139997810125351e-03 + + -4.6291999518871307e-02 2.5269600749015808e-01 + <_> + + 0 -1 571 5.4216001182794571e-02 + + -1.2848000042140484e-02 -1.4304540157318115e+00 + <_> + + 0 -1 572 2.3799999326001853e-04 + + -2.6676699519157410e-01 3.3588299155235291e-01 + <_> + + 0 -1 573 1.5216999687254429e-02 + + -5.1367300748825073e-01 1.3005100190639496e-01 + <_> + + 0 -1 574 1.7007999122142792e-02 + + 4.1575899720191956e-01 -3.1241199374198914e-01 + <_> + + 0 -1 575 3.0496999621391296e-02 + + -2.4820999801158905e-01 7.0828497409820557e-01 + <_> + + 0 -1 576 6.5430002287030220e-03 + + -2.2637000679969788e-01 1.9184599816799164e-01 + <_> + + 0 -1 577 1.4163999259471893e-01 + + 6.5227001905441284e-02 -8.8809502124786377e-01 + <_> + + 0 -1 578 1.9338000565767288e-02 + + 1.8891200423240662e-01 -2.7397701144218445e-01 + <_> + + 0 -1 579 -1.7324000597000122e-02 + + -9.4866698980331421e-01 2.4196999147534370e-02 + <_> + + 0 -1 580 -6.2069999985396862e-03 + + 3.6938399076461792e-01 -1.7494900524616241e-01 + <_> + + 0 -1 581 -1.6109000891447067e-02 + + 9.6159499883651733e-01 -2.0005300641059875e-01 + <_> + + 0 -1 582 -1.0122500360012054e-01 + + -3.0699110031127930e+00 1.1363799870014191e-01 + <_> + + 0 -1 583 -7.5509999878704548e-03 + + 2.2921000421047211e-01 -4.5645099878311157e-01 + <_> + + 0 -1 584 4.4247999787330627e-02 + + -3.1599999056197703e-04 3.9225301146507263e-01 + <_> + + 0 -1 585 -1.1636000126600266e-01 + + 9.5233702659606934e-01 -2.0201599597930908e-01 + <_> + + 0 -1 586 4.7360002063214779e-03 + + -9.9177002906799316e-02 2.0370499789714813e-01 + <_> + + 0 -1 587 2.2459000349044800e-02 + + 8.7280003353953362e-03 -1.0217070579528809e+00 + <_> + + 0 -1 588 -1.2109000235795975e-02 + + 6.4812600612640381e-01 -9.0149000287055969e-02 + <_> + + 0 -1 589 5.6120000779628754e-02 + + -3.6759998649358749e-02 -1.9275590181350708e+00 + <_> + + 0 -1 590 -8.7379999458789825e-03 + + 6.9261300563812256e-01 -6.8374998867511749e-02 + <_> + + 0 -1 591 6.6399998031556606e-03 + + -4.0569800138473511e-01 1.8625700473785400e-01 + <_> + + 0 -1 592 -1.8131999298930168e-02 + + -6.4518201351165771e-01 2.1976399421691895e-01 + <_> + + 0 -1 593 -2.2718999534845352e-02 + + 9.7776198387145996e-01 -1.8654300272464752e-01 + <_> + + 0 -1 594 1.2705000117421150e-02 + + -1.0546600073575974e-01 3.7404099106788635e-01 + <_> + + 0 -1 595 -1.3682999648153782e-02 + + 6.1064100265502930e-01 -2.6881098747253418e-01 + <_> + 115 + -3.7160909175872803e+00 + + <_> + + 0 -1 596 3.1357999891042709e-02 + + -1.0183910131454468e+00 5.7528597116470337e-01 + <_> + + 0 -1 597 9.3050003051757812e-02 + + -4.1297501325607300e-01 1.0091199874877930e+00 + <_> + + 0 -1 598 2.5949999690055847e-02 + + -5.8587902784347534e-01 5.6606197357177734e-01 + <_> + + 0 -1 599 1.6472000628709793e-02 + + -9.2857497930526733e-01 3.0924499034881592e-01 + <_> + + 0 -1 600 -1.8779999809339643e-03 + + 1.1951000243425369e-01 -1.1180130243301392e+00 + <_> + + 0 -1 601 -9.0129999443888664e-03 + + -5.7849502563476562e-01 3.3154401183128357e-01 + <_> + + 0 -1 602 2.2547999396920204e-02 + + -3.8325101137161255e-01 5.2462202310562134e-01 + <_> + + 0 -1 603 -3.7780001759529114e-02 + + 1.1790670156478882e+00 -3.4166999161243439e-02 + <_> + + 0 -1 604 -5.3799999877810478e-03 + + -8.6265897750854492e-01 1.1867900192737579e-01 + <_> + + 0 -1 605 -2.3893000558018684e-02 + + -7.4950599670410156e-01 2.1011400222778320e-01 + <_> + + 0 -1 606 -2.6521999388933182e-02 + + 9.2128598690032959e-01 -2.8252801299095154e-01 + <_> + + 0 -1 607 1.2280000373721123e-02 + + 2.6662799715995789e-01 -7.0013600587844849e-01 + <_> + + 0 -1 608 9.6594996750354767e-02 + + -2.8453999757766724e-01 7.3168998956680298e-01 + <_> + + 0 -1 609 -2.7414999902248383e-02 + + -6.1492699384689331e-01 1.5576200187206268e-01 + <_> + + 0 -1 610 -1.5767000615596771e-02 + + 5.7551199197769165e-01 -3.4362199902534485e-01 + <_> + + 0 -1 611 -2.1100000012665987e-03 + + 3.2599699497222900e-01 -1.3008299469947815e-01 + <_> + + 0 -1 612 1.2006999924778938e-02 + + 8.9322999119758606e-02 -9.6025598049163818e-01 + <_> + + 0 -1 613 -1.5421999618411064e-02 + + 3.4449499845504761e-01 -4.6711999177932739e-01 + <_> + + 0 -1 614 -4.1579999960958958e-03 + + 2.3696300387382507e-01 -5.2563297748565674e-01 + <_> + + 0 -1 615 -2.1185999736189842e-02 + + -7.4267697334289551e-01 2.1702000498771667e-01 + <_> + + 0 -1 616 -1.7077000811696053e-02 + + -9.0471798181533813e-01 6.6012002527713776e-02 + <_> + + 0 -1 617 -4.0849998593330383e-02 + + -3.4446600079536438e-01 2.1503700315952301e-01 + <_> + + 0 -1 618 -8.1930002197623253e-03 + + -9.3388599157333374e-01 5.0471000373363495e-02 + <_> + + 0 -1 619 -1.9238000735640526e-02 + + -5.3203701972961426e-01 1.7240600287914276e-01 + <_> + + 0 -1 620 -4.4192001223564148e-02 + + 9.2075002193450928e-01 -2.2148500382900238e-01 + <_> + + 0 -1 621 -6.2392000108957291e-02 + + -7.1053802967071533e-01 1.8323899805545807e-01 + <_> + + 0 -1 622 -1.0079999919980764e-03 + + -8.7063097953796387e-01 5.5330000817775726e-02 + <_> + + 0 -1 623 2.3870000615715981e-02 + + -2.2854200005531311e-01 5.2415597438812256e-01 + <_> + + 0 -1 624 2.1391000598669052e-02 + + -3.0325898528099060e-01 5.5860602855682373e-01 + <_> + + 0 -1 625 2.0254999399185181e-02 + + 2.6901501417160034e-01 -7.0261800289154053e-01 + <_> + + 0 -1 626 -2.8772000223398209e-02 + + -1.1835030317306519e+00 4.6512000262737274e-02 + <_> + + 0 -1 627 3.4199999645352364e-03 + + -5.4652100801467896e-01 2.5962498784065247e-01 + <_> + + 0 -1 628 5.6983001530170441e-02 + + -2.6982900500297546e-01 5.8170700073242188e-01 + <_> + + 0 -1 629 -9.3892000615596771e-02 + + -9.1046398878097534e-01 1.9677700102329254e-01 + <_> + + 0 -1 630 1.7699999734759331e-02 + + -4.4003298878669739e-01 2.1349500119686127e-01 + <_> + + 0 -1 631 2.2844199836254120e-01 + + 2.3605000227689743e-02 7.7171599864959717e-01 + <_> + + 0 -1 632 -1.8287500739097595e-01 + + 7.9228597879409790e-01 -2.4644799530506134e-01 + <_> + + 0 -1 633 -6.9891996681690216e-02 + + 8.0267798900604248e-01 -3.6072000861167908e-02 + <_> + + 0 -1 634 1.5297000296413898e-02 + + -2.0072300732135773e-01 1.1030600070953369e+00 + <_> + + 0 -1 635 6.7500001750886440e-03 + + -4.5967999845743179e-02 7.2094500064849854e-01 + <_> + + 0 -1 636 -1.5983000397682190e-02 + + -9.0357202291488647e-01 4.4987998902797699e-02 + <_> + + 0 -1 637 1.3088000006973743e-02 + + 3.5297098755836487e-01 -3.7710601091384888e-01 + <_> + + 0 -1 638 1.3061000034213066e-02 + + -1.9583599269390106e-01 1.1198940277099609e+00 + <_> + + 0 -1 639 -3.9907000958919525e-02 + + -1.3998429775238037e+00 1.9145099818706512e-01 + <_> + + 0 -1 640 1.5026999637484550e-02 + + 2.3600000422447920e-03 -1.1611249446868896e+00 + <_> + + 0 -1 641 -2.0517999306321144e-02 + + -4.8908099532127380e-01 1.6743400692939758e-01 + <_> + + 0 -1 642 -2.2359000518918037e-02 + + -1.2202980518341064e+00 -1.1975999921560287e-02 + <_> + + 0 -1 643 -7.9150004312396049e-03 + + 3.7228098511695862e-01 -8.5063003003597260e-02 + <_> + + 0 -1 644 1.5258000232279301e-02 + + -2.9412600398063660e-01 5.9406399726867676e-01 + <_> + + 0 -1 645 -3.1665999442338943e-02 + + -1.4395569562911987e+00 1.3578799366950989e-01 + <_> + + 0 -1 646 -3.0773999169468880e-02 + + -2.2545371055603027e+00 -3.3971000462770462e-02 + <_> + + 0 -1 647 -1.5483000315725803e-02 + + 3.7700700759887695e-01 1.5847999602556229e-02 + <_> + + 0 -1 648 3.5167001187801361e-02 + + -2.9446101188659668e-01 5.3159099817276001e-01 + <_> + + 0 -1 649 -1.7906000837683678e-02 + + -9.9788200855255127e-01 1.6235999763011932e-01 + <_> + + 0 -1 650 -3.1799999997019768e-03 + + 4.7657001763582230e-02 -7.5249898433685303e-01 + <_> + + 0 -1 651 1.5720000490546227e-02 + + 1.4873799681663513e-01 -6.5375399589538574e-01 + <_> + + 0 -1 652 2.9864000156521797e-02 + + -1.4952000230550766e-02 -1.2275190353393555e+00 + <_> + + 0 -1 653 2.9899999499320984e-03 + + -1.4263699948787689e-01 4.3272799253463745e-01 + <_> + + 0 -1 654 8.4749996662139893e-02 + + -1.9280999898910522e-02 -1.1946409940719604e+00 + <_> + + 0 -1 655 -5.8724999427795410e-02 + + -1.7328219413757324e+00 1.4374700188636780e-01 + <_> + + 0 -1 656 4.4755998998880386e-02 + + -2.4140599370002747e-01 5.4019999504089355e-01 + <_> + + 0 -1 657 4.0369000285863876e-02 + + 5.7680001482367516e-03 5.6578099727630615e-01 + <_> + + 0 -1 658 3.7735998630523682e-02 + + 3.8180999457836151e-02 -7.9370397329330444e-01 + <_> + + 0 -1 659 6.0752999037504196e-02 + + 7.6453000307083130e-02 1.4813209772109985e+00 + <_> + + 0 -1 660 -1.9832000136375427e-02 + + -1.6971720457077026e+00 -2.7370000258088112e-02 + <_> + + 0 -1 661 -1.6592699289321899e-01 + + 6.2976002693176270e-01 3.1762998551130295e-02 + <_> + + 0 -1 662 6.9014996290206909e-02 + + -3.3463200926780701e-01 3.0076700448989868e-01 + <_> + + 0 -1 663 1.1358000338077545e-02 + + 2.2741499543190002e-01 -3.8224700093269348e-01 + <_> + + 0 -1 664 1.7000000225380063e-03 + + 1.9223800301551819e-01 -5.2735102176666260e-01 + <_> + + 0 -1 665 7.9769000411033630e-02 + + 9.1491997241973877e-02 2.1049048900604248e+00 + <_> + + 0 -1 666 -5.7144001126289368e-02 + + -1.7452130317687988e+00 -4.0910001844167709e-02 + <_> + + 0 -1 667 7.3830001056194305e-03 + + -2.4214799702167511e-01 3.5577800869941711e-01 + <_> + + 0 -1 668 -1.8040999770164490e-02 + + 1.1779999732971191e+00 -1.7676700651645660e-01 + <_> + + 0 -1 669 9.4503000378608704e-02 + + 1.3936099410057068e-01 -1.2993700504302979e+00 + <_> + + 0 -1 670 5.4210000671446323e-03 + + -5.4608601331710815e-01 1.3916400074958801e-01 + <_> + + 0 -1 671 7.0290002040565014e-03 + + -2.1597200632095337e-01 3.9258098602294922e-01 + <_> + + 0 -1 672 3.4515999257564545e-02 + + 6.3188999891281128e-02 -7.2108101844787598e-01 + <_> + + 0 -1 673 -5.1924999803304672e-02 + + 6.8667602539062500e-01 6.3272997736930847e-02 + <_> + + 0 -1 674 -6.9162003695964813e-02 + + 1.7411810159683228e+00 -1.6619299352169037e-01 + <_> + + 0 -1 675 -5.5229999125003815e-03 + + 3.0694699287414551e-01 -1.6662900149822235e-01 + <_> + + 0 -1 676 6.8599998950958252e-02 + + -2.1405400335788727e-01 7.3185002803802490e-01 + <_> + + 0 -1 677 -6.7038998007774353e-02 + + -7.9360598325729370e-01 2.0525799691677094e-01 + <_> + + 0 -1 678 -2.1005000919103622e-02 + + 3.7344399094581604e-01 -2.9618600010871887e-01 + <_> + + 0 -1 679 2.0278999581933022e-02 + + -1.5200000256299973e-02 4.0555301308631897e-01 + <_> + + 0 -1 680 -4.7107998281717300e-02 + + 1.2116849422454834e+00 -1.7464299499988556e-01 + <_> + + 0 -1 681 1.8768499791622162e-01 + + -2.2909000515937805e-02 6.9645798206329346e-01 + <_> + + 0 -1 682 -4.3228998780250549e-02 + + -1.0602480173110962e+00 -5.5599998449906707e-04 + <_> + + 0 -1 683 2.0004000514745712e-02 + + -3.2751001417636871e-02 5.3805100917816162e-01 + <_> + + 0 -1 684 8.0880001187324524e-03 + + 3.7548001855611801e-02 -7.4768900871276855e-01 + <_> + + 0 -1 685 2.7101000770926476e-02 + + -8.1790000200271606e-02 3.3387100696563721e-01 + <_> + + 0 -1 686 -9.1746002435684204e-02 + + -1.9213509559631348e+00 -3.8952998816967010e-02 + <_> + + 0 -1 687 -1.2454999610781670e-02 + + 4.8360601067543030e-01 1.8168000504374504e-02 + <_> + + 0 -1 688 1.4649000018835068e-02 + + -1.9906699657440186e-01 7.2815400362014771e-01 + <_> + + 0 -1 689 2.9101999476552010e-02 + + 1.9871099293231964e-01 -4.9216800928115845e-01 + <_> + + 0 -1 690 8.7799998000264168e-03 + + -1.9499599933624268e-01 7.7317398786544800e-01 + <_> + + 0 -1 691 -5.4740000516176224e-02 + + 1.8087190389633179e+00 6.8323001265525818e-02 + <_> + + 0 -1 692 -1.4798000454902649e-02 + + 7.8064900636672974e-01 -1.8709599971771240e-01 + <_> + + 0 -1 693 2.5012999773025513e-02 + + 1.5285299718379974e-01 -1.6021020412445068e+00 + <_> + + 0 -1 694 4.6548001468181610e-02 + + -1.6738200187683105e-01 1.1902060508728027e+00 + <_> + + 0 -1 695 1.7624000087380409e-02 + + -1.0285499691963196e-01 3.9175900816917419e-01 + <_> + + 0 -1 696 1.6319599747657776e-01 + + -3.5624001175165176e-02 -1.6098170280456543e+00 + <_> + + 0 -1 697 1.3137999922037125e-02 + + -5.6359000504016876e-02 5.4158902168273926e-01 + <_> + + 0 -1 698 -1.5665000304579735e-02 + + 2.8063100576400757e-01 -3.1708601117134094e-01 + <_> + + 0 -1 699 8.0554001033306122e-02 + + 1.2640400230884552e-01 -1.0297529697418213e+00 + <_> + + 0 -1 700 3.5363998264074326e-02 + + 2.0752999931573868e-02 -7.9105597734451294e-01 + <_> + + 0 -1 701 3.2986998558044434e-02 + + 1.9057099521160126e-01 -8.3839899301528931e-01 + <_> + + 0 -1 702 1.2195000424981117e-02 + + 7.3729000985622406e-02 -6.2780702114105225e-01 + <_> + + 0 -1 703 4.3065998703241348e-02 + + 4.7384999692440033e-02 1.5712939500808716e+00 + <_> + + 0 -1 704 3.0326999723911285e-02 + + -2.7314600348472595e-01 3.8572001457214355e-01 + <_> + + 0 -1 705 3.5493001341819763e-02 + + 5.4593998938798904e-02 5.2583402395248413e-01 + <_> + + 0 -1 706 -1.4596999622881413e-02 + + 3.8152599334716797e-01 -2.8332400321960449e-01 + <_> + + 0 -1 707 1.2606999836862087e-02 + + 1.5455099940299988e-01 -3.0501499772071838e-01 + <_> + + 0 -1 708 1.0172000154852867e-02 + + 2.3637000471353531e-02 -8.7217897176742554e-01 + <_> + + 0 -1 709 2.8843000531196594e-02 + + 1.6090999543666840e-01 -2.0277599990367889e-01 + <_> + + 0 -1 710 5.5100000463426113e-04 + + -6.1545401811599731e-01 8.0935999751091003e-02 + <_> + 127 + -3.5645289421081543e+00 + + <_> + + 0 -1 711 4.8344001173973083e-02 + + -8.4904599189758301e-01 5.6974399089813232e-01 + <_> + + 0 -1 712 3.2460000365972519e-02 + + -8.1417298316955566e-01 4.4781699776649475e-01 + <_> + + 0 -1 713 3.3339999616146088e-02 + + -3.6423799395561218e-01 6.7937397956848145e-01 + <_> + + 0 -1 714 6.4019998535513878e-03 + + -1.1885459423065186e+00 1.9238699972629547e-01 + <_> + + 0 -1 715 -5.6889997795224190e-03 + + 3.3085298538208008e-01 -7.1334099769592285e-01 + <_> + + 0 -1 716 1.2698000296950340e-02 + + -5.0990802049636841e-01 1.1376299709081650e-01 + <_> + + 0 -1 717 6.0549997724592686e-03 + + -1.0470550060272217e+00 2.0222599804401398e-01 + <_> + + 0 -1 718 2.6420000940561295e-03 + + -5.0559401512145996e-01 3.6441200971603394e-01 + <_> + + 0 -1 719 -1.6925999894738197e-02 + + -9.9541902542114258e-01 1.2602199614048004e-01 + <_> + + 0 -1 720 2.8235999867320061e-02 + + -9.4137996435165405e-02 5.7780402898788452e-01 + <_> + + 0 -1 721 1.0428999550640583e-02 + + 2.3272900283336639e-01 -5.2569699287414551e-01 + <_> + + 0 -1 722 9.8860003054141998e-03 + + -1.0316299647092819e-01 4.7657600045204163e-01 + <_> + + 0 -1 723 2.6015000417828560e-02 + + -1.0920000495389104e-03 -1.5581729412078857e+00 + <_> + + 0 -1 724 -2.5537999346852303e-02 + + -6.5451401472091675e-01 1.8843199312686920e-01 + <_> + + 0 -1 725 -3.5310001112520695e-03 + + 2.8140598535537720e-01 -4.4575300812721252e-01 + <_> + + 0 -1 726 9.2449998483061790e-03 + + 1.5612000226974487e-01 -2.1370999515056610e-01 + <_> + + 0 -1 727 2.1030999720096588e-02 + + -2.9170298576354980e-01 5.2234101295471191e-01 + <_> + + 0 -1 728 -5.1063001155853271e-02 + + 1.3661290407180786e+00 3.0465999618172646e-02 + <_> + + 0 -1 729 -6.2330000102519989e-02 + + 1.2207020521163940e+00 -2.2434400022029877e-01 + <_> + + 0 -1 730 -3.2963000237941742e-02 + + -8.2016801834106445e-01 1.4531899988651276e-01 + <_> + + 0 -1 731 -3.7418000400066376e-02 + + -1.2218099832534790e+00 1.9448999315500259e-02 + <_> + + 0 -1 732 1.2402799725532532e-01 + + 1.2082300335168839e-01 -9.8729300498962402e-01 + <_> + + 0 -1 733 -8.9229997247457504e-03 + + -1.1688489913940430e+00 2.1105000749230385e-02 + <_> + + 0 -1 734 -5.9879999607801437e-02 + + -1.0689330101013184e+00 1.9860200583934784e-01 + <_> + + 0 -1 735 6.2620001845061779e-03 + + -3.6229598522186279e-01 3.8000801205635071e-01 + <_> + + 0 -1 736 -1.7673000693321228e-02 + + 4.9094098806381226e-01 -1.4606699347496033e-01 + <_> + + 0 -1 737 1.7579000443220139e-02 + + 5.8728098869323730e-01 -2.7774399518966675e-01 + <_> + + 0 -1 738 5.1560001447796822e-03 + + -7.5194999575614929e-02 6.0193097591400146e-01 + <_> + + 0 -1 739 -1.0599999688565731e-02 + + 2.7637401223182678e-01 -3.7794300913810730e-01 + <_> + + 0 -1 740 2.0884099602699280e-01 + + -5.3599998354911804e-03 1.0317809581756592e+00 + <_> + + 0 -1 741 -2.6412999257445335e-02 + + 8.2336401939392090e-01 -2.2480599582195282e-01 + <_> + + 0 -1 742 5.8892000466585159e-02 + + 1.3098299503326416e-01 -1.1853699684143066e+00 + <_> + + 0 -1 743 -1.1579000391066074e-02 + + -9.0667802095413208e-01 4.4126998633146286e-02 + <_> + + 0 -1 744 4.5988000929355621e-02 + + 1.0143999941647053e-02 1.0740900039672852e+00 + <_> + + 0 -1 745 -2.2838000208139420e-02 + + 1.7791990041732788e+00 -1.7315499484539032e-01 + <_> + + 0 -1 746 -8.1709995865821838e-03 + + 5.7386302947998047e-01 -7.4106000363826752e-02 + <_> + + 0 -1 747 3.5359999164938927e-03 + + -3.2072898745536804e-01 4.0182501077651978e-01 + <_> + + 0 -1 748 4.9444999545812607e-02 + + 1.9288000464439392e-01 -1.2166700363159180e+00 + <_> + + 0 -1 749 3.5139999818056822e-03 + + 6.9568000733852386e-02 -7.1323698759078979e-01 + <_> + + 0 -1 750 -3.0996000394225121e-02 + + -3.8862198591232300e-01 1.8098799884319305e-01 + <_> + + 0 -1 751 8.6452998220920563e-02 + + -2.5792999193072319e-02 -1.5453219413757324e+00 + <_> + + 0 -1 752 -1.3652600347995758e-01 + + -1.9199420213699341e+00 1.6613300144672394e-01 + <_> + + 0 -1 753 -5.7689999230206013e-03 + + -1.2822589874267578e+00 -1.5907999128103256e-02 + <_> + + 0 -1 754 -1.7899999395012856e-02 + + -4.0409898757934570e-01 2.3591600358486176e-01 + <_> + + 0 -1 755 -1.9969999790191650e-02 + + -7.2891902923583984e-01 5.6235000491142273e-02 + <_> + + 0 -1 756 -5.7493001222610474e-02 + + 5.7830798625946045e-01 -1.5796000137925148e-02 + <_> + + 0 -1 757 -8.3056002855300903e-02 + + 9.1511601209640503e-01 -2.1121400594711304e-01 + <_> + + 0 -1 758 -5.3771000355482101e-02 + + -5.1931297779083252e-01 1.8576000630855560e-01 + <_> + + 0 -1 759 -8.3670001477003098e-03 + + 2.4109700322151184e-01 -3.9648601412773132e-01 + <_> + + 0 -1 760 5.5406998842954636e-02 + + 1.6771200299263000e-01 -2.5664970874786377e+00 + <_> + + 0 -1 761 -6.7180998623371124e-02 + + -1.3658570051193237e+00 -1.4232000336050987e-02 + <_> + + 0 -1 762 -2.3900000378489494e-02 + + -1.7084569931030273e+00 1.6507799923419952e-01 + <_> + + 0 -1 763 5.5949999950826168e-03 + + -3.1373998522758484e-01 3.2837900519371033e-01 + <_> + + 0 -1 764 2.1294999867677689e-02 + + 1.4953400194644928e-01 -4.8579800128936768e-01 + <_> + + 0 -1 765 -2.4613000452518463e-02 + + 7.4346399307250977e-01 -2.2305199503898621e-01 + <_> + + 0 -1 766 -1.9626000896096230e-02 + + -4.0918299555778503e-01 1.8893200159072876e-01 + <_> + + 0 -1 767 -5.3266000002622604e-02 + + 8.1381601095199585e-01 -2.0853699743747711e-01 + <_> + + 0 -1 768 7.1290000341832638e-03 + + 3.2996100187301636e-01 -5.9937399625778198e-01 + <_> + + 0 -1 769 -2.2486999630928040e-02 + + -1.2551610469818115e+00 -2.0413000136613846e-02 + <_> + + 0 -1 770 -8.2310996949672699e-02 + + 1.3821430206298828e+00 5.9308998286724091e-02 + <_> + + 0 -1 771 1.3097000122070312e-01 + + -3.5843998193740845e-02 -1.5396369695663452e+00 + <_> + + 0 -1 772 1.4293000102043152e-02 + + -1.8475200235843658e-01 3.7455001473426819e-01 + <_> + + 0 -1 773 6.3479999080300331e-03 + + -4.4901099801063538e-01 1.3876999914646149e-01 + <_> + + 0 -1 774 -4.6055000275373459e-02 + + 6.7832601070404053e-01 -1.7071999609470367e-02 + <_> + + 0 -1 775 5.7693999260663986e-02 + + -1.1955999769270420e-02 -1.2261159420013428e+00 + <_> + + 0 -1 776 -6.0609998181462288e-03 + + 3.3958598971366882e-01 6.2800000887364149e-04 + <_> + + 0 -1 777 -5.2163001149892807e-02 + + -1.0621069669723511e+00 -1.3779999688267708e-02 + <_> + + 0 -1 778 4.6572998166084290e-02 + + 1.4538800716400146e-01 -1.2384550571441650e+00 + <_> + + 0 -1 779 7.5309998355805874e-03 + + -2.4467700719833374e-01 5.1377099752426147e-01 + <_> + + 0 -1 780 2.1615000441670418e-02 + + 1.3072599470615387e-01 -7.0996797084808350e-01 + <_> + + 0 -1 781 -1.7864000052213669e-02 + + -1.0474660396575928e+00 4.9599999329075217e-04 + <_> + + 0 -1 782 -3.7195000797510147e-02 + + -1.5126730203628540e+00 1.4801399409770966e-01 + <_> + + 0 -1 783 -3.1100001069717109e-04 + + 1.3971500098705292e-01 -4.6867498755455017e-01 + <_> + + 0 -1 784 2.5042999535799026e-02 + + 2.8632000088691711e-01 -4.1794699430465698e-01 + <_> + + 0 -1 785 9.3449996784329414e-03 + + -2.7336201071739197e-01 4.3444699048995972e-01 + <_> + + 0 -1 786 3.2363999634981155e-02 + + 1.8438899517059326e-01 -9.5019298791885376e-01 + <_> + + 0 -1 787 -6.2299999408423901e-03 + + 3.2581999897956848e-01 -3.0815601348876953e-01 + <_> + + 0 -1 788 5.1488999277353287e-02 + + 1.1416000127792358e-01 -1.9795479774475098e+00 + <_> + + 0 -1 789 -2.6449000462889671e-02 + + -1.1067299842834473e+00 -8.5519999265670776e-03 + <_> + + 0 -1 790 -1.5420000068843365e-02 + + 8.0138701200485229e-01 -3.2035000622272491e-02 + <_> + + 0 -1 791 1.9456999376416206e-02 + + -2.6449498534202576e-01 3.8753899931907654e-01 + <_> + + 0 -1 792 3.3620998263359070e-02 + + 1.6052000224590302e-02 5.8840900659561157e-01 + <_> + + 0 -1 793 2.8906000778079033e-02 + + 1.5216000378131866e-02 -9.4723600149154663e-01 + <_> + + 0 -1 794 2.0300000323913991e-04 + + -3.0766001343727112e-01 2.1235899627208710e-01 + <_> + + 0 -1 795 -4.9141999334096909e-02 + + -1.6058609485626221e+00 -3.1094999983906746e-02 + <_> + + 0 -1 796 7.6425999402999878e-02 + + 7.4758999049663544e-02 1.1639410257339478e+00 + <_> + + 0 -1 797 2.3897999897599220e-02 + + -6.4320000819861889e-03 -1.1150749921798706e+00 + <_> + + 0 -1 798 3.8970001041889191e-03 + + -2.4105699360370636e-01 2.0858900249004364e-01 + <_> + + 0 -1 799 -8.9445002377033234e-02 + + 1.9157789945602417e+00 -1.5721100568771362e-01 + <_> + + 0 -1 800 -1.5008999966084957e-02 + + -2.5174099206924438e-01 1.8179899454116821e-01 + <_> + + 0 -1 801 -1.1145999655127525e-02 + + -6.9349497556686401e-01 4.4927999377250671e-02 + <_> + + 0 -1 802 9.4578996300697327e-02 + + 1.8102100491523743e-01 -7.4978601932525635e-01 + <_> + + 0 -1 803 5.5038899183273315e-01 + + -3.0974000692367554e-02 -1.6746139526367188e+00 + <_> + + 0 -1 804 4.1381001472473145e-02 + + 6.3910000026226044e-02 7.6561200618743896e-01 + <_> + + 0 -1 805 2.4771999567747116e-02 + + 1.1380000039935112e-02 -8.8559401035308838e-01 + <_> + + 0 -1 806 5.0999000668525696e-02 + + 1.4890299737453461e-01 -2.4634211063385010e+00 + <_> + + 0 -1 807 -1.6893999651074409e-02 + + 3.8870999217033386e-01 -2.9880300164222717e-01 + <_> + + 0 -1 808 -1.2162300199270248e-01 + + -1.5542800426483154e+00 1.6300800442695618e-01 + <_> + + 0 -1 809 -3.6049999762326479e-03 + + 2.1842800080776215e-01 -3.7312099337577820e-01 + <_> + + 0 -1 810 1.1575400084257126e-01 + + -4.7061000019311905e-02 5.9403699636459351e-01 + <_> + + 0 -1 811 3.6903999745845795e-02 + + -2.5508600473403931e-01 5.5397301912307739e-01 + <_> + + 0 -1 812 1.1483999900519848e-02 + + -1.8129499256610870e-01 4.0682798624038696e-01 + <_> + + 0 -1 813 -2.0233999937772751e-02 + + 5.4311197996139526e-01 -2.3822399973869324e-01 + <_> + + 0 -1 814 -2.8765000402927399e-02 + + -6.9172298908233643e-01 1.5943300724029541e-01 + <_> + + 0 -1 815 -5.8320001699030399e-03 + + 2.9447799921035767e-01 -3.4005999565124512e-01 + <_> + + 0 -1 816 -5.5468998849391937e-02 + + 9.2200797796249390e-01 9.4093002378940582e-02 + <_> + + 0 -1 817 -1.4801000244915485e-02 + + -7.9539698362350464e-01 3.1521998345851898e-02 + <_> + + 0 -1 818 -7.0940000005066395e-03 + + 3.3096000552177429e-01 -5.0886999815702438e-02 + <_> + + 0 -1 819 -4.5124001801013947e-02 + + -1.3719749450683594e+00 -2.1408999338746071e-02 + <_> + + 0 -1 820 6.4377002418041229e-02 + + 6.3901998102664948e-02 9.1478300094604492e-01 + <_> + + 0 -1 821 -1.4727000147104263e-02 + + 3.6050599813461304e-01 -2.8614500164985657e-01 + <_> + + 0 -1 822 4.5007001608610153e-02 + + -1.5619699656963348e-01 5.3160297870635986e-01 + <_> + + 0 -1 823 -1.1330000124871731e-03 + + 1.3422900438308716e-01 -4.4358900189399719e-01 + <_> + + 0 -1 824 4.9451000988483429e-02 + + 1.0571800172328949e-01 -2.5589139461517334e+00 + <_> + + 0 -1 825 2.9102999716997147e-02 + + -1.0088000446557999e-02 -1.1073939800262451e+00 + <_> + + 0 -1 826 3.4786000847816467e-02 + + -2.7719999197870493e-03 5.6700998544692993e-01 + <_> + + 0 -1 827 -6.1309998854994774e-03 + + -4.6889400482177734e-01 1.2636399269104004e-01 + <_> + + 0 -1 828 1.5525000169873238e-02 + + -8.4279999136924744e-03 8.7469202280044556e-01 + <_> + + 0 -1 829 2.9249999206513166e-03 + + -3.4434300661087036e-01 2.0851600170135498e-01 + <_> + + 0 -1 830 -5.3571000695228577e-02 + + 1.4982949495315552e+00 5.7328000664710999e-02 + <_> + + 0 -1 831 -1.9217999652028084e-02 + + -9.9234098196029663e-01 -9.3919998034834862e-03 + <_> + + 0 -1 832 -5.5282998830080032e-02 + + -5.7682299613952637e-01 1.6860599815845490e-01 + <_> + + 0 -1 833 5.6336000561714172e-02 + + -3.3775001764297485e-02 -1.3889650106430054e+00 + <_> + + 0 -1 834 -2.3824000731110573e-02 + + 4.0182098746299744e-01 1.8360000103712082e-03 + <_> + + 0 -1 835 1.7810000572353601e-03 + + 1.8145999312400818e-01 -4.1743400692939758e-01 + <_> + + 0 -1 836 -3.7689000368118286e-02 + + 5.4683101177215576e-01 1.8219999969005585e-02 + <_> + + 0 -1 837 -2.4144999682903290e-02 + + 6.8352097272872925e-01 -1.9650200009346008e-01 + <_> + 135 + -3.7025990486145020e+00 + + <_> + + 0 -1 838 2.7444999665021896e-02 + + -8.9984202384948730e-01 5.1876497268676758e-01 + <_> + + 0 -1 839 1.1554100364446640e-01 + + -5.6524401903152466e-01 7.0551300048828125e-01 + <_> + + 0 -1 840 -2.2297000512480736e-02 + + 3.6079999804496765e-01 -6.6864597797393799e-01 + <_> + + 0 -1 841 1.3325000181794167e-02 + + -5.5573397874832153e-01 3.5789999365806580e-01 + <_> + + 0 -1 842 -3.8060001097619534e-03 + + -1.0713000297546387e+00 1.8850000202655792e-01 + <_> + + 0 -1 843 -2.6819999329745770e-03 + + -7.1584302186965942e-01 2.6344498991966248e-01 + <_> + + 0 -1 844 3.3819999080151320e-03 + + -4.6930798888206482e-01 2.6658400893211365e-01 + <_> + + 0 -1 845 3.7643000483512878e-02 + + 2.1098700165748596e-01 -1.0804339647293091e+00 + <_> + + 0 -1 846 -1.3861999846994877e-02 + + 6.6912001371383667e-01 -2.7942800521850586e-01 + <_> + + 0 -1 847 -2.7350001037120819e-03 + + -9.5332300662994385e-01 2.4051299691200256e-01 + <_> + + 0 -1 848 -3.8336999714374542e-02 + + 8.1432801485061646e-01 -2.4919399619102478e-01 + <_> + + 0 -1 849 -3.4697998315095901e-02 + + 1.2330100536346436e+00 6.8600000813603401e-03 + <_> + + 0 -1 850 2.3360999301075935e-02 + + -3.0794700980186462e-01 7.0714497566223145e-01 + <_> + + 0 -1 851 3.5057999193668365e-02 + + 2.1205900609493256e-01 -1.4399830102920532e+00 + <_> + + 0 -1 852 -1.3256999664008617e-02 + + -9.0260702371597290e-01 4.8610001802444458e-02 + <_> + + 0 -1 853 1.2740000151097775e-02 + + 2.2655199468135834e-01 -4.4643801450729370e-01 + <_> + + 0 -1 854 3.6400000099092722e-03 + + -3.9817899465560913e-01 3.4665399789810181e-01 + <_> + + 0 -1 855 1.0064700245857239e-01 + + 1.8383599817752838e-01 -1.3410769701004028e+00 + <_> + + 0 -1 856 0. + + 1.5536400675773621e-01 -5.1582497358322144e-01 + <_> + + 0 -1 857 1.1708999983966351e-02 + + 2.1651400625705719e-01 -7.2705197334289551e-01 + <_> + + 0 -1 858 -3.5964999347925186e-02 + + -1.4789500236511230e+00 -2.4317000061273575e-02 + <_> + + 0 -1 859 -2.1236000582575798e-02 + + -1.6844099760055542e-01 1.9526599347591400e-01 + <_> + + 0 -1 860 1.4874000102281570e-02 + + 3.7335999310016632e-02 -8.7557297945022583e-01 + <_> + + 0 -1 861 -5.1409997977316380e-03 + + 3.3466500043869019e-01 -2.4109700322151184e-01 + <_> + + 0 -1 862 2.3450000211596489e-02 + + 5.5320002138614655e-03 -1.2509720325469971e+00 + <_> + + 0 -1 863 -2.5062000378966331e-02 + + 4.5212399959564209e-01 -8.4469996392726898e-02 + <_> + + 0 -1 864 -7.7400001464411616e-04 + + 1.5249900519847870e-01 -4.8486500978469849e-01 + <_> + + 0 -1 865 -4.0483999997377396e-02 + + -1.3024920225143433e+00 1.7983500659465790e-01 + <_> + + 0 -1 866 2.8170999139547348e-02 + + -2.4410900473594666e-01 6.2271100282669067e-01 + <_> + + 0 -1 867 4.5692998915910721e-02 + + 2.8122000396251678e-02 9.2394399642944336e-01 + <_> + + 0 -1 868 3.9707001298666000e-02 + + -2.2332799434661865e-01 7.7674001455307007e-01 + <_> + + 0 -1 869 5.0517000257968903e-02 + + 2.0319999754428864e-01 -1.0895930528640747e+00 + <_> + + 0 -1 870 -1.7266999930143356e-02 + + 6.8598401546478271e-01 -2.3304499685764313e-01 + <_> + + 0 -1 871 8.0186001956462860e-02 + + -1.0292000137269497e-02 6.1881101131439209e-01 + <_> + + 0 -1 872 9.7676001489162445e-02 + + -2.0070299506187439e-01 1.0088349580764771e+00 + <_> + + 0 -1 873 -1.5572000294923782e-02 + + 4.7615298628807068e-01 4.5623999089002609e-02 + <_> + + 0 -1 874 -1.5305000357329845e-02 + + -1.1077369451522827e+00 4.5239999890327454e-03 + <_> + + 0 -1 875 -1.6485000029206276e-02 + + 1.0152939558029175e+00 1.6327999532222748e-02 + <_> + + 0 -1 876 -2.6141999289393425e-02 + + 4.1723299026489258e-01 -2.8645500540733337e-01 + <_> + + 0 -1 877 8.8679995387792587e-03 + + 2.1404999494552612e-01 -1.6772800683975220e-01 + <_> + + 0 -1 878 -2.6886999607086182e-02 + + -1.1564220190048218e+00 -1.0324000380933285e-02 + <_> + + 0 -1 879 7.7789998613297939e-03 + + 3.5359498858451843e-01 -2.9611301422119141e-01 + <_> + + 0 -1 880 -1.5974000096321106e-02 + + -1.5374109745025635e+00 -2.9958000406622887e-02 + <_> + + 0 -1 881 2.0866999402642250e-02 + + 2.0244100689888000e-01 -7.1270197629928589e-01 + <_> + + 0 -1 882 8.5482001304626465e-02 + + -2.5932999327778816e-02 -1.5156569480895996e+00 + <_> + + 0 -1 883 2.3872999474406242e-02 + + 1.6803400218486786e-01 -3.8806200027465820e-01 + <_> + + 0 -1 884 -3.9105001837015152e-02 + + -1.1958349943161011e+00 -2.0361000671982765e-02 + <_> + + 0 -1 885 -7.7946998178958893e-02 + + -1.0898950099945068e+00 1.4530299603939056e-01 + <_> + + 0 -1 886 -1.6876000910997391e-02 + + 2.8049701452255249e-01 -4.1336300969123840e-01 + <_> + + 0 -1 887 1.1875600367784500e-01 + + -4.3490998446941376e-02 4.1263699531555176e-01 + <_> + + 0 -1 888 1.5624199807643890e-01 + + -2.6429599523544312e-01 5.5127799510955811e-01 + <_> + + 0 -1 889 -4.5908000320196152e-02 + + 6.0189199447631836e-01 1.8921000882983208e-02 + <_> + + 0 -1 890 -1.0309999808669090e-02 + + 3.8152998685836792e-01 -2.9507899284362793e-01 + <_> + + 0 -1 891 9.5769003033638000e-02 + + 1.3246500492095947e-01 -4.6266800165176392e-01 + <_> + + 0 -1 892 1.3686999678611755e-02 + + 1.1738699674606323e-01 -5.1664102077484131e-01 + <_> + + 0 -1 893 2.3990001063793898e-03 + + -3.4007599949836731e-01 2.0953500270843506e-01 + <_> + + 0 -1 894 3.3264998346567154e-02 + + -1.7052799463272095e-01 1.4366799592971802e+00 + <_> + + 0 -1 895 -3.3206000924110413e-02 + + 6.1295700073242188e-01 -4.1549999266862869e-02 + <_> + + 0 -1 896 2.7979998849332333e-03 + + -4.8554301261901855e-01 1.3372699916362762e-01 + <_> + + 0 -1 897 -6.5792001783847809e-02 + + -4.0257668495178223e+00 1.0876700282096863e-01 + <_> + + 0 -1 898 2.1430000197142363e-03 + + -3.9179998636245728e-01 2.2427099943161011e-01 + <_> + + 0 -1 899 2.2363999858498573e-02 + + -8.6429998278617859e-02 3.7785199284553528e-01 + <_> + + 0 -1 900 -5.7410001754760742e-02 + + 1.1454069614410400e+00 -1.9736599922180176e-01 + <_> + + 0 -1 901 6.6550001502037048e-03 + + -2.1105000749230385e-02 5.8453398942947388e-01 + <_> + + 0 -1 902 1.2326999567449093e-02 + + 3.7817001342773438e-02 -6.6987001895904541e-01 + <_> + + 0 -1 903 -8.1869997084140778e-03 + + 5.6366002559661865e-01 -7.6877996325492859e-02 + <_> + + 0 -1 904 3.6681000143289566e-02 + + -1.7343300580978394e-01 1.1670149564743042e+00 + <_> + + 0 -1 905 -4.0220400691032410e-01 + + 1.2640819549560547e+00 4.3398998677730560e-02 + <_> + + 0 -1 906 -2.2126000374555588e-02 + + 6.6978102922439575e-01 -2.1605299413204193e-01 + <_> + + 0 -1 907 -1.3156999833881855e-02 + + -4.1198599338531494e-01 2.0215000212192535e-01 + <_> + + 0 -1 908 -1.2860000133514404e-02 + + -9.1582697629928589e-01 3.9232999086380005e-02 + <_> + + 0 -1 909 2.1627999842166901e-02 + + 3.8719999138265848e-03 3.5668200254440308e-01 + <_> + + 0 -1 910 1.1896000243723392e-02 + + -3.7303900718688965e-01 1.9235099852085114e-01 + <_> + + 0 -1 911 -1.9548999145627022e-02 + + -4.2374899983406067e-01 2.4429599940776825e-01 + <_> + + 0 -1 912 6.4444996416568756e-02 + + -1.6558900475502014e-01 1.2697030305862427e+00 + <_> + + 0 -1 913 1.0898499935865402e-01 + + 1.4894300699234009e-01 -2.1534640789031982e+00 + <_> + + 0 -1 914 -3.4077998250722885e-02 + + 1.3779460191726685e+00 -1.6198499500751495e-01 + <_> + + 0 -1 915 -3.7489999085664749e-03 + + -3.3828601241111755e-01 2.1152900159358978e-01 + <_> + + 0 -1 916 -1.0971999727189541e-02 + + 7.6517897844314575e-01 -1.9692599773406982e-01 + <_> + + 0 -1 917 -1.1485000140964985e-02 + + -6.9271200895309448e-01 2.1657100319862366e-01 + <_> + + 0 -1 918 2.5984000414609909e-02 + + -1.1983999982476234e-02 -9.9697297811508179e-01 + <_> + + 0 -1 919 4.2159999720752239e-03 + + -1.0205700248479843e-01 4.8884400725364685e-01 + <_> + + 0 -1 920 -4.7697000205516815e-02 + + 1.0666010379791260e+00 -1.7576299607753754e-01 + <_> + + 0 -1 921 4.0300001273863018e-04 + + 1.8524800240993500e-01 -7.4790000915527344e-01 + <_> + + 0 -1 922 1.1539600044488907e-01 + + -2.2019700706005096e-01 5.4509997367858887e-01 + <_> + + 0 -1 923 1.6021000221371651e-02 + + 2.5487500429153442e-01 -5.0740098953247070e-01 + <_> + + 0 -1 924 5.6632000952959061e-02 + + -1.1256000027060509e-02 -9.5968097448348999e-01 + <_> + + 0 -1 925 -1.0726000182330608e-02 + + -2.8544700145721436e-01 1.6994799673557281e-01 + <_> + + 0 -1 926 1.2420000135898590e-01 + + -3.6139998584985733e-02 -1.3132710456848145e+00 + <_> + + 0 -1 927 -5.3799999877810478e-03 + + 3.3092701435089111e-01 1.3307999819517136e-02 + <_> + + 0 -1 928 1.1908000335097313e-02 + + -3.4830299019813538e-01 2.4041900038719177e-01 + <_> + + 0 -1 929 -4.3007999658584595e-02 + + -1.4390469789505005e+00 1.5599599480628967e-01 + <_> + + 0 -1 930 -3.3149998635053635e-02 + + -1.1805850267410278e+00 -1.2347999960184097e-02 + <_> + + 0 -1 931 -2.1341999992728233e-02 + + 2.2119441032409668e+00 6.2737002968788147e-02 + <_> + + 0 -1 932 -1.2218999676406384e-02 + + -1.8709750175476074e+00 -4.5499999076128006e-02 + <_> + + 0 -1 933 -1.6860999166965485e-02 + + -7.6912701129913330e-01 1.5330000221729279e-01 + <_> + + 0 -1 934 -2.4999999441206455e-03 + + -6.2987399101257324e-01 5.1600001752376556e-02 + <_> + + 0 -1 935 -4.5037999749183655e-02 + + 8.5428899526596069e-01 6.2600001692771912e-03 + <_> + + 0 -1 936 3.9057999849319458e-02 + + -3.2458998262882233e-02 -1.3325669765472412e+00 + <_> + + 0 -1 937 6.6720000468194485e-03 + + -1.9423599541187286e-01 3.7328699231147766e-01 + <_> + + 0 -1 938 -1.6361000016331673e-02 + + 2.0605869293212891e+00 -1.5042699873447418e-01 + <_> + + 0 -1 939 6.1719999648630619e-03 + + -1.1610999703407288e-01 2.5455400347709656e-01 + <_> + + 0 -1 940 4.5722000300884247e-02 + + -1.6340000554919243e-02 -1.0449140071868896e+00 + <_> + + 0 -1 941 4.1209999471902847e-03 + + -4.1997998952865601e-02 3.9680999517440796e-01 + <_> + + 0 -1 942 -1.7800000205170363e-04 + + -6.6422599554061890e-01 3.3443000167608261e-02 + <_> + + 0 -1 943 7.1109998971223831e-03 + + -5.8231998234987259e-02 3.7857300043106079e-01 + <_> + + 0 -1 944 -4.9864001572132111e-02 + + 6.1019402742385864e-01 -2.1005700528621674e-01 + <_> + + 0 -1 945 -2.5011999532580376e-02 + + -5.7100099325180054e-01 1.7848399281501770e-01 + <_> + + 0 -1 946 3.0939999967813492e-02 + + 5.6363001465797424e-02 -6.4731001853942871e-01 + <_> + + 0 -1 947 4.6271000057458878e-02 + + 1.7482399940490723e-01 -9.8909401893615723e-01 + <_> + + 0 -1 948 -3.1870000530034304e-03 + + -6.6804802417755127e-01 3.2267000526189804e-02 + <_> + + 0 -1 949 -2.4351999163627625e-02 + + 2.9444900155067444e-01 -1.3599999947473407e-03 + <_> + + 0 -1 950 1.1974000371992588e-02 + + -2.8345099091529846e-01 4.7171199321746826e-01 + <_> + + 0 -1 951 1.3070000335574150e-02 + + -1.0834600031375885e-01 5.7193297147750854e-01 + <_> + + 0 -1 952 5.9163000434637070e-02 + + -5.0939001142978668e-02 -1.9059720039367676e+00 + <_> + + 0 -1 953 -4.1094999760389328e-02 + + 4.5104598999023438e-01 -9.7599998116493225e-03 + <_> + + 0 -1 954 -8.3989001810550690e-02 + + -2.0349199771881104e+00 -5.1019001752138138e-02 + <_> + + 0 -1 955 4.4619001448154449e-02 + + 1.7041100561618805e-01 -1.2278720140457153e+00 + <_> + + 0 -1 956 2.4419000372290611e-02 + + -2.1796999499201775e-02 -1.0822949409484863e+00 + <_> + + 0 -1 957 -4.3870001100003719e-03 + + 3.0466699600219727e-01 -3.7066599726676941e-01 + <_> + + 0 -1 958 2.4607999250292778e-02 + + -3.1169500946998596e-01 2.3657299578189850e-01 + <_> + + 0 -1 959 -8.5182003676891327e-02 + + -1.7982350587844849e+00 1.5254299342632294e-01 + <_> + + 0 -1 960 2.1844999864697456e-02 + + -5.1888000220060349e-02 -1.9017189741134644e+00 + <_> + + 0 -1 961 -1.6829000785946846e-02 + + 2.1025900542736053e-01 2.1656999364495277e-02 + <_> + + 0 -1 962 3.2547999173402786e-02 + + -2.0292599499225616e-01 6.0944002866744995e-01 + <_> + + 0 -1 963 2.4709999561309814e-03 + + -9.5371198654174805e-01 1.8568399548530579e-01 + <_> + + 0 -1 964 5.5415999144315720e-02 + + -1.4405299723148346e-01 2.1506340503692627e+00 + <_> + + 0 -1 965 -1.0635499656200409e-01 + + -1.0911970138549805e+00 1.3228000700473785e-01 + <_> + + 0 -1 966 -7.9889995977282524e-03 + + 1.0253400355577469e-01 -5.1744902133941650e-01 + <_> + + 0 -1 967 7.5567997992038727e-02 + + 5.8965001255273819e-02 1.2354209423065186e+00 + <_> + + 0 -1 968 -9.2805996537208557e-02 + + -1.3431650400161743e+00 -3.4462999552488327e-02 + <_> + + 0 -1 969 4.9431998282670975e-02 + + 4.9601998180150986e-02 1.6054730415344238e+00 + <_> + + 0 -1 970 -1.1772999539971352e-02 + + -1.0261050462722778e+00 -4.1559999808669090e-03 + <_> + + 0 -1 971 8.5886001586914062e-02 + + 8.4642998874187469e-02 9.5220798254013062e-01 + <_> + + 0 -1 972 8.1031002104282379e-02 + + -1.4687100052833557e-01 1.9359990358352661e+00 + <_> + 136 + -3.4265899658203125e+00 + + <_> + + 0 -1 973 -3.3840999007225037e-02 + + 6.5889501571655273e-01 -6.9755297899246216e-01 + <_> + + 0 -1 974 1.5410000458359718e-02 + + -9.0728402137756348e-01 3.0478599667549133e-01 + <_> + + 0 -1 975 5.4905999451875687e-02 + + -4.9774798750877380e-01 5.7132601737976074e-01 + <_> + + 0 -1 976 2.1390000358223915e-02 + + -4.2565199732780457e-01 5.8096802234649658e-01 + <_> + + 0 -1 977 7.8849997371435165e-03 + + -4.7905999422073364e-01 4.3016499280929565e-01 + <_> + + 0 -1 978 -3.7544999271631241e-02 + + 5.0861597061157227e-01 -1.9985899329185486e-01 + <_> + + 0 -1 979 1.5925799310207367e-01 + + -2.3263600468635559e-01 1.0993319749832153e+00 + <_> + + 0 -1 980 -6.8939998745918274e-02 + + 4.0569001436233521e-01 5.6855000555515289e-02 + <_> + + 0 -1 981 -3.3695001155138016e-02 + + 4.5132800936698914e-01 -3.3332800865173340e-01 + <_> + + 0 -1 982 -6.3314996659755707e-02 + + -8.5015702247619629e-01 2.2341699898242950e-01 + <_> + + 0 -1 983 7.3699997738003731e-03 + + -9.3082201480865479e-01 5.9216998517513275e-02 + <_> + + 0 -1 984 -9.5969997346401215e-03 + + -1.2794899940490723e+00 1.8447299301624298e-01 + <_> + + 0 -1 985 -1.3067999482154846e-01 + + 5.8426898717880249e-01 -2.6007199287414551e-01 + <_> + + 0 -1 986 5.7402998208999634e-02 + + -5.3789000958204269e-02 7.1175599098205566e-01 + <_> + + 0 -1 987 -7.2340001352131367e-03 + + -8.6962199211120605e-01 7.5214996933937073e-02 + <_> + + 0 -1 988 3.1098999083042145e-02 + + -7.5006999075412750e-02 9.0781599283218384e-01 + <_> + + 0 -1 989 3.5854000598192215e-02 + + -2.4795499444007874e-01 7.2272098064422607e-01 + <_> + + 0 -1 990 -3.1534999608993530e-02 + + -1.1238329410552979e+00 2.0988300442695618e-01 + <_> + + 0 -1 991 -1.9437000155448914e-02 + + -1.4499390125274658e+00 -1.5100000426173210e-02 + <_> + + 0 -1 992 -7.2420001961290836e-03 + + 5.3864902257919312e-01 -1.1375399678945541e-01 + <_> + + 0 -1 993 8.1639997661113739e-03 + + 6.6889002919197083e-02 -7.6872897148132324e-01 + <_> + + 0 -1 994 -4.3653000146150589e-02 + + 1.1413530111312866e+00 4.0217000991106033e-02 + <_> + + 0 -1 995 2.6569999754428864e-02 + + -2.4719099700450897e-01 5.9295099973678589e-01 + <_> + + 0 -1 996 3.2216999679803848e-02 + + -4.0024999529123306e-02 3.2688000798225403e-01 + <_> + + 0 -1 997 -7.2236001491546631e-02 + + 5.8729398250579834e-01 -2.5396001338958740e-01 + <_> + + 0 -1 998 3.1424999237060547e-02 + + 1.5315100550651550e-01 -5.6042098999023438e-01 + <_> + + 0 -1 999 -4.7699999413453043e-04 + + 1.6958899796009064e-01 -5.2626699209213257e-01 + <_> + + 0 -1 1000 2.7189999818801880e-03 + + -1.4944599568843842e-01 2.9658699035644531e-01 + <_> + + 0 -1 1001 3.2875001430511475e-02 + + -3.9943501353263855e-01 2.5156599283218384e-01 + <_> + + 0 -1 1002 -1.4553000219166279e-02 + + 2.7972599864006042e-01 -4.7203800082206726e-01 + <_> + + 0 -1 1003 3.8017999380826950e-02 + + -2.9200001154094934e-03 -1.1300059556961060e+00 + <_> + + 0 -1 1004 2.8659999370574951e-03 + + 4.1111800074577332e-01 -2.6220801472663879e-01 + <_> + + 0 -1 1005 -4.1606999933719635e-02 + + -1.4293819665908813e+00 -1.9132999703288078e-02 + <_> + + 0 -1 1006 -2.4802999570965767e-02 + + -2.5013598799705505e-01 1.5978699922561646e-01 + <_> + + 0 -1 1007 1.0098000057041645e-02 + + 4.3738998472690582e-02 -6.9986099004745483e-01 + <_> + + 0 -1 1008 -2.0947000011801720e-02 + + -9.4137799739837646e-01 2.3204000294208527e-01 + <_> + + 0 -1 1009 2.2458000108599663e-02 + + -2.7185800671577454e-01 4.5319199562072754e-01 + <_> + + 0 -1 1010 -3.7110999226570129e-02 + + -1.0314660072326660e+00 1.4421799778938293e-01 + <_> + + 0 -1 1011 -1.0648000054061413e-02 + + 6.3107001781463623e-01 -2.5520798563957214e-01 + <_> + + 0 -1 1012 5.5422998964786530e-02 + + 1.6206599771976471e-01 -1.7722640037536621e+00 + <_> + + 0 -1 1013 2.1601999178528786e-02 + + -2.5016099214553833e-01 5.4119801521301270e-01 + <_> + + 0 -1 1014 8.7000000348780304e-05 + + -2.9008901119232178e-01 3.3507999777793884e-01 + <_> + + 0 -1 1015 1.4406000263988972e-02 + + -7.8840004280209541e-03 -1.1677219867706299e+00 + <_> + + 0 -1 1016 1.0777399688959122e-01 + + 1.1292000114917755e-01 -2.4940319061279297e+00 + <_> + + 0 -1 1017 3.5943999886512756e-02 + + -1.9480599462985992e-01 9.5757502317428589e-01 + <_> + + 0 -1 1018 -3.9510000497102737e-03 + + 3.0927801132202148e-01 -2.5530201196670532e-01 + <_> + + 0 -1 1019 2.0942000672221184e-02 + + -7.6319999061524868e-03 -1.0086350440979004e+00 + <_> + + 0 -1 1020 -2.9877999797463417e-02 + + -4.6027699112892151e-01 1.9507199525833130e-01 + <_> + + 0 -1 1021 2.5971999391913414e-02 + + -1.2187999673187733e-02 -1.0035500526428223e+00 + <_> + + 0 -1 1022 1.0603000409901142e-02 + + -7.5969003140926361e-02 4.1669899225234985e-01 + <_> + + 0 -1 1023 8.5819996893405914e-03 + + -2.6648598909378052e-01 3.9111500978469849e-01 + <_> + + 0 -1 1024 2.1270999684929848e-02 + + 1.8273900449275970e-01 -3.6052298545837402e-01 + <_> + + 0 -1 1025 7.4518002569675446e-02 + + -1.8938399851322174e-01 9.2658001184463501e-01 + <_> + + 0 -1 1026 4.6569998376071453e-03 + + -1.4506199955940247e-01 3.3294600248336792e-01 + <_> + + 0 -1 1027 1.7119999974966049e-03 + + -5.2464002370834351e-01 8.9879997074604034e-02 + <_> + + 0 -1 1028 9.8500004969537258e-04 + + -3.8381999731063843e-01 2.4392999708652496e-01 + <_> + + 0 -1 1029 2.8233999386429787e-02 + + -5.7879998348653316e-03 -1.2617139816284180e+00 + <_> + + 0 -1 1030 -3.2678000628948212e-02 + + -5.7953298091888428e-01 1.6955299675464630e-01 + <_> + + 0 -1 1031 2.2536000236868858e-02 + + 2.2281000390648842e-02 -8.7869602441787720e-01 + <_> + + 0 -1 1032 -2.1657999604940414e-02 + + -6.5108501911163330e-01 1.2966899573802948e-01 + <_> + + 0 -1 1033 7.6799998059868813e-03 + + -3.3965200185775757e-01 2.2013300657272339e-01 + <_> + + 0 -1 1034 1.4592000283300877e-02 + + 1.5077300369739532e-01 -5.0452399253845215e-01 + <_> + + 0 -1 1035 2.7868000790476799e-02 + + -2.5045299530029297e-01 4.5741999149322510e-01 + <_> + + 0 -1 1036 5.6940000504255295e-03 + + -1.0948500037193298e-01 5.5757802724838257e-01 + <_> + + 0 -1 1037 -1.0002999566495419e-02 + + -9.7366297245025635e-01 1.8467999994754791e-02 + <_> + + 0 -1 1038 -4.0719998069107533e-03 + + 3.8222199678421021e-01 -1.6921100020408630e-01 + <_> + + 0 -1 1039 -2.2593999281525612e-02 + + -1.0391089916229248e+00 5.1839998923242092e-03 + <_> + + 0 -1 1040 -3.9579998701810837e-02 + + -5.5109229087829590e+00 1.1163999885320663e-01 + <_> + + 0 -1 1041 -1.7537999898195267e-02 + + 9.5485800504684448e-01 -1.8584500253200531e-01 + <_> + + 0 -1 1042 9.0300003066658974e-03 + + 1.0436000302433968e-02 8.2114797830581665e-01 + <_> + + 0 -1 1043 -7.9539995640516281e-03 + + 2.2632899880409241e-01 -3.4568199515342712e-01 + <_> + + 0 -1 1044 2.7091000229120255e-02 + + 1.6430099308490753e-01 -1.3926379680633545e+00 + <_> + + 0 -1 1045 -2.0625999197363853e-02 + + -8.6366099119186401e-01 2.3880000226199627e-03 + <_> + + 0 -1 1046 -7.1989998221397400e-02 + + -2.8192629814147949e+00 1.1570499837398529e-01 + <_> + + 0 -1 1047 -2.6964999735355377e-02 + + -1.2946130037307739e+00 -2.4661000818014145e-02 + <_> + + 0 -1 1048 -4.7377999871969223e-02 + + -8.1306397914886475e-01 1.1831399798393250e-01 + <_> + + 0 -1 1049 -1.0895600169897079e-01 + + 6.5937900543212891e-01 -2.0843900740146637e-01 + <_> + + 0 -1 1050 1.3574000447988510e-02 + + 7.4240001849830151e-03 5.3152197599411011e-01 + <_> + + 0 -1 1051 -6.6920001991093159e-03 + + 3.0655801296234131e-01 -3.1084299087524414e-01 + <_> + + 0 -1 1052 -3.9070001803338528e-03 + + 2.5576499104499817e-01 -5.2932001650333405e-02 + <_> + + 0 -1 1053 -3.7613000720739365e-02 + + -1.4350049495697021e+00 -1.5448000282049179e-02 + <_> + + 0 -1 1054 8.6329998448491096e-03 + + -1.6884399950504303e-01 4.2124900221824646e-01 + <_> + + 0 -1 1055 -3.2097000628709793e-02 + + -6.4979398250579834e-01 4.1110001504421234e-02 + <_> + + 0 -1 1056 5.8495998382568359e-02 + + -5.2963998168706894e-02 6.3368302583694458e-01 + <_> + + 0 -1 1057 -4.0901999920606613e-02 + + -9.2101097106933594e-01 9.0640000998973846e-03 + <_> + + 0 -1 1058 -1.9925000146031380e-02 + + 5.3759998083114624e-01 -6.2996998429298401e-02 + <_> + + 0 -1 1059 -4.6020001173019409e-03 + + -5.4333502054214478e-01 8.4104999899864197e-02 + <_> + + 0 -1 1060 1.6824999824166298e-02 + + 1.5563699603080750e-01 -4.0171200037002563e-01 + <_> + + 0 -1 1061 9.4790002331137657e-03 + + -2.4245299398899078e-01 5.1509499549865723e-01 + <_> + + 0 -1 1062 -1.9534999504685402e-02 + + -5.1118397712707520e-01 1.3831999897956848e-01 + <_> + + 0 -1 1063 1.0746000334620476e-02 + + -2.1854999661445618e-01 6.2828701734542847e-01 + <_> + + 0 -1 1064 3.7927001714706421e-02 + + 1.1640299856662750e-01 -2.7301959991455078e+00 + <_> + + 0 -1 1065 1.6390999779105186e-02 + + -1.4635999687016010e-02 -1.0797250270843506e+00 + <_> + + 0 -1 1066 -1.9785000011324883e-02 + + 1.2166420221328735e+00 3.3275000751018524e-02 + <_> + + 0 -1 1067 1.1067000217735767e-02 + + -2.5388300418853760e-01 4.4038599729537964e-01 + <_> + + 0 -1 1068 5.2479999139904976e-03 + + 2.2496800124645233e-01 -2.4216499924659729e-01 + <_> + + 0 -1 1069 -1.1141999624669552e-02 + + 2.5018098950386047e-01 -3.0811500549316406e-01 + <_> + + 0 -1 1070 -1.0666999965906143e-02 + + -3.2729101181030273e-01 2.6168298721313477e-01 + <_> + + 0 -1 1071 1.0545299947261810e-01 + + -5.5750001221895218e-02 -1.9605729579925537e+00 + <_> + + 0 -1 1072 5.4827999323606491e-02 + + -1.9519999623298645e-03 7.3866099119186401e-01 + <_> + + 0 -1 1073 1.7760999500751495e-02 + + -3.0647200345993042e-01 2.6346999406814575e-01 + <_> + + 0 -1 1074 -3.1185999512672424e-02 + + -2.4600900709629059e-01 1.7082199454307556e-01 + <_> + + 0 -1 1075 -5.7296000421047211e-02 + + 4.7033500671386719e-01 -2.6048299670219421e-01 + <_> + + 0 -1 1076 -1.1312000453472137e-02 + + 3.8628900051116943e-01 -2.8817000985145569e-01 + <_> + + 0 -1 1077 3.0592000111937523e-02 + + -4.8826001584529877e-02 -1.7638969421386719e+00 + <_> + + 0 -1 1078 1.8489999929443002e-03 + + 2.1099899709224701e-01 -2.5940999388694763e-02 + <_> + + 0 -1 1079 1.1419000104069710e-02 + + -1.6829599440097809e-01 1.0278660058975220e+00 + <_> + + 0 -1 1080 8.1403002142906189e-02 + + 1.1531999707221985e-01 -1.2482399940490723e+00 + <_> + + 0 -1 1081 5.3495999425649643e-02 + + -4.6303998678922653e-02 -1.7165969610214233e+00 + <_> + + 0 -1 1082 -2.3948000743985176e-02 + + -4.0246599912643433e-01 2.0562100410461426e-01 + <_> + + 0 -1 1083 6.7690000869333744e-03 + + -3.3152300119400024e-01 2.0683400332927704e-01 + <_> + + 0 -1 1084 -3.2343998551368713e-02 + + -7.2632801532745361e-01 2.0073500275611877e-01 + <_> + + 0 -1 1085 3.7863001227378845e-02 + + -1.5631000697612762e-01 1.6697460412979126e+00 + <_> + + 0 -1 1086 1.5440000221133232e-02 + + 1.9487400352954865e-01 -3.5384199023246765e-01 + <_> + + 0 -1 1087 -4.4376000761985779e-02 + + 8.2093602418899536e-01 -1.8193599581718445e-01 + <_> + + 0 -1 1088 -2.3102000355720520e-02 + + -4.3044099211692810e-01 1.2375400215387344e-01 + <_> + + 0 -1 1089 1.9400000572204590e-02 + + -2.9726000502705574e-02 -1.1597590446472168e+00 + <_> + + 0 -1 1090 1.0385700315237045e-01 + + 1.1149899661540985e-01 -4.6835222244262695e+00 + <_> + + 0 -1 1091 -1.8964000046253204e-02 + + 2.1773819923400879e+00 -1.4544400572776794e-01 + <_> + + 0 -1 1092 3.8750998675823212e-02 + + -4.9446001648902893e-02 3.4018298983573914e-01 + <_> + + 0 -1 1093 2.2766999900341034e-02 + + -3.2802999019622803e-01 3.0531400442123413e-01 + <_> + + 0 -1 1094 -3.1357001513242722e-02 + + 1.1520819664001465e+00 2.7305999770760536e-02 + <_> + + 0 -1 1095 9.6909999847412109e-03 + + -3.8799500465393066e-01 2.1512599289417267e-01 + <_> + + 0 -1 1096 -4.9284998327493668e-02 + + -1.6774909496307373e+00 1.5774199366569519e-01 + <_> + + 0 -1 1097 -3.9510998874902725e-02 + + -9.7647899389266968e-01 -1.0552000254392624e-02 + <_> + + 0 -1 1098 4.7997999936342239e-02 + + 2.0843900740146637e-01 -6.8992799520492554e-01 + <_> + + 0 -1 1099 5.1422998309135437e-02 + + -1.6665300726890564e-01 1.2149239778518677e+00 + <_> + + 0 -1 1100 1.4279999770224094e-02 + + 2.3627699911594391e-01 -4.1396799683570862e-01 + <_> + + 0 -1 1101 -9.1611996293067932e-02 + + -9.2830902338027954e-01 -1.8345000222325325e-02 + <_> + + 0 -1 1102 6.5080001950263977e-03 + + -7.3647201061248779e-01 1.9497099518775940e-01 + <_> + + 0 -1 1103 3.5723000764846802e-02 + + 1.4197799563407898e-01 -4.2089301347732544e-01 + <_> + + 0 -1 1104 5.0638001412153244e-02 + + 1.1644000187516212e-02 7.8486597537994385e-01 + <_> + + 0 -1 1105 -1.4613999985158443e-02 + + -1.1909500360488892e+00 -3.5128001123666763e-02 + <_> + + 0 -1 1106 -3.8662999868392944e-02 + + 2.4314730167388916e+00 6.5647996962070465e-02 + <_> + + 0 -1 1107 -4.0346998721361160e-02 + + 7.1755301952362061e-01 -1.9108299911022186e-01 + <_> + + 0 -1 1108 2.3902000859379768e-02 + + 1.5646199882030487e-01 -7.9294800758361816e-01 + <_> + 137 + -3.5125269889831543e+00 + + <_> + + 0 -1 1109 8.5640000179409981e-03 + + -8.1450700759887695e-01 5.8875298500061035e-01 + <_> + + 0 -1 1110 -1.3292600214481354e-01 + + 9.3213397264480591e-01 -2.9367300868034363e-01 + <_> + + 0 -1 1111 9.8400004208087921e-03 + + -5.6462901830673218e-01 4.1647699475288391e-01 + <_> + + 0 -1 1112 5.0889998674392700e-03 + + -7.9232800006866455e-01 1.6975000500679016e-01 + <_> + + 0 -1 1113 -6.1039000749588013e-02 + + -1.4169000387191772e+00 2.5020999833941460e-02 + <_> + + 0 -1 1114 -4.6599999768659472e-04 + + 3.7982499599456787e-01 -4.1567099094390869e-01 + <_> + + 0 -1 1115 3.3889999613165855e-03 + + -4.0768599510192871e-01 3.5548499226570129e-01 + <_> + + 0 -1 1116 2.1006999537348747e-02 + + -2.4080100655555725e-01 8.6112701892852783e-01 + <_> + + 0 -1 1117 7.5559997931122780e-03 + + -8.7467199563980103e-01 9.8572000861167908e-02 + <_> + + 0 -1 1118 2.4779999628663063e-02 + + 1.5566200017929077e-01 -6.9229799509048462e-01 + <_> + + 0 -1 1119 -3.5620000213384628e-02 + + -1.1472270488739014e+00 3.6359999328851700e-02 + <_> + + 0 -1 1120 1.9810000434517860e-02 + + 1.5516200661659241e-01 -6.9520097970962524e-01 + <_> + + 0 -1 1121 1.5019999817013741e-02 + + 4.1990000754594803e-02 -9.6622800827026367e-01 + <_> + + 0 -1 1122 -2.3137999698519707e-02 + + 4.3396899104118347e-01 2.4160000029951334e-03 + <_> + + 0 -1 1123 -1.8743000924587250e-02 + + 4.3481099605560303e-01 -3.2522499561309814e-01 + <_> + + 0 -1 1124 4.5080000162124634e-01 + + -9.4573996961116791e-02 7.2421300411224365e-01 + <_> + + 0 -1 1125 1.1854999698698521e-02 + + -3.8133099675178528e-01 3.0098399519920349e-01 + <_> + + 0 -1 1126 -2.4830000475049019e-02 + + 8.9300602674484253e-01 -1.0295899957418442e-01 + <_> + + 0 -1 1127 -4.4743001461029053e-02 + + 8.6280298233032227e-01 -2.1716499328613281e-01 + <_> + + 0 -1 1128 -1.4600000344216824e-02 + + 6.0069400072097778e-01 -1.5906299650669098e-01 + <_> + + 0 -1 1129 -2.4527000263333321e-02 + + -1.5872869491577148e+00 -2.1817000582814217e-02 + <_> + + 0 -1 1130 2.3024000227451324e-02 + + 1.6853399574756622e-01 -3.8106900453567505e-01 + <_> + + 0 -1 1131 -2.4917000904679298e-02 + + 5.0810897350311279e-01 -2.7279898524284363e-01 + <_> + + 0 -1 1132 1.0130000300705433e-03 + + -4.3138799071311951e-01 2.6438099145889282e-01 + <_> + + 0 -1 1133 1.5603000298142433e-02 + + -3.1624200940132141e-01 5.5715900659561157e-01 + <_> + + 0 -1 1134 -2.6685999706387520e-02 + + 1.0553920269012451e+00 2.9074000194668770e-02 + <_> + + 0 -1 1135 1.3940000208094716e-03 + + -7.1873801946640015e-01 6.5390996634960175e-02 + <_> + + 0 -1 1136 -6.4799998654052615e-04 + + 2.4884399771690369e-01 -2.0978200435638428e-01 + <_> + + 0 -1 1137 -3.1888000667095184e-02 + + -6.8844497203826904e-01 6.3589997589588165e-02 + <_> + + 0 -1 1138 -4.9290000461041927e-03 + + -5.9152501821517944e-01 2.7943599224090576e-01 + <_> + + 0 -1 1139 3.1168000772595406e-02 + + 4.5223999768495560e-02 -8.8639199733734131e-01 + <_> + + 0 -1 1140 -3.3663000911474228e-02 + + -6.1590200662612915e-01 1.5749299526214600e-01 + <_> + + 0 -1 1141 1.1966999620199203e-02 + + -3.0606698989868164e-01 4.2293301224708557e-01 + <_> + + 0 -1 1142 -3.4680001437664032e-02 + + -1.3734940290451050e+00 1.5908700227737427e-01 + <_> + + 0 -1 1143 9.9290004000067711e-03 + + -5.5860197544097900e-01 1.2119200080633163e-01 + <_> + + 0 -1 1144 5.9574998915195465e-02 + + 4.9720001406967640e-03 8.2055401802062988e-01 + <_> + + 0 -1 1145 -6.5428003668785095e-02 + + 1.5651429891586304e+00 -1.6817499697208405e-01 + <_> + + 0 -1 1146 -9.2895999550819397e-02 + + -1.5794529914855957e+00 1.4661799371242523e-01 + <_> + + 0 -1 1147 -4.1184000670909882e-02 + + -1.5518720149993896e+00 -2.9969999566674232e-02 + <_> + + 0 -1 1148 2.1447999402880669e-02 + + 1.7196300625801086e-01 -6.9343197345733643e-01 + <_> + + 0 -1 1149 -2.5569999590516090e-02 + + -1.3061310052871704e+00 -2.4336999282240868e-02 + <_> + + 0 -1 1150 -4.1200999170541763e-02 + + -1.3821059465408325e+00 1.4801800251007080e-01 + <_> + + 0 -1 1151 -1.7668999731540680e-02 + + -7.0889997482299805e-01 3.6524001508951187e-02 + <_> + + 0 -1 1152 9.0060001239180565e-03 + + -4.0913999080657959e-02 8.0373102426528931e-01 + <_> + + 0 -1 1153 -1.1652999557554722e-02 + + 5.7546800374984741e-01 -2.4991700053215027e-01 + <_> + + 0 -1 1154 -7.4780001305043697e-03 + + -4.9280899763107300e-01 1.9810900092124939e-01 + <_> + + 0 -1 1155 8.5499999113380909e-04 + + -4.8858100175857544e-01 1.3563099503517151e-01 + <_> + + 0 -1 1156 -3.0538000166416168e-02 + + -6.0278397798538208e-01 1.8522000312805176e-01 + <_> + + 0 -1 1157 -1.8846999853849411e-02 + + 2.3565599322319031e-01 -3.5136300325393677e-01 + <_> + + 0 -1 1158 -8.1129996106028557e-03 + + -8.1304997205734253e-02 2.1069599688053131e-01 + <_> + + 0 -1 1159 -3.4830000251531601e-02 + + -1.2065670490264893e+00 -1.4251999557018280e-02 + <_> + + 0 -1 1160 1.9021000713109970e-02 + + 2.3349900543689728e-01 -4.5664900541305542e-01 + <_> + + 0 -1 1161 -1.9004000350832939e-02 + + -8.1075799465179443e-01 1.3140000402927399e-02 + <_> + + 0 -1 1162 -8.9057996869087219e-02 + + 6.1542397737503052e-01 3.2983001321554184e-02 + <_> + + 0 -1 1163 6.8620000965893269e-03 + + -2.9583099484443665e-01 2.7003699541091919e-01 + <_> + + 0 -1 1164 -2.8240999206900597e-02 + + -6.1102700233459473e-01 1.7357499897480011e-01 + <_> + + 0 -1 1165 -3.2099999953061342e-04 + + -5.3322899341583252e-01 6.8539001047611237e-02 + <_> + + 0 -1 1166 -1.0829100012779236e-01 + + -1.2879559993743896e+00 1.1801700294017792e-01 + <_> + + 0 -1 1167 1.5878999605774879e-02 + + -1.7072600126266479e-01 1.1103910207748413e+00 + <_> + + 0 -1 1168 8.6859995499253273e-03 + + -1.0995099693536758e-01 4.6010500192642212e-01 + <_> + + 0 -1 1169 -2.5234999135136604e-02 + + 1.0220669507980347e+00 -1.8694299459457397e-01 + <_> + + 0 -1 1170 -1.3508999720215797e-02 + + -7.8316599130630493e-01 1.4202600717544556e-01 + <_> + + 0 -1 1171 -7.7149998396635056e-03 + + -8.8060700893402100e-01 1.1060000397264957e-02 + <_> + + 0 -1 1172 7.1580000221729279e-02 + + 1.1369399726390839e-01 -1.1032789945602417e+00 + <_> + + 0 -1 1173 -1.3554000295698643e-02 + + -8.1096500158309937e-01 3.4080001059919596e-03 + <_> + + 0 -1 1174 2.9450000729411840e-03 + + -7.2879999876022339e-02 3.4998100996017456e-01 + <_> + + 0 -1 1175 -5.0833001732826233e-02 + + -1.2868590354919434e+00 -2.8842000290751457e-02 + <_> + + 0 -1 1176 -8.7989997118711472e-03 + + 4.7613599896430969e-01 -1.4690400660037994e-01 + <_> + + 0 -1 1177 2.1424399316310883e-01 + + -5.9702001512050629e-02 -2.4802260398864746e+00 + <_> + + 0 -1 1178 1.3962999917566776e-02 + + 1.7420299351215363e-01 -4.3911001086235046e-01 + <_> + + 0 -1 1179 4.2502000927925110e-02 + + -1.9965299963951111e-01 7.0654797554016113e-01 + <_> + + 0 -1 1180 1.9827999174594879e-02 + + -6.9136001169681549e-02 6.1643397808074951e-01 + <_> + + 0 -1 1181 -3.3560000360012054e-02 + + -1.2740780115127563e+00 -2.5673000141978264e-02 + <_> + + 0 -1 1182 6.3542999327182770e-02 + + 1.2403500080108643e-01 -1.0776289701461792e+00 + <_> + + 0 -1 1183 2.1933000534772873e-02 + + 1.4952000230550766e-02 -7.1023499965667725e-01 + <_> + + 0 -1 1184 -7.8424997627735138e-02 + + 6.2033998966217041e-01 3.3610999584197998e-02 + <_> + + 0 -1 1185 1.4390000142157078e-02 + + -3.6324599385261536e-01 1.7308300733566284e-01 + <_> + + 0 -1 1186 -6.7309997975826263e-02 + + 5.2374100685119629e-01 1.2799999676644802e-02 + <_> + + 0 -1 1187 1.3047499954700470e-01 + + -1.7122499644756317e-01 1.1235200166702271e+00 + <_> + + 0 -1 1188 -4.6245999634265900e-02 + + -1.1908329725265503e+00 1.7425599694252014e-01 + <_> + + 0 -1 1189 -2.9842000454664230e-02 + + 8.3930599689483643e-01 -1.8064199388027191e-01 + <_> + + 0 -1 1190 -3.8099999073892832e-04 + + 3.5532799363136292e-01 -2.3842300474643707e-01 + <_> + + 0 -1 1191 -2.2378999739885330e-02 + + -8.7943899631500244e-01 -7.8399997437372804e-04 + <_> + + 0 -1 1192 -1.5569999814033508e-03 + + -1.4253300428390503e-01 2.5876200199127197e-01 + <_> + + 0 -1 1193 1.2013000436127186e-02 + + -2.9015499353408813e-01 2.6051101088523865e-01 + <_> + + 0 -1 1194 2.4384999647736549e-02 + + -3.1438998878002167e-02 5.8695900440216064e-01 + <_> + + 0 -1 1195 -4.7180999070405960e-02 + + 6.9430100917816162e-01 -2.1816100180149078e-01 + <_> + + 0 -1 1196 -2.4893999099731445e-02 + + -6.4599299430847168e-01 1.5611599385738373e-01 + <_> + + 0 -1 1197 2.1944999694824219e-02 + + -2.7742000296711922e-02 -1.1346880197525024e+00 + <_> + + 0 -1 1198 1.8809899687767029e-01 + + -1.0076000355184078e-02 1.2429029941558838e+00 + <_> + + 0 -1 1199 -7.7872000634670258e-02 + + 8.5008001327514648e-01 -1.9015499949455261e-01 + <_> + + 0 -1 1200 -4.8769000917673111e-02 + + -2.0763080120086670e+00 1.2179400026798248e-01 + <_> + + 0 -1 1201 -1.7115000635385513e-02 + + -8.5687297582626343e-01 7.8760003671050072e-03 + <_> + + 0 -1 1202 -2.7499999850988388e-03 + + 3.8645499944686890e-01 -1.1391499638557434e-01 + <_> + + 0 -1 1203 -9.8793998360633850e-02 + + -1.7233899831771851e+00 -5.6063000112771988e-02 + <_> + + 0 -1 1204 -2.1936999633908272e-02 + + 5.4749399423599243e-01 -4.2481999844312668e-02 + <_> + + 0 -1 1205 6.1096999794244766e-02 + + -3.8945000618696213e-02 -1.0807880163192749e+00 + <_> + + 0 -1 1206 -2.4563999846577644e-02 + + 5.8311098814010620e-01 -9.7599998116493225e-04 + <_> + + 0 -1 1207 3.3752001821994781e-02 + + -1.3795999810099602e-02 -8.4730297327041626e-01 + <_> + + 0 -1 1208 3.8199000060558319e-02 + + 1.5114299952983856e-01 -7.9473400115966797e-01 + <_> + + 0 -1 1209 -2.0117999985814095e-02 + + 5.1579099893569946e-01 -2.1445399522781372e-01 + <_> + + 0 -1 1210 2.4734999984502792e-02 + + -2.2105000913143158e-02 4.2917698621749878e-01 + <_> + + 0 -1 1211 -2.4357000365853310e-02 + + -8.6201298236846924e-01 -3.6760000512003899e-03 + <_> + + 0 -1 1212 -2.6442000642418861e-02 + + -4.5397499203681946e-01 2.2462800145149231e-01 + <_> + + 0 -1 1213 -3.4429999068379402e-03 + + 1.3073000311851501e-01 -3.8622701168060303e-01 + <_> + + 0 -1 1214 1.0701700299978256e-01 + + 1.3158600032329559e-01 -7.9306900501251221e-01 + <_> + + 0 -1 1215 4.5152999460697174e-02 + + -2.5296801328659058e-01 4.0672400593757629e-01 + <_> + + 0 -1 1216 4.4349998235702515e-02 + + 2.2613000124692917e-02 7.9618102312088013e-01 + <_> + + 0 -1 1217 1.0839999886229634e-03 + + -3.9158400893211365e-01 1.1639100313186646e-01 + <_> + + 0 -1 1218 7.1433000266551971e-02 + + 8.2466997206211090e-02 1.2530590295791626e+00 + <_> + + 0 -1 1219 3.5838000476360321e-02 + + -1.8203300237655640e-01 7.7078700065612793e-01 + <_> + + 0 -1 1220 -2.0839000120759010e-02 + + -6.1744397878646851e-01 1.5891399979591370e-01 + <_> + + 0 -1 1221 4.2525801062583923e-01 + + -4.8978000879287720e-02 -1.8422030210494995e+00 + <_> + + 0 -1 1222 1.1408000253140926e-02 + + 1.7918199300765991e-01 -1.5383499860763550e-01 + <_> + + 0 -1 1223 -1.5364999882876873e-02 + + -8.4016501903533936e-01 -1.0280000278726220e-03 + <_> + + 0 -1 1224 -1.5212000347673893e-02 + + -1.8995699286460876e-01 1.7130999267101288e-01 + <_> + + 0 -1 1225 -1.8972000107169151e-02 + + -7.9541999101638794e-01 6.6800001077353954e-03 + <_> + + 0 -1 1226 -3.3330000005662441e-03 + + -2.3530800640583038e-01 2.4730099737644196e-01 + <_> + + 0 -1 1227 9.3248002231121063e-02 + + -5.4758001118898392e-02 -1.8324300050735474e+00 + <_> + + 0 -1 1228 -1.2555000372231007e-02 + + 2.6385200023651123e-01 -3.8526400923728943e-01 + <_> + + 0 -1 1229 -2.7070000767707825e-02 + + -6.6929799318313599e-01 2.0340999588370323e-02 + <_> + + 0 -1 1230 -2.3677000775933266e-02 + + 6.7265301942825317e-01 -1.4344000257551670e-02 + <_> + + 0 -1 1231 -1.4275000430643559e-02 + + 3.0186399817466736e-01 -2.8514400124549866e-01 + <_> + + 0 -1 1232 2.8096999973058701e-02 + + 1.4766000211238861e-01 -1.4078520536422729e+00 + <_> + + 0 -1 1233 5.0840001553297043e-02 + + -1.8613600730895996e-01 7.9953002929687500e-01 + <_> + + 0 -1 1234 1.1505999602377415e-02 + + 1.9118399918079376e-01 -8.5035003721714020e-02 + <_> + + 0 -1 1235 -1.4661000110208988e-02 + + 4.5239299535751343e-01 -2.2205199301242828e-01 + <_> + + 0 -1 1236 2.2842499613761902e-01 + + 1.3488399982452393e-01 -1.2894610166549683e+00 + <_> + + 0 -1 1237 1.1106900125741959e-01 + + -2.0753799378871918e-01 5.4561597108840942e-01 + <_> + + 0 -1 1238 3.2450000289827585e-03 + + 3.2053700089454651e-01 -1.6403500735759735e-01 + <_> + + 0 -1 1239 8.5309997200965881e-02 + + -2.0210500061511993e-01 5.3296798467636108e-01 + <_> + + 0 -1 1240 2.2048000246286392e-02 + + 1.5698599815368652e-01 -1.7014099657535553e-01 + <_> + + 0 -1 1241 -1.5676999464631081e-02 + + -6.2863498926162720e-01 4.0761999785900116e-02 + <_> + + 0 -1 1242 3.3112901449203491e-01 + + 1.6609300673007965e-01 -1.0326379537582397e+00 + <_> + + 0 -1 1243 8.8470000773668289e-03 + + -2.5076198577880859e-01 3.1660598516464233e-01 + <_> + + 0 -1 1244 4.6080000698566437e-02 + + 1.5352100133895874e-01 -1.6333500146865845e+00 + <_> + + 0 -1 1245 -3.7703000009059906e-02 + + 5.6873798370361328e-01 -2.0102599263191223e-01 + <_> + 159 + -3.5939640998840332e+00 + + <_> + + 0 -1 1246 -8.1808999180793762e-02 + + 5.7124799489974976e-01 -6.7438799142837524e-01 + <_> + + 0 -1 1247 2.1761199831962585e-01 + + -3.8610199093818665e-01 9.0343999862670898e-01 + <_> + + 0 -1 1248 1.4878000132739544e-02 + + 2.2241599857807159e-01 -1.2779350280761719e+00 + <_> + + 0 -1 1249 5.2434999495744705e-02 + + -2.8690400719642639e-01 7.5742298364639282e-01 + <_> + + 0 -1 1250 9.1429995372891426e-03 + + -6.4880400896072388e-01 2.2268800437450409e-01 + <_> + + 0 -1 1251 7.9169999808073044e-03 + + -2.9253599047660828e-01 3.1030198931694031e-01 + <_> + + 0 -1 1252 -2.6084000244736671e-02 + + 4.5532700419425964e-01 -3.8500601053237915e-01 + <_> + + 0 -1 1253 -2.9400000348687172e-03 + + -5.1264399290084839e-01 2.7432298660278320e-01 + <_> + + 0 -1 1254 5.7130001485347748e-02 + + 1.5788000077009201e-02 -1.2133100032806396e+00 + <_> + + 0 -1 1255 -6.1309998854994774e-03 + + 3.9174601435661316e-01 -3.0866798758506775e-01 + <_> + + 0 -1 1256 -4.0405001491308212e-02 + + 1.1901949644088745e+00 -2.0347100496292114e-01 + <_> + + 0 -1 1257 -2.0297000184655190e-02 + + -6.8239498138427734e-01 2.0458699762821198e-01 + <_> + + 0 -1 1258 -1.7188999801874161e-02 + + -8.4939897060394287e-01 3.8433000445365906e-02 + <_> + + 0 -1 1259 -2.4215999990701675e-02 + + -1.1039420366287231e+00 1.5975099802017212e-01 + <_> + + 0 -1 1260 5.6869000196456909e-02 + + -1.9595299661159515e-01 1.1806850433349609e+00 + <_> + + 0 -1 1261 3.6199999158270657e-04 + + -4.0847799181938171e-01 3.2938599586486816e-01 + <_> + + 0 -1 1262 9.9790003150701523e-03 + + -2.9673001170158386e-01 4.1547900438308716e-01 + <_> + + 0 -1 1263 -5.2625000476837158e-02 + + -1.3069299459457397e+00 1.7862600088119507e-01 + <_> + + 0 -1 1264 -1.3748999685049057e-02 + + 2.3665800690650940e-01 -4.4536599516868591e-01 + <_> + + 0 -1 1265 -3.0517000705003738e-02 + + 2.9018300771713257e-01 -1.1210100352764130e-01 + <_> + + 0 -1 1266 -3.0037501454353333e-01 + + -2.4237680435180664e+00 -4.2830999940633774e-02 + <_> + + 0 -1 1267 -3.5990998148918152e-02 + + 8.8206499814987183e-01 -4.7012999653816223e-02 + <_> + + 0 -1 1268 -5.5112000554800034e-02 + + 8.0119001865386963e-01 -2.0490999519824982e-01 + <_> + + 0 -1 1269 3.3762000501155853e-02 + + 1.4617599546909332e-01 -1.1349489688873291e+00 + <_> + + 0 -1 1270 -8.2710003480315208e-03 + + -8.1604897975921631e-01 1.8988000229001045e-02 + <_> + + 0 -1 1271 -5.4399999789893627e-03 + + -7.0980900526046753e-01 2.2343699634075165e-01 + <_> + + 0 -1 1272 3.1059999018907547e-03 + + -7.2808599472045898e-01 4.0224999189376831e-02 + <_> + + 0 -1 1273 5.3651999682188034e-02 + + 1.7170900106430054e-01 -1.1163710355758667e+00 + <_> + + 0 -1 1274 -1.2541399896144867e-01 + + 2.7680370807647705e+00 -1.4611500501632690e-01 + <_> + + 0 -1 1275 9.2542000114917755e-02 + + 1.1609800159931183e-01 -3.9635529518127441e+00 + <_> + + 0 -1 1276 3.8513999432325363e-02 + + -7.6399999670684338e-03 -9.8780900239944458e-01 + <_> + + 0 -1 1277 -2.0200000144541264e-03 + + 2.3059999942779541e-01 -7.4970299005508423e-01 + <_> + + 0 -1 1278 9.7599998116493225e-03 + + -3.1137999892234802e-01 3.0287799239158630e-01 + <_> + + 0 -1 1279 2.4095000699162483e-02 + + -4.9529999494552612e-02 5.2690100669860840e-01 + <_> + + 0 -1 1280 -1.7982000485062599e-02 + + -1.1610640287399292e+00 -5.7000000961124897e-03 + <_> + + 0 -1 1281 -1.0555000044405460e-02 + + -2.7189099788665771e-01 2.3597699403762817e-01 + <_> + + 0 -1 1282 -7.2889998555183411e-03 + + -5.4219102859497070e-01 8.1914000213146210e-02 + <_> + + 0 -1 1283 2.3939000442624092e-02 + + 1.7975799739360809e-01 -6.7049497365951538e-01 + <_> + + 0 -1 1284 -1.8365999683737755e-02 + + 6.2664300203323364e-01 -2.0970100164413452e-01 + <_> + + 0 -1 1285 1.5715999528765678e-02 + + 2.4193699657917023e-01 -1.0444309711456299e+00 + <_> + + 0 -1 1286 -4.8804000020027161e-02 + + -9.4060599803924561e-01 -3.7519999314099550e-03 + <_> + + 0 -1 1287 6.7130001261830330e-03 + + -7.5432002544403076e-02 6.1575299501419067e-01 + <_> + + 0 -1 1288 9.7770001739263535e-03 + + 3.9285000413656235e-02 -8.4810298681259155e-01 + <_> + + 0 -1 1289 1.4744999818503857e-02 + + 1.6968999803066254e-01 -5.0906401872634888e-01 + <_> + + 0 -1 1290 9.7079001367092133e-02 + + -3.3103000372648239e-02 -1.2706379890441895e+00 + <_> + + 0 -1 1291 4.8285998404026031e-02 + + 9.4329997897148132e-02 2.7203190326690674e+00 + <_> + + 0 -1 1292 9.7810002043843269e-03 + + -3.9533400535583496e-01 1.5363800525665283e-01 + <_> + + 0 -1 1293 -3.9893999695777893e-02 + + -2.2767400741577148e-01 1.3913999497890472e-01 + <_> + + 0 -1 1294 2.2848000749945641e-02 + + -2.7391999959945679e-01 3.4199500083923340e-01 + <_> + + 0 -1 1295 6.7179999314248562e-03 + + -1.0874299705028534e-01 4.8125401139259338e-01 + <_> + + 0 -1 1296 5.9599999338388443e-02 + + -4.9522001296281815e-02 -2.0117089748382568e+00 + <_> + + 0 -1 1297 6.9340001791715622e-03 + + 1.5037499368190765e-01 -1.1271899938583374e-01 + <_> + + 0 -1 1298 1.5757000073790550e-02 + + -2.0885000005364418e-02 -1.1651979684829712e+00 + <_> + + 0 -1 1299 -4.9690000712871552e-02 + + -8.0213499069213867e-01 1.4372299611568451e-01 + <_> + + 0 -1 1300 5.2347000688314438e-02 + + -2.0836700499057770e-01 6.1677598953247070e-01 + <_> + + 0 -1 1301 2.2430999204516411e-02 + + 2.0305900275707245e-01 -7.5326198339462280e-01 + <_> + + 0 -1 1302 4.1142001748085022e-02 + + -1.8118199706077576e-01 1.0033359527587891e+00 + <_> + + 0 -1 1303 -2.1632000803947449e-02 + + 4.9998998641967773e-01 -3.4662999212741852e-02 + <_> + + 0 -1 1304 -8.2808002829551697e-02 + + 1.1711900234222412e+00 -1.8433600664138794e-01 + <_> + + 0 -1 1305 8.5060000419616699e-03 + + -6.3225001096725464e-02 2.9024899005889893e-01 + <_> + + 0 -1 1306 7.8905001282691956e-02 + + -2.3274500668048859e-01 5.9695798158645630e-01 + <_> + + 0 -1 1307 -9.0207003057003021e-02 + + -8.2211899757385254e-01 1.7772200703620911e-01 + <_> + + 0 -1 1308 -2.9269000515341759e-02 + + 6.0860699415206909e-01 -2.1468900144100189e-01 + <_> + + 0 -1 1309 6.9499998353421688e-03 + + -4.2665999382734299e-02 6.0512101650238037e-01 + <_> + + 0 -1 1310 -8.0629996955394745e-03 + + -1.1508270502090454e+00 -2.7286000549793243e-02 + <_> + + 0 -1 1311 1.9595999270677567e-02 + + -9.1880001127719879e-03 5.6857800483703613e-01 + <_> + + 0 -1 1312 -1.4884999953210354e-02 + + 3.7658798694610596e-01 -2.7149501442909241e-01 + <_> + + 0 -1 1313 2.5217000395059586e-02 + + -9.9991001188755035e-02 2.4664700031280518e-01 + <_> + + 0 -1 1314 -1.5855999663472176e-02 + + 6.6826701164245605e-01 -2.0614700019359589e-01 + <_> + + 0 -1 1315 2.9441000893712044e-02 + + 1.5832200646400452e-01 -7.6060897111892700e-01 + <_> + + 0 -1 1316 -8.5279997438192368e-03 + + 3.8212299346923828e-01 -2.5407800078392029e-01 + <_> + + 0 -1 1317 2.4421999230980873e-02 + + 1.5105099976062775e-01 -2.8752899169921875e-01 + <_> + + 0 -1 1318 -3.3886998891830444e-02 + + -6.8002802133560181e-01 3.4327000379562378e-02 + <_> + + 0 -1 1319 -2.0810000132769346e-03 + + 2.5413900613784790e-01 -2.6859098672866821e-01 + <_> + + 0 -1 1320 3.0358999967575073e-02 + + -3.0842000618577003e-02 -1.1476809978485107e+00 + <_> + + 0 -1 1321 4.0210001170635223e-03 + + -3.5253798961639404e-01 2.9868099093437195e-01 + <_> + + 0 -1 1322 2.7681000530719757e-02 + + -3.8148999214172363e-02 -1.3262039422988892e+00 + <_> + + 0 -1 1323 7.9039996489882469e-03 + + -2.3737000301480293e-02 7.0503002405166626e-01 + <_> + + 0 -1 1324 4.4031001627445221e-02 + + 1.0674899816513062e-01 -4.5261201262474060e-01 + <_> + + 0 -1 1325 -3.2370999455451965e-02 + + 4.6674901247024536e-01 -6.1546999961137772e-02 + <_> + + 0 -1 1326 2.0933000370860100e-02 + + -2.8447899222373962e-01 4.3845599889755249e-01 + <_> + + 0 -1 1327 2.5227999314665794e-02 + + -2.2537000477313995e-02 7.0389097929000854e-01 + <_> + + 0 -1 1328 6.5520000644028187e-03 + + -3.2554900646209717e-01 2.4023699760437012e-01 + <_> + + 0 -1 1329 -5.8557998389005661e-02 + + -1.2227720022201538e+00 1.1668799817562103e-01 + <_> + + 0 -1 1330 3.1899999827146530e-02 + + -1.9305000081658363e-02 -1.0973169803619385e+00 + <_> + + 0 -1 1331 -3.0445000156760216e-02 + + 6.5582501888275146e-01 7.5090996921062469e-02 + <_> + + 0 -1 1332 1.4933000318706036e-02 + + -5.2155798673629761e-01 1.1523099988698959e-01 + <_> + + 0 -1 1333 -4.9008000642061234e-02 + + -7.8303998708724976e-01 1.6657200455665588e-01 + <_> + + 0 -1 1334 8.3158999681472778e-02 + + -2.6879999786615372e-03 -8.5282301902770996e-01 + <_> + + 0 -1 1335 2.3902999237179756e-02 + + -5.1010999828577042e-02 4.1999098658561707e-01 + <_> + + 0 -1 1336 1.6428999602794647e-02 + + 1.9232999533414841e-02 -6.5049099922180176e-01 + <_> + + 0 -1 1337 -1.1838000267744064e-02 + + -6.2409800291061401e-01 1.5411199629306793e-01 + <_> + + 0 -1 1338 -1.6799999866634607e-04 + + 1.7589199542999268e-01 -3.4338700771331787e-01 + <_> + + 0 -1 1339 1.9193999469280243e-02 + + 4.3418999761343002e-02 7.9069197177886963e-01 + <_> + + 0 -1 1340 -1.0032000020146370e-02 + + 4.5648899674415588e-01 -2.2494800388813019e-01 + <_> + + 0 -1 1341 -1.4004000462591648e-02 + + 3.3570998907089233e-01 -4.8799999058246613e-03 + <_> + + 0 -1 1342 -1.0319899767637253e-01 + + -2.3378000259399414e+00 -5.8933001011610031e-02 + <_> + + 0 -1 1343 -9.5697000622749329e-02 + + -6.6153901815414429e-01 2.0098599791526794e-01 + <_> + + 0 -1 1344 -4.1480999439954758e-02 + + 4.5939201116561890e-01 -2.2314099967479706e-01 + <_> + + 0 -1 1345 2.4099999573081732e-03 + + -2.6898598670959473e-01 2.4922999739646912e-01 + <_> + + 0 -1 1346 1.0724999755620956e-01 + + -1.8640199303627014e-01 7.2769802808761597e-01 + <_> + + 0 -1 1347 3.1870000530034304e-03 + + -2.4608999490737915e-02 2.8643900156021118e-01 + <_> + + 0 -1 1348 2.9167000204324722e-02 + + -3.4683000296354294e-02 -1.1162580251693726e+00 + <_> + + 0 -1 1349 1.1287000030279160e-02 + + 6.3760001212358475e-03 6.6632097959518433e-01 + <_> + + 0 -1 1350 -1.2001000344753265e-02 + + 4.2420101165771484e-01 -2.6279801130294800e-01 + <_> + + 0 -1 1351 -1.2695999816060066e-02 + + -2.1957000717520714e-02 1.8936799466609955e-01 + <_> + + 0 -1 1352 2.4597000330686569e-02 + + -3.4963998943567276e-02 -1.0989320278167725e+00 + <_> + + 0 -1 1353 4.5953001827001572e-02 + + 1.1109799891710281e-01 -2.9306049346923828e+00 + <_> + + 0 -1 1354 -2.7241000905632973e-02 + + 2.9101699590682983e-01 -2.7407899498939514e-01 + <_> + + 0 -1 1355 4.0063999593257904e-02 + + 1.1877900362014771e-01 -6.2801802158355713e-01 + <_> + + 0 -1 1356 2.3055000230669975e-02 + + 1.4813800156116486e-01 -3.7007498741149902e-01 + <_> + + 0 -1 1357 -2.3737000301480293e-02 + + -5.3724801540374756e-01 1.9358199834823608e-01 + <_> + + 0 -1 1358 7.7522002160549164e-02 + + -6.0194000601768494e-02 -1.9489669799804688e+00 + <_> + + 0 -1 1359 -1.3345000334084034e-02 + + -4.5229598879814148e-01 1.8741500377655029e-01 + <_> + + 0 -1 1360 -2.1719999611377716e-02 + + 1.2144249677658081e+00 -1.5365800261497498e-01 + <_> + + 0 -1 1361 -7.1474999189376831e-02 + + -2.3047130107879639e+00 1.0999900102615356e-01 + <_> + + 0 -1 1362 -5.4999999701976776e-03 + + -7.1855199337005615e-01 2.0100999623537064e-02 + <_> + + 0 -1 1363 2.6740999892354012e-02 + + 7.3545001447200775e-02 9.8786002397537231e-01 + <_> + + 0 -1 1364 -3.9407998323440552e-02 + + -1.2227380275726318e+00 -4.3506998568773270e-02 + <_> + + 0 -1 1365 2.5888999924063683e-02 + + 1.3409300148487091e-01 -1.1770780086517334e+00 + <_> + + 0 -1 1366 4.8925001174211502e-02 + + -3.0810000374913216e-02 -9.3479502201080322e-01 + <_> + + 0 -1 1367 3.6892998963594437e-02 + + 1.3333700597286224e-01 -1.4998290538787842e+00 + <_> + + 0 -1 1368 7.8929997980594635e-02 + + -1.4538800716400146e-01 1.5631790161132812e+00 + <_> + + 0 -1 1369 2.9006000608205795e-02 + + 1.9383700191974640e-01 -6.7642802000045776e-01 + <_> + + 0 -1 1370 6.3089998438954353e-03 + + -3.7465399503707886e-01 1.0857500135898590e-01 + <_> + + 0 -1 1371 -6.5830998122692108e-02 + + 8.1059402227401733e-01 3.0201999470591545e-02 + <_> + + 0 -1 1372 -6.8965002894401550e-02 + + 8.3772599697113037e-01 -1.7140999436378479e-01 + <_> + + 0 -1 1373 -1.1669100075960159e-01 + + -9.4647198915481567e-01 1.3123199343681335e-01 + <_> + + 0 -1 1374 -1.3060000492259860e-03 + + 4.6007998287677765e-02 -5.2011597156524658e-01 + <_> + + 0 -1 1375 -4.4558998197317123e-02 + + -1.9423669576644897e+00 1.3200700283050537e-01 + <_> + + 0 -1 1376 5.1033001393079758e-02 + + -2.1480999886989594e-01 4.8673900961875916e-01 + <_> + + 0 -1 1377 -3.1578000634908676e-02 + + 5.9989798069000244e-01 7.9159997403621674e-03 + <_> + + 0 -1 1378 2.1020000800490379e-02 + + -2.2069500386714935e-01 5.4046201705932617e-01 + <_> + + 0 -1 1379 -1.3824200630187988e-01 + + 6.2957501411437988e-01 -2.1712999790906906e-02 + <_> + + 0 -1 1380 5.2228998392820358e-02 + + -2.3360900580883026e-01 4.9760800600051880e-01 + <_> + + 0 -1 1381 2.5884000584483147e-02 + + 1.8041999638080597e-01 -2.2039200365543365e-01 + <_> + + 0 -1 1382 -1.2138999998569489e-02 + + -6.9731897115707397e-01 1.5712000429630280e-02 + <_> + + 0 -1 1383 -2.4237999692559242e-02 + + 3.4593299031257629e-01 7.1469999849796295e-02 + <_> + + 0 -1 1384 -2.5272000581026077e-02 + + -8.7583297491073608e-01 -9.8240002989768982e-03 + <_> + + 0 -1 1385 1.2597000226378441e-02 + + 2.3649999499320984e-01 -2.8731200098991394e-01 + <_> + + 0 -1 1386 5.7330999523401260e-02 + + -6.1530999839305878e-02 -2.2326040267944336e+00 + <_> + + 0 -1 1387 1.6671000048518181e-02 + + -1.9850100576877594e-01 4.0810701251029968e-01 + <_> + + 0 -1 1388 -2.2818999364972115e-02 + + 9.6487599611282349e-01 -2.0245699584484100e-01 + <_> + + 0 -1 1389 3.7000001611886546e-05 + + -5.8908998966217041e-02 2.7055400609970093e-01 + <_> + + 0 -1 1390 -7.6700001955032349e-03 + + -4.5317101478576660e-01 8.9628003537654877e-02 + <_> + + 0 -1 1391 9.4085998833179474e-02 + + 1.1604599654674530e-01 -1.0951169729232788e+00 + <_> + + 0 -1 1392 -6.2267001718282700e-02 + + 1.8096530437469482e+00 -1.4773200452327728e-01 + <_> + + 0 -1 1393 1.7416000366210938e-02 + + 2.3068200051784515e-01 -4.2417600750923157e-01 + <_> + + 0 -1 1394 -2.2066000849008560e-02 + + 4.9270299077033997e-01 -2.0630900561809540e-01 + <_> + + 0 -1 1395 -1.0404000058770180e-02 + + 6.0924297571182251e-01 2.8130000457167625e-02 + <_> + + 0 -1 1396 -9.3670003116130829e-03 + + 4.0171200037002563e-01 -2.1681700646877289e-01 + <_> + + 0 -1 1397 -2.9039999470114708e-02 + + -8.4876501560211182e-01 1.4246800541877747e-01 + <_> + + 0 -1 1398 -2.1061999723315239e-02 + + -7.9198300838470459e-01 -1.2595999985933304e-02 + <_> + + 0 -1 1399 -3.7000998854637146e-02 + + -6.7488902807235718e-01 1.2830400466918945e-01 + <_> + + 0 -1 1400 1.0735999792814255e-02 + + 3.6779999732971191e-02 -6.3393002748489380e-01 + <_> + + 0 -1 1401 1.6367599368095398e-01 + + 1.3803899288177490e-01 -4.7189000248908997e-01 + <_> + + 0 -1 1402 9.4917997717857361e-02 + + -1.3855700194835663e-01 1.9492419958114624e+00 + <_> + + 0 -1 1403 3.5261999815702438e-02 + + 1.3721899688243866e-01 -2.1186530590057373e+00 + <_> + + 0 -1 1404 1.2811000458896160e-02 + + -2.0008100569248199e-01 4.9507799744606018e-01 + <_> + 155 + -3.3933560848236084e+00 + + <_> + + 0 -1 1405 1.3904400169849396e-01 + + -4.6581199765205383e-01 7.6431602239608765e-01 + <_> + + 0 -1 1406 1.1916999705135822e-02 + + -9.4398999214172363e-01 3.9726299047470093e-01 + <_> + + 0 -1 1407 -1.0006999596953392e-02 + + 3.2718798518180847e-01 -6.3367402553558350e-01 + <_> + + 0 -1 1408 -6.0479999519884586e-03 + + 2.7427899837493896e-01 -5.7446998357772827e-01 + <_> + + 0 -1 1409 -1.2489999644458294e-03 + + 2.3629300296306610e-01 -6.8593502044677734e-01 + <_> + + 0 -1 1410 3.2382000237703323e-02 + + -5.7630199193954468e-01 2.7492699027061462e-01 + <_> + + 0 -1 1411 -1.3957999646663666e-02 + + -6.1061501502990723e-01 2.4541600048542023e-01 + <_> + + 0 -1 1412 1.1159999994561076e-03 + + -5.6539100408554077e-01 2.7179300785064697e-01 + <_> + + 0 -1 1413 2.7000000045518391e-05 + + -8.0235999822616577e-01 1.1509100347757339e-01 + <_> + + 0 -1 1414 -2.5700000696815550e-04 + + -8.1205898523330688e-01 2.3844699561595917e-01 + <_> + + 0 -1 1415 4.0460000745952129e-03 + + 1.3909600675106049e-01 -6.6163200139999390e-01 + <_> + + 0 -1 1416 1.4356000348925591e-02 + + -1.6485199332237244e-01 4.1901698708534241e-01 + <_> + + 0 -1 1417 -5.5374998599290848e-02 + + 1.4425870180130005e+00 -1.8820199370384216e-01 + <_> + + 0 -1 1418 9.3594998121261597e-02 + + 1.3548299670219421e-01 -9.1636097431182861e-01 + <_> + + 0 -1 1419 2.6624999940395355e-02 + + -3.3748298883438110e-01 3.9233601093292236e-01 + <_> + + 0 -1 1420 3.7469998933374882e-03 + + -1.1615400016307831e-01 4.4399300217628479e-01 + <_> + + 0 -1 1421 -3.1886000186204910e-02 + + -9.9498301744461060e-01 1.6120000509545207e-03 + <_> + + 0 -1 1422 -2.2600000724196434e-02 + + -4.8067399859428406e-01 1.7007300257682800e-01 + <_> + + 0 -1 1423 2.5202000513672829e-02 + + 3.5580001771450043e-02 -8.0215400457382202e-01 + <_> + + 0 -1 1424 -3.1036999076604843e-02 + + -1.0895340442657471e+00 1.8081900477409363e-01 + <_> + + 0 -1 1425 -2.6475999504327774e-02 + + 9.5671200752258301e-01 -2.1049399673938751e-01 + <_> + + 0 -1 1426 -1.3853999786078930e-02 + + -1.0370320081710815e+00 2.2166700661182404e-01 + <_> + + 0 -1 1427 -6.2925003468990326e-02 + + 9.0199398994445801e-01 -1.9085299968719482e-01 + <_> + + 0 -1 1428 -4.4750999659299850e-02 + + -1.0119110345840454e+00 1.4691199362277985e-01 + <_> + + 0 -1 1429 -2.0428000018000603e-02 + + 6.1624497175216675e-01 -2.3552699387073517e-01 + <_> + + 0 -1 1430 -8.0329999327659607e-03 + + -8.3279997110366821e-02 2.1728700399398804e-01 + <_> + + 0 -1 1431 8.7280003353953362e-03 + + 6.5458998084068298e-02 -6.0318702459335327e-01 + <_> + + 0 -1 1432 -2.7202000841498375e-02 + + -9.3447399139404297e-01 1.5270000696182251e-01 + <_> + + 0 -1 1433 -1.6471000388264656e-02 + + -8.4177100658416748e-01 1.3332000002264977e-02 + <_> + + 0 -1 1434 -1.3744000345468521e-02 + + 6.0567200183868408e-01 -9.2021003365516663e-02 + <_> + + 0 -1 1435 2.9164999723434448e-02 + + -2.8114000335335732e-02 -1.4014569520950317e+00 + <_> + + 0 -1 1436 3.7457000464200974e-02 + + 1.3080599904060364e-01 -4.9382498860359192e-01 + <_> + + 0 -1 1437 -2.5070000439882278e-02 + + -1.1289390325546265e+00 -1.4600000344216824e-02 + <_> + + 0 -1 1438 -6.3812002539634705e-02 + + 7.5871598720550537e-01 -1.8200000049546361e-03 + <_> + + 0 -1 1439 -9.3900002539157867e-03 + + 2.9936400055885315e-01 -2.9487800598144531e-01 + <_> + + 0 -1 1440 -7.6000002445653081e-04 + + 1.9725000485777855e-02 1.9993899762630463e-01 + <_> + + 0 -1 1441 -2.1740999072790146e-02 + + -8.5247898101806641e-01 4.9169998615980148e-02 + <_> + + 0 -1 1442 -1.7869999632239342e-02 + + -5.9985999017953873e-02 1.5222500264644623e-01 + <_> + + 0 -1 1443 -2.4831000715494156e-02 + + 3.5603401064872742e-01 -2.6259899139404297e-01 + <_> + + 0 -1 1444 1.5715500712394714e-01 + + 1.5599999460391700e-04 1.0428730249404907e+00 + <_> + + 0 -1 1445 6.9026999175548553e-02 + + -3.3006999641656876e-02 -1.1796669960021973e+00 + <_> + + 0 -1 1446 -1.1021999642252922e-02 + + 5.8987700939178467e-01 -5.7647999376058578e-02 + <_> + + 0 -1 1447 -1.3834999874234200e-02 + + 5.9502798318862915e-01 -2.4418599903583527e-01 + <_> + + 0 -1 1448 -3.0941000208258629e-02 + + -1.1723799705505371e+00 1.6907000541687012e-01 + <_> + + 0 -1 1449 2.1258000284433365e-02 + + -1.8900999799370766e-02 -1.0684759616851807e+00 + <_> + + 0 -1 1450 9.3079999089241028e-02 + + 1.6305600106716156e-01 -1.3375270366668701e+00 + <_> + + 0 -1 1451 2.9635999351739883e-02 + + -2.2524799406528473e-01 4.5400100946426392e-01 + <_> + + 0 -1 1452 -1.2199999764561653e-04 + + 2.7409100532531738e-01 -3.7371399998664856e-01 + <_> + + 0 -1 1453 -4.2098000645637512e-02 + + -7.5828802585601807e-01 1.7137000337243080e-02 + <_> + + 0 -1 1454 -2.2505000233650208e-02 + + -2.2759300470352173e-01 2.3698699474334717e-01 + <_> + + 0 -1 1455 -1.2862999923527241e-02 + + 1.9252400100231171e-01 -3.2127100229263306e-01 + <_> + + 0 -1 1456 2.7860000729560852e-02 + + 1.6723699867725372e-01 -1.0209059715270996e+00 + <_> + + 0 -1 1457 -2.7807999402284622e-02 + + 1.2824759483337402e+00 -1.7225299775600433e-01 + <_> + + 0 -1 1458 -6.1630001291632652e-03 + + -5.4072898626327515e-01 2.3885700106620789e-01 + <_> + + 0 -1 1459 -2.0436000078916550e-02 + + 6.3355398178100586e-01 -2.1090599894523621e-01 + <_> + + 0 -1 1460 -1.2307999655604362e-02 + + -4.9778199195861816e-01 1.7402599751949310e-01 + <_> + + 0 -1 1461 -4.0493998676538467e-02 + + -1.1848740577697754e+00 -3.3890999853610992e-02 + <_> + + 0 -1 1462 2.9657000675797462e-02 + + 2.1740999072790146e-02 1.0069919824600220e+00 + <_> + + 0 -1 1463 6.8379999138414860e-03 + + 2.9217999428510666e-02 -5.9906297922134399e-01 + <_> + + 0 -1 1464 1.6164999455213547e-02 + + -2.1000799536705017e-01 3.7637299299240112e-01 + <_> + + 0 -1 1465 5.0193000584840775e-02 + + 2.5319999549537897e-03 -7.1668201684951782e-01 + <_> + + 0 -1 1466 1.9680000841617584e-03 + + -2.1921400725841522e-01 3.2298699021339417e-01 + <_> + + 0 -1 1467 2.4979999288916588e-02 + + -9.6840001642704010e-03 -7.7572900056838989e-01 + <_> + + 0 -1 1468 -1.5809999778866768e-02 + + 4.4637501239776611e-01 -6.1760000884532928e-02 + <_> + + 0 -1 1469 3.7206999957561493e-02 + + -2.0495399832725525e-01 5.7722198963165283e-01 + <_> + + 0 -1 1470 -7.9264998435974121e-02 + + -7.6745402812957764e-01 1.2550400197505951e-01 + <_> + + 0 -1 1471 -1.7152000218629837e-02 + + -1.4121830463409424e+00 -5.1704000681638718e-02 + <_> + + 0 -1 1472 3.2740000635385513e-02 + + 1.9334000349044800e-01 -6.3633698225021362e-01 + <_> + + 0 -1 1473 -1.1756999790668488e-01 + + 8.4325402975082397e-01 -1.8018600344657898e-01 + <_> + + 0 -1 1474 1.2057200074195862e-01 + + 1.2530000507831573e-01 -2.1213600635528564e+00 + <_> + + 0 -1 1475 4.2779999785125256e-03 + + -4.6604400873184204e-01 8.9643999934196472e-02 + <_> + + 0 -1 1476 -7.2544999420642853e-02 + + 5.1826500892639160e-01 1.6823999583721161e-02 + <_> + + 0 -1 1477 1.7710599303245544e-01 + + -3.0910000205039978e-02 -1.1046639680862427e+00 + <_> + + 0 -1 1478 8.4229996427893639e-03 + + 2.4445800483226776e-01 -3.8613098859786987e-01 + <_> + + 0 -1 1479 -1.3035000301897526e-02 + + 9.8004400730133057e-01 -1.7016500234603882e-01 + <_> + + 0 -1 1480 1.8912000581622124e-02 + + 2.0248499512672424e-01 -3.8545900583267212e-01 + <_> + + 0 -1 1481 2.1447999402880669e-02 + + -2.5717198848724365e-01 3.5181200504302979e-01 + <_> + + 0 -1 1482 6.3357003033161163e-02 + + 1.6994799673557281e-01 -9.1383802890777588e-01 + <_> + + 0 -1 1483 -3.2435998320579529e-02 + + -8.5681599378585815e-01 -2.1680999547243118e-02 + <_> + + 0 -1 1484 -2.3564999923110008e-02 + + 5.6115597486495972e-01 -2.2400000307243317e-04 + <_> + + 0 -1 1485 1.8789000809192657e-02 + + -2.5459799170494080e-01 3.4512901306152344e-01 + <_> + + 0 -1 1486 3.1042000278830528e-02 + + 7.5719999149441719e-03 3.4800198674201965e-01 + <_> + + 0 -1 1487 -1.1226999573409557e-02 + + -6.0219800472259521e-01 4.2814999818801880e-02 + <_> + + 0 -1 1488 -1.2845999561250210e-02 + + 4.2020401358604431e-01 -5.3801000118255615e-02 + <_> + + 0 -1 1489 -1.2791999615728855e-02 + + 2.2724500298500061e-01 -3.2398000359535217e-01 + <_> + + 0 -1 1490 6.8651996552944183e-02 + + 9.3532003462314606e-02 10. + <_> + + 0 -1 1491 5.2789999172091484e-03 + + -2.6926299929618835e-01 3.3303201198577881e-01 + <_> + + 0 -1 1492 -3.8779001682996750e-02 + + -7.2365301847457886e-01 1.7806500196456909e-01 + <_> + + 0 -1 1493 6.1820000410079956e-03 + + -3.5119399428367615e-01 1.6586300730705261e-01 + <_> + + 0 -1 1494 1.7515200376510620e-01 + + 1.1623100191354752e-01 -1.5419290065765381e+00 + <_> + + 0 -1 1495 1.1627999693155289e-01 + + -9.1479998081922531e-03 -9.9842602014541626e-01 + <_> + + 0 -1 1496 -2.2964000701904297e-02 + + 2.0565399527549744e-01 1.5432000160217285e-02 + <_> + + 0 -1 1497 -5.1410000771284103e-02 + + 5.8072400093078613e-01 -2.0118400454521179e-01 + <_> + + 0 -1 1498 2.2474199533462524e-01 + + 1.8728999421000481e-02 1.0829299688339233e+00 + <_> + + 0 -1 1499 9.4860000535845757e-03 + + -3.3171299099922180e-01 1.9902999699115753e-01 + <_> + + 0 -1 1500 -1.1846300214529037e-01 + + 1.3711010217666626e+00 6.8926997482776642e-02 + <_> + + 0 -1 1501 3.7810999900102615e-02 + + -9.3600002583116293e-04 -8.3996999263763428e-01 + <_> + + 0 -1 1502 2.2202000021934509e-02 + + -1.1963999830186367e-02 3.6673998832702637e-01 + <_> + + 0 -1 1503 -3.6366000771522522e-02 + + 3.7866500020027161e-01 -2.7714800834655762e-01 + <_> + + 0 -1 1504 -1.3184699416160583e-01 + + -2.7481179237365723e+00 1.0666900128126144e-01 + <_> + + 0 -1 1505 -4.1655998677015305e-02 + + 4.7524300217628479e-01 -2.3249800503253937e-01 + <_> + + 0 -1 1506 -3.3151999115943909e-02 + + -5.7929402589797974e-01 1.7434400320053101e-01 + <_> + + 0 -1 1507 1.5769999474287033e-02 + + -1.1284000240266323e-02 -8.3701401948928833e-01 + <_> + + 0 -1 1508 -3.9363000541925430e-02 + + 3.4821599721908569e-01 -1.7455400526523590e-01 + <_> + + 0 -1 1509 -6.7849002778530121e-02 + + 1.4225699901580811e+00 -1.4765599370002747e-01 + <_> + + 0 -1 1510 -2.6775000616908073e-02 + + 2.3947000503540039e-01 1.3271999545395374e-02 + <_> + + 0 -1 1511 3.9919000118970871e-02 + + -8.9999996125698090e-03 -7.5938898324966431e-01 + <_> + + 0 -1 1512 1.0065600275993347e-01 + + -1.8685000017285347e-02 7.6245301961898804e-01 + <_> + + 0 -1 1513 -8.1022001802921295e-02 + + -9.0439099073410034e-01 -8.5880002006888390e-03 + <_> + + 0 -1 1514 -2.1258000284433365e-02 + + -2.1319599449634552e-01 2.1919700503349304e-01 + <_> + + 0 -1 1515 -1.0630999691784382e-02 + + 1.9598099589347839e-01 -3.5768100619316101e-01 + <_> + + 0 -1 1516 8.1300002057105303e-04 + + -9.2794999480247498e-02 2.6145899295806885e-01 + <_> + + 0 -1 1517 3.4650000743567944e-03 + + -5.5336099863052368e-01 2.7386000379920006e-02 + <_> + + 0 -1 1518 1.8835999071598053e-02 + + 1.8446099758148193e-01 -6.6934299468994141e-01 + <_> + + 0 -1 1519 -2.5631999596953392e-02 + + 1.9382879734039307e+00 -1.4708900451660156e-01 + <_> + + 0 -1 1520 -4.0939999744296074e-03 + + -2.6451599597930908e-01 2.0733200013637543e-01 + <_> + + 0 -1 1521 -8.9199998183175921e-04 + + -5.5031597614288330e-01 5.0374999642372131e-02 + <_> + + 0 -1 1522 -4.9518000334501266e-02 + + -2.5615389347076416e+00 1.3141700625419617e-01 + <_> + + 0 -1 1523 1.1680999770760536e-02 + + -2.4819800257682800e-01 3.9982700347900391e-01 + <_> + + 0 -1 1524 3.4563999623060226e-02 + + 1.6178800165653229e-01 -7.1418899297714233e-01 + <_> + + 0 -1 1525 -8.2909995689988136e-03 + + 2.2180099785327911e-01 -2.9181700944900513e-01 + <_> + + 0 -1 1526 -2.2358000278472900e-02 + + 3.1044098734855652e-01 -2.7280000504106283e-03 + <_> + + 0 -1 1527 -3.0801000073552132e-02 + + -9.5672702789306641e-01 -8.3400001749396324e-03 + <_> + + 0 -1 1528 4.3779000639915466e-02 + + 1.2556900084018707e-01 -1.1759619712829590e+00 + <_> + + 0 -1 1529 4.3046001344919205e-02 + + -5.8876998722553253e-02 -1.8568470478057861e+00 + <_> + + 0 -1 1530 2.7188999578356743e-02 + + 4.2858000844717026e-02 3.9036700129508972e-01 + <_> + + 0 -1 1531 9.4149997457861900e-03 + + -4.3567001819610596e-02 -1.1094470024108887e+00 + <_> + + 0 -1 1532 9.4311997294425964e-02 + + 4.0256999433040619e-02 9.8442298173904419e-01 + <_> + + 0 -1 1533 1.7025099694728851e-01 + + 2.9510000720620155e-02 -6.9509297609329224e-01 + <_> + + 0 -1 1534 -4.7148000448942184e-02 + + 1.0338569879531860e+00 6.7602001130580902e-02 + <_> + + 0 -1 1535 1.1186300218105316e-01 + + -6.8682998418807983e-02 -2.4985830783843994e+00 + <_> + + 0 -1 1536 -1.4353999868035316e-02 + + -5.9481900930404663e-01 1.5001699328422546e-01 + <_> + + 0 -1 1537 3.4024000167846680e-02 + + -6.4823001623153687e-02 -2.1382639408111572e+00 + <_> + + 0 -1 1538 2.1601999178528786e-02 + + 5.5309999734163284e-02 7.8292900323867798e-01 + <_> + + 0 -1 1539 2.1771999076008797e-02 + + -7.1279997937381268e-03 -7.2148102521896362e-01 + <_> + + 0 -1 1540 8.2416996359825134e-02 + + 1.4609499275684357e-01 -1.3636670112609863e+00 + <_> + + 0 -1 1541 8.4671996533870697e-02 + + -1.7784699797630310e-01 7.2857701778411865e-01 + <_> + + 0 -1 1542 -5.5128000676631927e-02 + + -5.9402400255203247e-01 1.9357800483703613e-01 + <_> + + 0 -1 1543 -6.4823001623153687e-02 + + -1.0783840417861938e+00 -4.0734000504016876e-02 + <_> + + 0 -1 1544 -2.2769000381231308e-02 + + 7.7900201082229614e-01 3.4960000775754452e-03 + <_> + + 0 -1 1545 5.4756000638008118e-02 + + -6.5683998167514801e-02 -1.8188409805297852e+00 + <_> + + 0 -1 1546 -8.9000001025851816e-05 + + -1.7891999334096909e-02 2.0768299698829651e-01 + <_> + + 0 -1 1547 9.8361998796463013e-02 + + -5.5946998298168182e-02 -1.4153920412063599e+00 + <_> + + 0 -1 1548 -7.0930002257227898e-03 + + 3.4135299921035767e-01 -1.2089899927377701e-01 + <_> + + 0 -1 1549 5.0278000533580780e-02 + + -2.6286700367927551e-01 2.5797298550605774e-01 + <_> + + 0 -1 1550 -5.7870000600814819e-03 + + -1.3178600370883942e-01 1.7350199818611145e-01 + <_> + + 0 -1 1551 1.3973999768495560e-02 + + 2.8518000617623329e-02 -6.1152201890945435e-01 + <_> + + 0 -1 1552 2.1449999883770943e-02 + + 2.6181999593973160e-02 3.0306598544120789e-01 + <_> + + 0 -1 1553 -2.9214000329375267e-02 + + 4.4940599799156189e-01 -2.2803099453449249e-01 + <_> + + 0 -1 1554 4.8099999548867345e-04 + + -1.9879999756813049e-01 2.0744499564170837e-01 + <_> + + 0 -1 1555 1.7109999898821115e-03 + + -5.4037201404571533e-01 6.7865997552871704e-02 + <_> + + 0 -1 1556 8.6660003289580345e-03 + + -1.3128000311553478e-02 5.2297902107238770e-01 + <_> + + 0 -1 1557 6.3657999038696289e-02 + + 6.8299002945423126e-02 -4.9235099554061890e-01 + <_> + + 0 -1 1558 -2.7968000620603561e-02 + + 6.8183898925781250e-01 7.8781001269817352e-02 + <_> + + 0 -1 1559 4.8953998833894730e-02 + + -2.0622399449348450e-01 5.0388097763061523e-01 + <_> + 169 + -3.2396929264068604e+00 + + <_> + + 0 -1 1560 -2.9312999919056892e-02 + + 7.1284699440002441e-01 -5.8230698108673096e-01 + <_> + + 0 -1 1561 1.2415099889039993e-01 + + -3.6863499879837036e-01 6.0067200660705566e-01 + <_> + + 0 -1 1562 7.9349996522068977e-03 + + -8.6008298397064209e-01 2.1724699437618256e-01 + <_> + + 0 -1 1563 3.0365999788045883e-02 + + -2.7186998724937439e-01 6.1247897148132324e-01 + <_> + + 0 -1 1564 2.5218000635504723e-02 + + -3.4748300909996033e-01 5.0427699089050293e-01 + <_> + + 0 -1 1565 1.0014000348746777e-02 + + -3.1898999214172363e-01 4.1376799345016479e-01 + <_> + + 0 -1 1566 -1.6775000840425491e-02 + + -6.9048100709915161e-01 9.4830997288227081e-02 + <_> + + 0 -1 1567 -2.6950000319629908e-03 + + -2.0829799771308899e-01 2.3737199604511261e-01 + <_> + + 0 -1 1568 4.2257998138666153e-02 + + -4.9366700649261475e-01 1.8170599639415741e-01 + <_> + + 0 -1 1569 -4.8505000770092010e-02 + + 1.3429640531539917e+00 3.9769001305103302e-02 + <_> + + 0 -1 1570 2.8992999345064163e-02 + + 4.6496000140905380e-02 -8.1643497943878174e-01 + <_> + + 0 -1 1571 -4.0089000016450882e-02 + + -7.1197801828384399e-01 2.2553899884223938e-01 + <_> + + 0 -1 1572 -4.1021998971700668e-02 + + 1.0057929754257202e+00 -1.9690200686454773e-01 + <_> + + 0 -1 1573 1.1838000267744064e-02 + + -1.2600000016391277e-02 8.0767101049423218e-01 + <_> + + 0 -1 1574 -2.1328000351786613e-02 + + -8.2023900747299194e-01 2.0524999126791954e-02 + <_> + + 0 -1 1575 -2.3904999718070030e-02 + + 5.4210501909255981e-01 -7.4767000973224640e-02 + <_> + + 0 -1 1576 1.8008999526500702e-02 + + -3.3827701210975647e-01 4.2358601093292236e-01 + <_> + + 0 -1 1577 -4.3614000082015991e-02 + + -1.1983489990234375e+00 1.5566200017929077e-01 + <_> + + 0 -1 1578 -9.2449998483061790e-03 + + -8.9029997587203979e-01 1.1003999970853329e-02 + <_> + + 0 -1 1579 4.7485001385211945e-02 + + 1.6664099693298340e-01 -9.0764498710632324e-01 + <_> + + 0 -1 1580 -1.4233999885618687e-02 + + 6.2695199251174927e-01 -2.5791200995445251e-01 + <_> + + 0 -1 1581 3.8010000716894865e-03 + + -2.8229999542236328e-01 2.6624599099159241e-01 + <_> + + 0 -1 1582 3.4330000635236502e-03 + + -6.3771998882293701e-01 9.8422996699810028e-02 + <_> + + 0 -1 1583 -2.9221000149846077e-02 + + -7.6769900321960449e-01 2.2634500265121460e-01 + <_> + + 0 -1 1584 -6.4949998632073402e-03 + + 4.5600101351737976e-01 -2.6528900861740112e-01 + <_> + + 0 -1 1585 -3.0034000054001808e-02 + + -7.6551097631454468e-01 1.4009299874305725e-01 + <_> + + 0 -1 1586 7.8360000625252724e-03 + + 4.6755999326705933e-02 -7.2356200218200684e-01 + <_> + + 0 -1 1587 8.8550001382827759e-03 + + -4.9141999334096909e-02 5.1472699642181396e-01 + <_> + + 0 -1 1588 9.5973998308181763e-02 + + -2.0068999379873276e-02 -1.0850950479507446e+00 + <_> + + 0 -1 1589 -3.2876998186111450e-02 + + -9.5875298976898193e-01 1.4543600380420685e-01 + <_> + + 0 -1 1590 -1.3384000398218632e-02 + + -7.0013600587844849e-01 2.9157999902963638e-02 + <_> + + 0 -1 1591 1.5235999599099159e-02 + + -2.8235700726509094e-01 2.5367999076843262e-01 + <_> + + 0 -1 1592 1.2054000049829483e-02 + + -2.5303399562835693e-01 4.6526700258255005e-01 + <_> + + 0 -1 1593 -7.6295003294944763e-02 + + -6.9915801286697388e-01 1.3217200338840485e-01 + <_> + + 0 -1 1594 -1.2040000408887863e-02 + + 4.5894598960876465e-01 -2.3856499791145325e-01 + <_> + + 0 -1 1595 2.1916000172495842e-02 + + 1.8268600106239319e-01 -6.1629700660705566e-01 + <_> + + 0 -1 1596 -2.7330000884830952e-03 + + -6.3257902860641479e-01 3.4219000488519669e-02 + <_> + + 0 -1 1597 -4.8652000725269318e-02 + + -1.0297729969024658e+00 1.7386500537395477e-01 + <_> + + 0 -1 1598 -1.0463999584317207e-02 + + 3.4757301211357117e-01 -2.7464100718498230e-01 + <_> + + 0 -1 1599 -6.6550001502037048e-03 + + -2.8980299830436707e-01 2.4037900567054749e-01 + <_> + + 0 -1 1600 8.5469996556639671e-03 + + -4.4340500235557556e-01 1.4267399907112122e-01 + <_> + + 0 -1 1601 1.9913999363780022e-02 + + 1.7740400135517120e-01 -2.4096299707889557e-01 + <_> + + 0 -1 1602 2.2012999281287193e-02 + + -1.0812000371515751e-02 -9.4690799713134766e-01 + <_> + + 0 -1 1603 -5.2179001271724701e-02 + + 1.6547499895095825e+00 9.6487000584602356e-02 + <_> + + 0 -1 1604 1.9698999822139740e-02 + + -6.7560002207756042e-03 -8.6311501264572144e-01 + <_> + + 0 -1 1605 2.3040000349283218e-02 + + -2.3519999813288450e-03 3.8531300425529480e-01 + <_> + + 0 -1 1606 -1.5038000419735909e-02 + + -6.1905699968338013e-01 3.1077999621629715e-02 + <_> + + 0 -1 1607 -4.9956001341342926e-02 + + 7.0657497644424438e-01 4.7880999743938446e-02 + <_> + + 0 -1 1608 -6.9269999861717224e-02 + + 3.9212900400161743e-01 -2.3848000168800354e-01 + <_> + + 0 -1 1609 4.7399997711181641e-03 + + -2.4309000000357628e-02 2.5386300683021545e-01 + <_> + + 0 -1 1610 -3.3923998475074768e-02 + + 4.6930399537086487e-01 -2.3321899771690369e-01 + <_> + + 0 -1 1611 -1.6231000423431396e-02 + + 3.2319200038909912e-01 -2.0545600354671478e-01 + <_> + + 0 -1 1612 -5.0193000584840775e-02 + + -1.2277870178222656e+00 -4.0798000991344452e-02 + <_> + + 0 -1 1613 5.6944001466035843e-02 + + 4.5184001326560974e-02 6.0197502374649048e-01 + <_> + + 0 -1 1614 4.0936999022960663e-02 + + -1.6772800683975220e-01 8.9819300174713135e-01 + <_> + + 0 -1 1615 -3.0839999672025442e-03 + + 3.3716198801994324e-01 -2.7240800857543945e-01 + <_> + + 0 -1 1616 -3.2600000500679016e-02 + + -8.5446500778198242e-01 1.9664999097585678e-02 + <_> + + 0 -1 1617 9.8480999469757080e-02 + + 5.4742000997066498e-02 6.3827300071716309e-01 + <_> + + 0 -1 1618 -3.8185000419616699e-02 + + 5.2274698019027710e-01 -2.3384800553321838e-01 + <_> + + 0 -1 1619 -4.5917000621557236e-02 + + 6.2829202413558960e-01 3.2859001308679581e-02 + <_> + + 0 -1 1620 -1.1955499649047852e-01 + + -6.1572700738906860e-01 3.4680001437664032e-02 + <_> + + 0 -1 1621 -1.2044399976730347e-01 + + -8.4380000829696655e-01 1.6530700027942657e-01 + <_> + + 0 -1 1622 7.0619001984596252e-02 + + -6.3261002302169800e-02 -1.9863929748535156e+00 + <_> + + 0 -1 1623 8.4889996796846390e-03 + + -1.7663399875164032e-01 3.8011199235916138e-01 + <_> + + 0 -1 1624 2.2710999473929405e-02 + + -2.7605999261140823e-02 -9.1921401023864746e-01 + <_> + + 0 -1 1625 4.9700000090524554e-04 + + -2.4293200671672821e-01 2.2878900170326233e-01 + <_> + + 0 -1 1626 3.4651998430490494e-02 + + -2.3705999553203583e-01 5.4010999202728271e-01 + <_> + + 0 -1 1627 -4.4700000435113907e-03 + + 3.9078998565673828e-01 -1.2693800032138824e-01 + <_> + + 0 -1 1628 2.3643000051379204e-02 + + -2.6663699746131897e-01 3.2312598824501038e-01 + <_> + + 0 -1 1629 1.2813000008463860e-02 + + 1.7540800571441650e-01 -6.0787999629974365e-01 + <_> + + 0 -1 1630 -1.1250999756157398e-02 + + -1.0852589607238770e+00 -2.8046000748872757e-02 + <_> + + 0 -1 1631 -4.1535001248121262e-02 + + 7.1887397766113281e-01 2.7982000261545181e-02 + <_> + + 0 -1 1632 -9.3470998108386993e-02 + + -1.1906319856643677e+00 -4.4810999184846878e-02 + <_> + + 0 -1 1633 -2.7249999344348907e-02 + + 6.2942498922348022e-01 9.5039997249841690e-03 + <_> + + 0 -1 1634 -2.1759999915957451e-02 + + 1.3233649730682373e+00 -1.5027000010013580e-01 + <_> + + 0 -1 1635 -9.6890004351735115e-03 + + -3.3947101235389709e-01 1.7085799574851990e-01 + <_> + + 0 -1 1636 6.9395996630191803e-02 + + -2.5657799839973450e-01 4.7652098536491394e-01 + <_> + + 0 -1 1637 3.1208999454975128e-02 + + 1.4154000580310822e-01 -3.4942001104354858e-01 + <_> + + 0 -1 1638 -4.9727000296115875e-02 + + -1.1675560474395752e+00 -4.0757998824119568e-02 + <_> + + 0 -1 1639 -2.0301999524235725e-02 + + -3.9486399292945862e-01 1.5814900398254395e-01 + <_> + + 0 -1 1640 -1.5367000363767147e-02 + + 4.9300000071525574e-01 -2.0092099905014038e-01 + <_> + + 0 -1 1641 -5.0735000520944595e-02 + + 1.8736059665679932e+00 8.6730003356933594e-02 + <_> + + 0 -1 1642 -2.0726000890135765e-02 + + -8.8938397169113159e-01 -7.3199998587369919e-03 + <_> + + 0 -1 1643 -3.0993999913334846e-02 + + -1.1664899587631226e+00 1.4274600148200989e-01 + <_> + + 0 -1 1644 -4.4269999489188194e-03 + + -6.6815102100372314e-01 4.4120000675320625e-03 + <_> + + 0 -1 1645 -4.5743998140096664e-02 + + -4.7955200076103210e-01 1.5121999382972717e-01 + <_> + + 0 -1 1646 1.6698999330401421e-02 + + 1.2048599869012833e-01 -4.5235899090766907e-01 + <_> + + 0 -1 1647 3.2210000790655613e-03 + + -7.7615000307559967e-02 2.7846598625183105e-01 + <_> + + 0 -1 1648 2.4434000253677368e-02 + + -1.9987100362777710e-01 6.7253702878952026e-01 + <_> + + 0 -1 1649 -7.9677999019622803e-02 + + 9.2222398519515991e-01 9.2557996511459351e-02 + <_> + + 0 -1 1650 4.4530000537633896e-02 + + -2.6690500974655151e-01 3.3320501446723938e-01 + <_> + + 0 -1 1651 -1.2528300285339355e-01 + + -5.4253101348876953e-01 1.3976299762725830e-01 + <_> + + 0 -1 1652 1.7971999943256378e-02 + + 1.8219999969005585e-02 -6.8048501014709473e-01 + <_> + + 0 -1 1653 1.9184000790119171e-02 + + -1.2583999894559383e-02 5.4126697778701782e-01 + <_> + + 0 -1 1654 4.0024001151323318e-02 + + -1.7638799548149109e-01 7.8810399770736694e-01 + <_> + + 0 -1 1655 1.3558999635279179e-02 + + 2.0737600326538086e-01 -4.7744300961494446e-01 + <_> + + 0 -1 1656 1.6220999881625175e-02 + + 2.3076999932527542e-02 -6.1182099580764771e-01 + <_> + + 0 -1 1657 1.1229000054299831e-02 + + -1.7728000879287720e-02 4.1764199733734131e-01 + <_> + + 0 -1 1658 3.9193000644445419e-02 + + -1.8948499858379364e-01 7.4019300937652588e-01 + <_> + + 0 -1 1659 -9.5539996400475502e-03 + + 4.0947100520133972e-01 -1.3508899509906769e-01 + <_> + + 0 -1 1660 2.7878999710083008e-02 + + -2.0350700616836548e-01 6.1625397205352783e-01 + <_> + + 0 -1 1661 -2.3600999265909195e-02 + + -1.6967060565948486e+00 1.4633199572563171e-01 + <_> + + 0 -1 1662 2.6930000633001328e-02 + + -3.0401999130845070e-02 -1.0909470319747925e+00 + <_> + + 0 -1 1663 2.8999999631196260e-04 + + -2.0076000690460205e-01 2.2314099967479706e-01 + <_> + + 0 -1 1664 -4.1124999523162842e-02 + + -4.5242199301719666e-01 5.7392001152038574e-02 + <_> + + 0 -1 1665 6.6789998672902584e-03 + + 2.3824900388717651e-01 -2.1262100338935852e-01 + <_> + + 0 -1 1666 4.7864999622106552e-02 + + -1.8194800615310669e-01 6.1918401718139648e-01 + <_> + + 0 -1 1667 -3.1679999083280563e-03 + + -2.7393200993537903e-01 2.5017300248146057e-01 + <_> + + 0 -1 1668 -8.6230002343654633e-03 + + -4.6280300617218018e-01 4.2397998273372650e-02 + <_> + + 0 -1 1669 -7.4350000359117985e-03 + + 4.1796800494194031e-01 -1.7079999670386314e-03 + <_> + + 0 -1 1670 -1.8769999733194709e-03 + + 1.4602300524711609e-01 -3.3721101284027100e-01 + <_> + + 0 -1 1671 -8.6226001381874084e-02 + + 7.5143402814865112e-01 1.0711999610066414e-02 + <_> + + 0 -1 1672 4.6833999454975128e-02 + + -1.9119599461555481e-01 4.8414900898933411e-01 + <_> + + 0 -1 1673 -9.2000002041459084e-05 + + 3.5220399498939514e-01 -1.7333300411701202e-01 + <_> + + 0 -1 1674 -1.6343999654054642e-02 + + -6.4397698640823364e-01 9.0680001303553581e-03 + <_> + + 0 -1 1675 4.5703999698162079e-02 + + 1.8216000869870186e-02 3.1970798969268799e-01 + <_> + + 0 -1 1676 -2.7382999658584595e-02 + + 1.0564049482345581e+00 -1.7276400327682495e-01 + <_> + + 0 -1 1677 -2.7602000162005424e-02 + + 2.9715499281883240e-01 -9.4600003212690353e-03 + <_> + + 0 -1 1678 7.6939999125897884e-03 + + -2.1660299599170685e-01 4.7385200858116150e-01 + <_> + + 0 -1 1679 -7.0500001311302185e-04 + + 2.4048799276351929e-01 -2.6776000857353210e-01 + <_> + + 0 -1 1680 1.1054199934005737e-01 + + -3.3539000898599625e-02 -1.0233880281448364e+00 + <_> + + 0 -1 1681 6.8765997886657715e-02 + + -4.3239998631179333e-03 5.7153397798538208e-01 + <_> + + 0 -1 1682 1.7999999690800905e-03 + + 7.7574998140335083e-02 -4.2092698812484741e-01 + <_> + + 0 -1 1683 1.9232000410556793e-01 + + 8.2021996378898621e-02 2.8810169696807861e+00 + <_> + + 0 -1 1684 1.5742099285125732e-01 + + -1.3708199560642242e-01 2.0890059471130371e+00 + <_> + + 0 -1 1685 -4.9387000501155853e-02 + + -1.8610910177230835e+00 1.4332099258899689e-01 + <_> + + 0 -1 1686 5.1929000765085220e-02 + + -1.8737000226974487e-01 5.4231601953506470e-01 + <_> + + 0 -1 1687 4.9965001642704010e-02 + + 1.4175300300121307e-01 -1.5625779628753662e+00 + <_> + + 0 -1 1688 -4.2633000761270523e-02 + + 1.6059479713439941e+00 -1.4712899923324585e-01 + <_> + + 0 -1 1689 -3.7553999572992325e-02 + + -8.0974900722503662e-01 1.3256999850273132e-01 + <_> + + 0 -1 1690 -3.7174999713897705e-02 + + -1.3945020437240601e+00 -5.7055000215768814e-02 + <_> + + 0 -1 1691 1.3945999555289745e-02 + + 3.3427000045776367e-02 5.7474797964096069e-01 + <_> + + 0 -1 1692 -4.4800000614486635e-04 + + -5.5327498912811279e-01 2.1952999755740166e-02 + <_> + + 0 -1 1693 3.1993001699447632e-02 + + 2.0340999588370323e-02 3.7459200620651245e-01 + <_> + + 0 -1 1694 -4.2799999937415123e-03 + + 4.4428700208663940e-01 -2.2999699413776398e-01 + <_> + + 0 -1 1695 9.8550003021955490e-03 + + 1.8315799534320831e-01 -4.0964999794960022e-01 + <_> + + 0 -1 1696 9.3356996774673462e-02 + + -6.3661001622676849e-02 -1.6929290294647217e+00 + <_> + + 0 -1 1697 1.7209999263286591e-02 + + 2.0153899490833282e-01 -4.6061098575592041e-01 + <_> + + 0 -1 1698 8.4319999441504478e-03 + + -3.2003998756408691e-01 1.5312199294567108e-01 + <_> + + 0 -1 1699 -1.4054999686777592e-02 + + 8.6882400512695312e-01 3.2575000077486038e-02 + <_> + + 0 -1 1700 -7.7180000953376293e-03 + + 6.3686698675155640e-01 -1.8425500392913818e-01 + <_> + + 0 -1 1701 2.8005000203847885e-02 + + 1.7357499897480011e-01 -4.7883599996566772e-01 + <_> + + 0 -1 1702 -1.8884999677538872e-02 + + 2.4101600050926208e-01 -2.6547598838806152e-01 + <_> + + 0 -1 1703 -1.8585000187158585e-02 + + 5.4232501983642578e-01 5.3633000701665878e-02 + <_> + + 0 -1 1704 -3.6437001079320908e-02 + + 2.3908898830413818e+00 -1.3634699583053589e-01 + <_> + + 0 -1 1705 3.2455001026391983e-02 + + 1.5910699963569641e-01 -6.7581498622894287e-01 + <_> + + 0 -1 1706 5.9781998395919800e-02 + + -2.3479999508708715e-03 -7.3053699731826782e-01 + <_> + + 0 -1 1707 9.8209995776414871e-03 + + -1.1444099992513657e-01 3.0570301413536072e-01 + <_> + + 0 -1 1708 -3.5163998603820801e-02 + + -1.0511469841003418e+00 -3.3103000372648239e-02 + <_> + + 0 -1 1709 2.7429999317973852e-03 + + -2.0135399699211121e-01 3.2754099369049072e-01 + <_> + + 0 -1 1710 8.1059997901320457e-03 + + -2.1383500099182129e-01 4.3362098932266235e-01 + <_> + + 0 -1 1711 8.8942997157573700e-02 + + 1.0940899699926376e-01 -4.7609338760375977e+00 + <_> + + 0 -1 1712 -3.0054999515414238e-02 + + -1.7169300317764282e+00 -6.0919001698493958e-02 + <_> + + 0 -1 1713 -2.1734999492764473e-02 + + 6.4778900146484375e-01 -3.2830998301506042e-02 + <_> + + 0 -1 1714 3.7648998200893402e-02 + + -1.0060000233352184e-02 -7.6569098234176636e-01 + <_> + + 0 -1 1715 2.7189999818801880e-03 + + 1.9888900220394135e-01 -8.2479000091552734e-02 + <_> + + 0 -1 1716 -1.0548000223934650e-02 + + -8.6613601446151733e-01 -2.5986000895500183e-02 + <_> + + 0 -1 1717 1.2966300547122955e-01 + + 1.3911999762058258e-01 -2.2271950244903564e+00 + <_> + + 0 -1 1718 -1.7676999792456627e-02 + + 3.3967700600624084e-01 -2.3989599943161011e-01 + <_> + + 0 -1 1719 -7.7051997184753418e-02 + + -2.5017969608306885e+00 1.2841999530792236e-01 + <_> + + 0 -1 1720 -1.9230000674724579e-02 + + 5.0641202926635742e-01 -1.9751599431037903e-01 + <_> + + 0 -1 1721 -5.1222998648881912e-02 + + -2.9333369731903076e+00 1.3858500123023987e-01 + <_> + + 0 -1 1722 2.0830000285059214e-03 + + -6.0043597221374512e-01 2.9718000441789627e-02 + <_> + + 0 -1 1723 2.5418000295758247e-02 + + 3.3915799856185913e-01 -1.4392000436782837e-01 + <_> + + 0 -1 1724 -2.3905999958515167e-02 + + -1.1082680225372314e+00 -4.7377001494169235e-02 + <_> + + 0 -1 1725 -6.3740001060068607e-03 + + 4.4533699750900269e-01 -6.7052997648715973e-02 + <_> + + 0 -1 1726 -3.7698999047279358e-02 + + -1.0406579971313477e+00 -4.1790001094341278e-02 + <_> + + 0 -1 1727 2.1655100584030151e-01 + + 3.3863000571727753e-02 8.2017302513122559e-01 + <_> + + 0 -1 1728 -1.3400999829173088e-02 + + 5.2903497219085693e-01 -1.9133000075817108e-01 + <_> + 196 + -3.2103500366210938e+00 + + <_> + + 0 -1 1729 7.1268998086452484e-02 + + -5.3631198406219482e-01 6.0715299844741821e-01 + <_> + + 0 -1 1730 5.6111000478267670e-02 + + -5.0141602754592896e-01 4.3976101279258728e-01 + <_> + + 0 -1 1731 4.0463998913764954e-02 + + -3.2922199368476868e-01 5.4834699630737305e-01 + <_> + + 0 -1 1732 6.3155002892017365e-02 + + -3.1701698899269104e-01 4.6152999997138977e-01 + <_> + + 0 -1 1733 1.0320999659597874e-02 + + 1.0694999992847443e-01 -9.8243898153305054e-01 + <_> + + 0 -1 1734 6.2606997787952423e-02 + + -1.4329700171947479e-01 7.1095001697540283e-01 + <_> + + 0 -1 1735 -3.9416000247001648e-02 + + 9.4380199909210205e-01 -2.1572099626064301e-01 + <_> + + 0 -1 1736 -5.3960001096129417e-03 + + -5.4611998796463013e-01 2.5303798913955688e-01 + <_> + + 0 -1 1737 1.0773199796676636e-01 + + 1.2496000155806541e-02 -1.0809199810028076e+00 + <_> + + 0 -1 1738 1.6982000321149826e-02 + + -3.1536400318145752e-01 5.1239997148513794e-01 + <_> + + 0 -1 1739 3.1216999515891075e-02 + + -4.5199999585747719e-03 -1.2443480491638184e+00 + <_> + + 0 -1 1740 -2.3106999695301056e-02 + + -7.6492899656295776e-01 2.0640599727630615e-01 + <_> + + 0 -1 1741 -1.1203999631106853e-02 + + 2.4092699587345123e-01 -3.5142099857330322e-01 + <_> + + 0 -1 1742 -4.7479998320341110e-03 + + -9.7007997334003448e-02 2.0638099312782288e-01 + <_> + + 0 -1 1743 -1.7358999699354172e-02 + + -7.9020297527313232e-01 2.1852999925613403e-02 + <_> + + 0 -1 1744 1.8851999193429947e-02 + + -1.0394600033760071e-01 5.4844200611114502e-01 + <_> + + 0 -1 1745 7.2249998338520527e-03 + + -4.0409401059150696e-01 2.6763799786567688e-01 + <_> + + 0 -1 1746 1.8915999680757523e-02 + + 2.0508000254631042e-01 -1.0206340551376343e+00 + <_> + + 0 -1 1747 3.1156999990344048e-02 + + 1.2400000123307109e-03 -8.7293499708175659e-01 + <_> + + 0 -1 1748 2.0951999351382256e-02 + + -5.5559999309480190e-03 8.0356198549270630e-01 + <_> + + 0 -1 1749 1.1291000060737133e-02 + + -3.6478400230407715e-01 2.2767899930477142e-01 + <_> + + 0 -1 1750 -5.7011000812053680e-02 + + -1.4295619726181030e+00 1.4322000741958618e-01 + <_> + + 0 -1 1751 7.2194002568721771e-02 + + -4.1850000619888306e-02 -1.9111829996109009e+00 + <_> + + 0 -1 1752 -1.9874000921845436e-02 + + 2.6425498723983765e-01 -3.2617700099945068e-01 + <_> + + 0 -1 1753 -1.6692999750375748e-02 + + -8.3907800912857056e-01 4.0799999260343611e-04 + <_> + + 0 -1 1754 -3.9834998548030853e-02 + + -4.8858499526977539e-01 1.6436100006103516e-01 + <_> + + 0 -1 1755 2.7009999379515648e-02 + + -1.8862499296665192e-01 8.3419400453567505e-01 + <_> + + 0 -1 1756 -3.9420002140104771e-03 + + 2.3231500387191772e-01 -7.2360001504421234e-02 + <_> + + 0 -1 1757 2.2833000868558884e-02 + + -3.5884000360965729e-02 -1.1549400091171265e+00 + <_> + + 0 -1 1758 -6.8888001143932343e-02 + + -1.7837309837341309e+00 1.5159000456333160e-01 + <_> + + 0 -1 1759 4.3097000569105148e-02 + + -2.1608099341392517e-01 5.0624102354049683e-01 + <_> + + 0 -1 1760 8.6239995434880257e-03 + + -1.7795599997043610e-01 2.8957900404930115e-01 + <_> + + 0 -1 1761 1.4561000280082226e-02 + + -1.1408000253140926e-02 -8.9402002096176147e-01 + <_> + + 0 -1 1762 -1.1501000262796879e-02 + + 3.0171999335289001e-01 -4.3659001588821411e-02 + <_> + + 0 -1 1763 -1.0971499979496002e-01 + + -9.5147097110748291e-01 -1.9973000511527061e-02 + <_> + + 0 -1 1764 4.5228000730276108e-02 + + 3.3110998570919037e-02 9.6619802713394165e-01 + <_> + + 0 -1 1765 -2.7047999203205109e-02 + + 9.7963601350784302e-01 -1.7261900007724762e-01 + <_> + + 0 -1 1766 1.8030999228358269e-02 + + -2.0801000297069550e-02 2.7385899424552917e-01 + <_> + + 0 -1 1767 5.0524998456239700e-02 + + -5.6802999228239059e-02 -1.7775089740753174e+00 + <_> + + 0 -1 1768 -2.9923999682068825e-02 + + 6.5329200029373169e-01 -2.3537000641226768e-02 + <_> + + 0 -1 1769 3.8058001548051834e-02 + + 2.6317000389099121e-02 -7.0665699243545532e-01 + <_> + + 0 -1 1770 1.8563899397850037e-01 + + -5.6039998307824135e-03 3.2873699069023132e-01 + <_> + + 0 -1 1771 -4.0670000016689301e-03 + + 3.4204798936843872e-01 -3.0171599984169006e-01 + <_> + + 0 -1 1772 1.0108999907970428e-02 + + -7.3600001633167267e-03 5.7981598377227783e-01 + <_> + + 0 -1 1773 -1.1567000299692154e-02 + + -5.2722197771072388e-01 4.6447999775409698e-02 + <_> + + 0 -1 1774 -6.5649999305605888e-03 + + -5.8529102802276611e-01 1.9101899862289429e-01 + <_> + + 0 -1 1775 1.0582000017166138e-02 + + 2.1073000505566597e-02 -6.8892598152160645e-01 + <_> + + 0 -1 1776 -2.0304000005125999e-02 + + -3.6400699615478516e-01 1.5338799357414246e-01 + <_> + + 0 -1 1777 2.3529999889433384e-03 + + 3.6164000630378723e-02 -5.9825098514556885e-01 + <_> + + 0 -1 1778 -1.4690000098198652e-03 + + -1.4707699418067932e-01 3.7507998943328857e-01 + <_> + + 0 -1 1779 8.6449999362230301e-03 + + -2.1708500385284424e-01 5.1936799287796021e-01 + <_> + + 0 -1 1780 -2.4326000362634659e-02 + + -1.0846769809722900e+00 1.4084799587726593e-01 + <_> + + 0 -1 1781 7.4418999254703522e-02 + + -1.5513800084590912e-01 1.1822769641876221e+00 + <_> + + 0 -1 1782 1.7077999189496040e-02 + + 4.4231001287698746e-02 9.1561102867126465e-01 + <_> + + 0 -1 1783 -2.4577999487519264e-02 + + -1.5504100322723389e+00 -5.4745998233556747e-02 + <_> + + 0 -1 1784 3.0205000191926956e-02 + + 1.6662800312042236e-01 -1.0001239776611328e+00 + <_> + + 0 -1 1785 1.2136000208556652e-02 + + -7.7079099416732788e-01 -4.8639997839927673e-03 + <_> + + 0 -1 1786 8.6717002093791962e-02 + + 1.1061699688434601e-01 -1.6857999563217163e+00 + <_> + + 0 -1 1787 -4.2309001088142395e-02 + + 1.1075930595397949e+00 -1.5438599884510040e-01 + <_> + + 0 -1 1788 -2.6420000940561295e-03 + + 2.7451899647712708e-01 -1.8456199765205383e-01 + <_> + + 0 -1 1789 -5.6662000715732574e-02 + + -8.0625599622726440e-01 -1.6928000375628471e-02 + <_> + + 0 -1 1790 2.3475000634789467e-02 + + 1.4187699556350708e-01 -2.5500899553298950e-01 + <_> + + 0 -1 1791 -2.0803000777959824e-02 + + 1.9826300442218781e-01 -3.1171199679374695e-01 + <_> + + 0 -1 1792 7.2599998675286770e-03 + + -5.0590999424457550e-02 4.1923800110816956e-01 + <_> + + 0 -1 1793 3.4160000085830688e-01 + + -1.6674900054931641e-01 9.2748600244522095e-01 + <_> + + 0 -1 1794 6.2029999680817127e-03 + + -1.2625899910926819e-01 4.0445300936698914e-01 + <_> + + 0 -1 1795 3.2692000269889832e-02 + + -3.2634999603033066e-02 -9.8939800262451172e-01 + <_> + + 0 -1 1796 2.1100000594742596e-04 + + -6.4534001052379608e-02 2.5473698973655701e-01 + <_> + + 0 -1 1797 7.2100001852959394e-04 + + -3.6618599295616150e-01 1.1973100155591965e-01 + <_> + + 0 -1 1798 5.4490998387336731e-02 + + 1.2073499709367752e-01 -1.0291390419006348e+00 + <_> + + 0 -1 1799 -1.0141000151634216e-02 + + -5.2177202701568604e-01 3.3734999597072601e-02 + <_> + + 0 -1 1800 -1.8815999850630760e-02 + + 6.5181797742843628e-01 1.3399999588727951e-03 + <_> + + 0 -1 1801 -5.3480002097785473e-03 + + 1.7370699346065521e-01 -3.4132000803947449e-01 + <_> + + 0 -1 1802 -1.0847000405192375e-02 + + -1.9699899852275848e-01 1.5045499801635742e-01 + <_> + + 0 -1 1803 -4.9926001578569412e-02 + + -5.0888502597808838e-01 3.0762000009417534e-02 + <_> + + 0 -1 1804 1.2160000391304493e-02 + + -6.9251999258995056e-02 1.8745499849319458e-01 + <_> + + 0 -1 1805 -2.2189998999238014e-03 + + -4.0849098563194275e-01 7.9954996705055237e-02 + <_> + + 0 -1 1806 3.1580000650137663e-03 + + -2.1124599874019623e-01 2.2366400063037872e-01 + <_> + + 0 -1 1807 4.1439998894929886e-03 + + -4.9900299310684204e-01 6.2917001545429230e-02 + <_> + + 0 -1 1808 -7.3730000294744968e-03 + + -2.0553299784660339e-01 2.2096699476242065e-01 + <_> + + 0 -1 1809 5.1812000572681427e-02 + + 1.8096800148487091e-01 -4.3495801091194153e-01 + <_> + + 0 -1 1810 1.8340000882744789e-02 + + 1.5200000256299973e-02 3.7991699576377869e-01 + <_> + + 0 -1 1811 1.7490799725055695e-01 + + -2.0920799672603607e-01 4.0013000369071960e-01 + <_> + + 0 -1 1812 5.3993999958038330e-02 + + 2.4751600623130798e-01 -2.6712900400161743e-01 + <_> + + 0 -1 1813 -3.2033199071884155e-01 + + -1.9094380140304565e+00 -6.6960997879505157e-02 + <_> + + 0 -1 1814 -2.7060000225901604e-02 + + -7.1371299028396606e-01 1.5904599428176880e-01 + <_> + + 0 -1 1815 7.7463999390602112e-02 + + -1.6970199346542358e-01 7.7552998065948486e-01 + <_> + + 0 -1 1816 2.3771999403834343e-02 + + 1.9021899998188019e-01 -6.0162097215652466e-01 + <_> + + 0 -1 1817 1.1501000262796879e-02 + + 7.7039999887347221e-03 -6.1730301380157471e-01 + <_> + + 0 -1 1818 3.2616000622510910e-02 + + 1.7159199714660645e-01 -7.0978200435638428e-01 + <_> + + 0 -1 1819 -4.4383000582456589e-02 + + -2.2606229782104492e+00 -7.3276996612548828e-02 + <_> + + 0 -1 1820 -5.8476001024246216e-02 + + 2.4087750911712646e+00 8.3091996610164642e-02 + <_> + + 0 -1 1821 1.9303999841213226e-02 + + -2.7082300186157227e-01 2.7369999885559082e-01 + <_> + + 0 -1 1822 -4.4705998152494431e-02 + + 3.1355598568916321e-01 -6.2492001801729202e-02 + <_> + + 0 -1 1823 -6.0334999114274979e-02 + + -1.4515119791030884e+00 -5.8761000633239746e-02 + <_> + + 0 -1 1824 1.1667000129818916e-02 + + -1.8084999173879623e-02 5.0479698181152344e-01 + <_> + + 0 -1 1825 2.8009999543428421e-02 + + -2.3302899301052094e-01 3.0708700418472290e-01 + <_> + + 0 -1 1826 6.5397001802921295e-02 + + 1.4135900139808655e-01 -5.0010901689529419e-01 + <_> + + 0 -1 1827 9.6239997074007988e-03 + + -2.2054600715637207e-01 3.9191201329231262e-01 + <_> + + 0 -1 1828 2.5510000996291637e-03 + + -1.1381500214338303e-01 2.0032300055027008e-01 + <_> + + 0 -1 1829 3.1847000122070312e-02 + + 2.5476999580860138e-02 -5.3326398134231567e-01 + <_> + + 0 -1 1830 3.3055000007152557e-02 + + 1.7807699739933014e-01 -6.2793898582458496e-01 + <_> + + 0 -1 1831 4.7600999474525452e-02 + + -1.4747899770736694e-01 1.4204180240631104e+00 + <_> + + 0 -1 1832 -1.9571999087929726e-02 + + -5.2693498134613037e-01 1.5838600695133209e-01 + <_> + + 0 -1 1833 -5.4730001837015152e-02 + + 8.8231599330902100e-01 -1.6627800464630127e-01 + <_> + + 0 -1 1834 -2.2686000913381577e-02 + + -4.8386898636817932e-01 1.5000100433826447e-01 + <_> + + 0 -1 1835 1.0713200271129608e-01 + + -2.1336199343204498e-01 4.2333900928497314e-01 + <_> + + 0 -1 1836 -3.6380000412464142e-02 + + -7.4198000133037567e-02 1.4589400589466095e-01 + <_> + + 0 -1 1837 1.3935999944806099e-02 + + -2.4911600351333618e-01 2.6771199703216553e-01 + <_> + + 0 -1 1838 2.0991999655961990e-02 + + 8.7959999218583107e-03 4.3064999580383301e-01 + <_> + + 0 -1 1839 4.9118999391794205e-02 + + -1.7591999471187592e-01 6.9282901287078857e-01 + <_> + + 0 -1 1840 3.6315999925136566e-02 + + 1.3145299255847931e-01 -3.3597299456596375e-01 + <_> + + 0 -1 1841 4.1228000074625015e-02 + + -4.5692000538110733e-02 -1.3515930175781250e+00 + <_> + + 0 -1 1842 1.5672000125050545e-02 + + 1.7544099688529968e-01 -6.0550000518560410e-02 + <_> + + 0 -1 1843 -1.6286000609397888e-02 + + -1.1308189630508423e+00 -3.9533000439405441e-02 + <_> + + 0 -1 1844 -3.0229999683797359e-03 + + -2.2454300522804260e-01 2.3628099262714386e-01 + <_> + + 0 -1 1845 -1.3786299526691437e-01 + + 4.5376899838447571e-01 -2.1098700165748596e-01 + <_> + + 0 -1 1846 -9.6760001033544540e-03 + + -1.5105099976062775e-01 2.0781700313091278e-01 + <_> + + 0 -1 1847 -2.4839999154210091e-02 + + -6.8350297212600708e-01 -8.0040004104375839e-03 + <_> + + 0 -1 1848 -1.3964399695396423e-01 + + 6.5011298656463623e-01 4.6544000506401062e-02 + <_> + + 0 -1 1849 -8.2153998315334320e-02 + + 4.4887199997901917e-01 -2.3591999709606171e-01 + <_> + + 0 -1 1850 3.8449999410659075e-03 + + -8.8173002004623413e-02 2.7346798777580261e-01 + <_> + + 0 -1 1851 -6.6579999402165413e-03 + + -4.6866598725318909e-01 7.7001996338367462e-02 + <_> + + 0 -1 1852 -1.5898000448942184e-02 + + 2.9268398880958557e-01 -2.1941000595688820e-02 + <_> + + 0 -1 1853 -5.0946000963449478e-02 + + -1.2093789577484131e+00 -4.2109999805688858e-02 + <_> + + 0 -1 1854 1.6837999224662781e-02 + + -4.5595999807119370e-02 5.0180697441101074e-01 + <_> + + 0 -1 1855 1.5918999910354614e-02 + + -2.6904299855232239e-01 2.6516300439834595e-01 + <_> + + 0 -1 1856 3.6309999413788319e-03 + + -1.3046100735664368e-01 3.1807100772857666e-01 + <_> + + 0 -1 1857 -8.6144998669624329e-02 + + 1.9443659782409668e+00 -1.3978299498558044e-01 + <_> + + 0 -1 1858 3.3140998333692551e-02 + + 1.5266799926757812e-01 -3.0866000801324844e-02 + <_> + + 0 -1 1859 -3.9679999463260174e-03 + + -7.1202301979064941e-01 -1.3844000175595284e-02 + <_> + + 0 -1 1860 -2.4008000269532204e-02 + + 9.2007797956466675e-01 4.6723999083042145e-02 + <_> + + 0 -1 1861 8.7320003658533096e-03 + + -2.2567300498485565e-01 3.1931799650192261e-01 + <_> + + 0 -1 1862 -2.7786999940872192e-02 + + -7.2337102890014648e-01 1.7018599808216095e-01 + <_> + + 0 -1 1863 -1.9455300271511078e-01 + + 1.2461860179901123e+00 -1.4736199378967285e-01 + <_> + + 0 -1 1864 -1.0869699716567993e-01 + + -1.4465179443359375e+00 1.2145300209522247e-01 + <_> + + 0 -1 1865 -1.9494999200105667e-02 + + -7.8153097629547119e-01 -2.3732999339699745e-02 + <_> + + 0 -1 1866 3.0650000553578138e-03 + + -8.5471397638320923e-01 1.6686999797821045e-01 + <_> + + 0 -1 1867 5.9193998575210571e-02 + + -1.4853699505329132e-01 1.1273469924926758e+00 + <_> + + 0 -1 1868 -5.4207999259233475e-02 + + 5.4726999998092651e-01 3.5523999482393265e-02 + <_> + + 0 -1 1869 -3.9324998855590820e-02 + + 3.6642599105834961e-01 -2.0543999969959259e-01 + <_> + + 0 -1 1870 8.2278996706008911e-02 + + -3.5007998347282410e-02 5.3994202613830566e-01 + <_> + + 0 -1 1871 -7.4479999020695686e-03 + + -6.1537498235702515e-01 -3.5319998860359192e-03 + <_> + + 0 -1 1872 7.3770000599324703e-03 + + -6.5591000020503998e-02 4.1961398720741272e-01 + <_> + + 0 -1 1873 7.0779998786747456e-03 + + -3.4129500389099121e-01 1.2536799907684326e-01 + <_> + + 0 -1 1874 -1.5581999905407429e-02 + + -3.0240398645401001e-01 2.1511000394821167e-01 + <_> + + 0 -1 1875 -2.7399999089539051e-03 + + 7.6553001999855042e-02 -4.1060501337051392e-01 + <_> + + 0 -1 1876 -7.0600003004074097e-02 + + -9.7356200218200684e-01 1.1241800338029861e-01 + <_> + + 0 -1 1877 -1.1706000193953514e-02 + + 1.8560700118541718e-01 -2.9755198955535889e-01 + <_> + + 0 -1 1878 7.1499997284263372e-04 + + -5.9650000184774399e-02 2.4824699759483337e-01 + <_> + + 0 -1 1879 -3.6866001784801483e-02 + + 3.2751700282096863e-01 -2.3059600591659546e-01 + <_> + + 0 -1 1880 -3.2526999711990356e-02 + + -2.9320299625396729e-01 1.5427699685096741e-01 + <_> + + 0 -1 1881 -7.4813999235630035e-02 + + -1.2143570184707642e+00 -5.2244000136852264e-02 + <_> + + 0 -1 1882 4.1469998657703400e-02 + + 1.3062499463558197e-01 -2.3274369239807129e+00 + <_> + + 0 -1 1883 -2.8880000114440918e-02 + + -6.6074597835540771e-01 -9.0960003435611725e-03 + <_> + + 0 -1 1884 4.6381998807191849e-02 + + 1.6630199551582336e-01 -6.6949498653411865e-01 + <_> + + 0 -1 1885 2.5424998998641968e-01 + + -5.4641999304294586e-02 -1.2676080465316772e+00 + <_> + + 0 -1 1886 2.4000001139938831e-03 + + 2.0276799798011780e-01 1.4667999930679798e-02 + <_> + + 0 -1 1887 -8.2805998623371124e-02 + + -7.8713601827621460e-01 -2.4468999356031418e-02 + <_> + + 0 -1 1888 -1.1438000015914440e-02 + + 2.8623399138450623e-01 -3.0894000083208084e-02 + <_> + + 0 -1 1889 -1.2913399934768677e-01 + + 1.7292929887771606e+00 -1.4293900132179260e-01 + <_> + + 0 -1 1890 3.8552999496459961e-02 + + 1.9232999533414841e-02 3.7732601165771484e-01 + <_> + + 0 -1 1891 1.0191400349140167e-01 + + -7.4533998966217041e-02 -3.3868899345397949e+00 + <_> + + 0 -1 1892 -1.9068000838160515e-02 + + 3.1814101338386536e-01 1.9261000677943230e-02 + <_> + + 0 -1 1893 -6.0775000602006912e-02 + + 7.6936298608779907e-01 -1.7644000053405762e-01 + <_> + + 0 -1 1894 2.4679999798536301e-02 + + 1.8396499752998352e-01 -3.0868801474571228e-01 + <_> + + 0 -1 1895 2.6759000495076180e-02 + + -2.3454900085926056e-01 3.3056598901748657e-01 + <_> + + 0 -1 1896 1.4969999901950359e-02 + + 1.7213599383831024e-01 -1.8248899281024933e-01 + <_> + + 0 -1 1897 2.6142999529838562e-02 + + -4.6463999897241592e-02 -1.1318379640579224e+00 + <_> + + 0 -1 1898 -3.7512000650167465e-02 + + 8.0404001474380493e-01 6.9660000503063202e-02 + <_> + + 0 -1 1899 -5.3229997865855694e-03 + + -8.1884402036666870e-01 -1.8224999308586121e-02 + <_> + + 0 -1 1900 1.7813000828027725e-02 + + 1.4957800507545471e-01 -1.8667200207710266e-01 + <_> + + 0 -1 1901 -3.4010000526905060e-02 + + -7.2852301597595215e-01 -1.6615999862551689e-02 + <_> + + 0 -1 1902 -1.5953000634908676e-02 + + 5.6944000720977783e-01 1.3832000084221363e-02 + <_> + + 0 -1 1903 1.9743999466300011e-02 + + 4.0525000542402267e-02 -4.1773399710655212e-01 + <_> + + 0 -1 1904 -1.0374800115823746e-01 + + -1.9825149774551392e+00 1.1960200220346451e-01 + <_> + + 0 -1 1905 -1.9285000860691071e-02 + + 5.0230598449707031e-01 -1.9745899736881256e-01 + <_> + + 0 -1 1906 -1.2780000455677509e-02 + + 4.0195000171661377e-01 -2.6957999914884567e-02 + <_> + + 0 -1 1907 -1.6352999955415726e-02 + + -7.6608800888061523e-01 -2.4209000170230865e-02 + <_> + + 0 -1 1908 -1.2763699889183044e-01 + + 8.6578500270843506e-01 6.4205996692180634e-02 + <_> + + 0 -1 1909 1.9068999215960503e-02 + + -5.5929797887802124e-01 -1.6880000475794077e-03 + <_> + + 0 -1 1910 3.2480999827384949e-02 + + 4.0722001343965530e-02 4.8925098776817322e-01 + <_> + + 0 -1 1911 9.4849998131394386e-03 + + -1.9231900572776794e-01 5.1139700412750244e-01 + <_> + + 0 -1 1912 5.0470000132918358e-03 + + 1.8706800043582916e-01 -1.6113600134849548e-01 + <_> + + 0 -1 1913 4.1267998516559601e-02 + + -4.8817999660968781e-02 -1.1326299905776978e+00 + <_> + + 0 -1 1914 -7.6358996331691742e-02 + + 1.4169390201568604e+00 8.7319999933242798e-02 + <_> + + 0 -1 1915 -7.2834998369216919e-02 + + 1.3189860582351685e+00 -1.4819100499153137e-01 + <_> + + 0 -1 1916 5.9576999396085739e-02 + + 4.8376999795436859e-02 8.5611802339553833e-01 + <_> + + 0 -1 1917 2.0263999700546265e-02 + + -2.1044099330902100e-01 3.3858999609947205e-01 + <_> + + 0 -1 1918 -8.0301001667976379e-02 + + -1.2464400529861450e+00 1.1857099831104279e-01 + <_> + + 0 -1 1919 -1.7835000529885292e-02 + + 2.5782299041748047e-01 -2.4564799666404724e-01 + <_> + + 0 -1 1920 1.1431000195443630e-02 + + 2.2949799895286560e-01 -2.9497599601745605e-01 + <_> + + 0 -1 1921 -2.5541000068187714e-02 + + -8.6252999305725098e-01 -7.0400000549852848e-04 + <_> + + 0 -1 1922 -7.6899997657164931e-04 + + 3.1511399149894714e-01 -1.4349000155925751e-01 + <_> + + 0 -1 1923 -1.4453999698162079e-02 + + 2.5148499011993408e-01 -2.8232899308204651e-01 + <_> + + 0 -1 1924 8.6730001494288445e-03 + + 2.6601400971412659e-01 -2.8190800547599792e-01 + <_> + 197 + -3.2772979736328125e+00 + + <_> + + 0 -1 1925 5.4708998650312424e-02 + + -5.4144299030303955e-01 6.1043000221252441e-01 + <_> + + 0 -1 1926 -1.0838799923658371e-01 + + 7.1739900112152100e-01 -4.1196098923683167e-01 + <_> + + 0 -1 1927 2.2996999323368073e-02 + + -5.8269798755645752e-01 2.9645600914955139e-01 + <_> + + 0 -1 1928 2.7540000155568123e-03 + + -7.4243897199630737e-01 1.4183300733566284e-01 + <_> + + 0 -1 1929 -2.1520000882446766e-03 + + 1.7879900336265564e-01 -6.8548601865768433e-01 + <_> + + 0 -1 1930 -2.2559000179171562e-02 + + -1.0775549411773682e+00 1.2388999760150909e-01 + <_> + + 0 -1 1931 8.3025000989437103e-02 + + 2.4500999599695206e-02 -1.0251879692077637e+00 + <_> + + 0 -1 1932 -6.6740000620484352e-03 + + -4.5283100008964539e-01 2.1230199933052063e-01 + <_> + + 0 -1 1933 7.6485000550746918e-02 + + -2.6972699165344238e-01 4.8580199480056763e-01 + <_> + + 0 -1 1934 5.4910001344978809e-03 + + -4.8871201276779175e-01 3.1616398692131042e-01 + <_> + + 0 -1 1935 -1.0414999909698963e-02 + + 4.1512900590896606e-01 -3.0044800043106079e-01 + <_> + + 0 -1 1936 2.7607999742031097e-02 + + 1.6203799843788147e-01 -9.9868500232696533e-01 + <_> + + 0 -1 1937 -2.3272000253200531e-02 + + -1.1024399995803833e+00 2.1124999970197678e-02 + <_> + + 0 -1 1938 -5.5619999766349792e-02 + + 6.5033102035522461e-01 -2.7938000857830048e-02 + <_> + + 0 -1 1939 -4.0631998330354691e-02 + + 4.2117300629615784e-01 -2.6763799786567688e-01 + <_> + + 0 -1 1940 -7.3560001328587532e-03 + + 3.5277798771858215e-01 -3.7854000926017761e-01 + <_> + + 0 -1 1941 1.7007000744342804e-02 + + -2.9189500212669373e-01 4.1053798794746399e-01 + <_> + + 0 -1 1942 -3.7034001201391220e-02 + + -1.3216309547424316e+00 1.2966500222682953e-01 + <_> + + 0 -1 1943 -1.9633000716567039e-02 + + -8.7702298164367676e-01 1.0799999581649899e-03 + <_> + + 0 -1 1944 -2.3546999320387840e-02 + + 2.6106101274490356e-01 -2.1481400728225708e-01 + <_> + + 0 -1 1945 -4.3352998793125153e-02 + + -9.9089699983596802e-01 -9.9560003727674484e-03 + <_> + + 0 -1 1946 -2.2183999419212341e-02 + + 6.3454401493072510e-01 -5.6547001004219055e-02 + <_> + + 0 -1 1947 1.6530999913811684e-02 + + 2.4664999917149544e-02 -7.3326802253723145e-01 + <_> + + 0 -1 1948 -3.2744001597166061e-02 + + -5.6297200918197632e-01 1.6640299558639526e-01 + <_> + + 0 -1 1949 7.1415998041629791e-02 + + -3.0000001424923539e-04 -9.3286401033401489e-01 + <_> + + 0 -1 1950 8.0999999772757292e-04 + + -9.5380000770092010e-02 2.5184699892997742e-01 + <_> + + 0 -1 1951 -8.4090000018477440e-03 + + -6.5496802330017090e-01 6.7300997674465179e-02 + <_> + + 0 -1 1952 -1.7254000529646873e-02 + + -4.6492999792098999e-01 1.6070899367332458e-01 + <_> + + 0 -1 1953 -1.8641000613570213e-02 + + -1.0594010353088379e+00 -1.9617000594735146e-02 + <_> + + 0 -1 1954 -9.1979997232556343e-03 + + 5.0716197490692139e-01 -1.5339200198650360e-01 + <_> + + 0 -1 1955 1.8538000062108040e-02 + + -3.0498200654983521e-01 7.3506200313568115e-01 + <_> + + 0 -1 1956 -5.0335001200437546e-02 + + -1.1140480041503906e+00 1.8000100553035736e-01 + <_> + + 0 -1 1957 -2.3529000580310822e-02 + + -8.6907899379730225e-01 -1.2459999881684780e-02 + <_> + + 0 -1 1958 -2.7100000530481339e-02 + + 6.5942901372909546e-01 -3.5323999822139740e-02 + <_> + + 0 -1 1959 6.5879998728632927e-03 + + -2.2953400015830994e-01 4.2425099015235901e-01 + <_> + + 0 -1 1960 2.3360000923275948e-02 + + 1.8356199562549591e-01 -9.8587298393249512e-01 + <_> + + 0 -1 1961 1.2946999631822109e-02 + + -3.3147400617599487e-01 2.1323199570178986e-01 + <_> + + 0 -1 1962 -6.6559999249875546e-03 + + -1.1951400339603424e-01 2.9752799868583679e-01 + <_> + + 0 -1 1963 -2.2570999339222908e-02 + + 3.8499400019645691e-01 -2.4434499442577362e-01 + <_> + + 0 -1 1964 -6.3813999295234680e-02 + + -8.9383500814437866e-01 1.4217500388622284e-01 + <_> + + 0 -1 1965 -4.9945000559091568e-02 + + 5.3864401578903198e-01 -2.0485299825668335e-01 + <_> + + 0 -1 1966 6.8319998681545258e-03 + + -5.6678999215364456e-02 3.9970999956130981e-01 + <_> + + 0 -1 1967 -5.5835999548435211e-02 + + -1.5239470005035400e+00 -5.1183000206947327e-02 + <_> + + 0 -1 1968 3.1957000494003296e-01 + + 7.4574001133441925e-02 1.2447799444198608e+00 + <_> + + 0 -1 1969 8.0955997109413147e-02 + + -1.9665500521659851e-01 5.9889698028564453e-01 + <_> + + 0 -1 1970 -1.4911999925971031e-02 + + -6.4020597934722900e-01 1.5807600319385529e-01 + <_> + + 0 -1 1971 4.6709001064300537e-02 + + 8.5239000618457794e-02 -4.5487201213836670e-01 + <_> + + 0 -1 1972 6.0539999976754189e-03 + + -4.3184000253677368e-01 2.2452600300312042e-01 + <_> + + 0 -1 1973 -3.4375999122858047e-02 + + 4.0202501416206360e-01 -2.3903599381446838e-01 + <_> + + 0 -1 1974 -3.4924000501632690e-02 + + 5.2870100736618042e-01 3.9709001779556274e-02 + <_> + + 0 -1 1975 3.0030000489205122e-03 + + -3.8754299283027649e-01 1.4192600548267365e-01 + <_> + + 0 -1 1976 -1.4132999815046787e-02 + + 8.7528401613235474e-01 8.5507996380329132e-02 + <_> + + 0 -1 1977 -6.7940000444650650e-03 + + -1.1649219989776611e+00 -3.3943001180887222e-02 + <_> + + 0 -1 1978 -5.2886001765727997e-02 + + 1.0930680036544800e+00 5.1187001168727875e-02 + <_> + + 0 -1 1979 -2.1079999860376120e-03 + + 1.3696199655532837e-01 -3.3849999308586121e-01 + <_> + + 0 -1 1980 1.8353000283241272e-02 + + 1.3661600649356842e-01 -4.0777799487113953e-01 + <_> + + 0 -1 1981 1.2671999633312225e-02 + + -1.4936000108718872e-02 -8.1707501411437988e-01 + <_> + + 0 -1 1982 1.2924999929964542e-02 + + 1.7625099420547485e-01 -3.2491698861122131e-01 + <_> + + 0 -1 1983 -1.7921000719070435e-02 + + -5.2745401859283447e-01 4.4443000108003616e-02 + <_> + + 0 -1 1984 1.9160000374540687e-03 + + -1.0978599637746811e-01 2.2067500650882721e-01 + <_> + + 0 -1 1985 -1.4697999693453312e-02 + + 3.9067798852920532e-01 -2.2224999964237213e-01 + <_> + + 0 -1 1986 -1.4972999691963196e-02 + + -2.5450900197029114e-01 1.7790000140666962e-01 + <_> + + 0 -1 1987 1.4636999927461147e-02 + + -2.5125000625848770e-02 -8.7121301889419556e-01 + <_> + + 0 -1 1988 -1.0974000208079815e-02 + + 7.9082798957824707e-01 2.0121000707149506e-02 + <_> + + 0 -1 1989 -9.1599998995661736e-03 + + -4.7906899452209473e-01 5.2232000976800919e-02 + <_> + + 0 -1 1990 4.6179997734725475e-03 + + -1.7244599759578705e-01 3.4527799487113953e-01 + <_> + + 0 -1 1991 2.3476999253034592e-02 + + 3.7760001141577959e-03 -6.5333700180053711e-01 + <_> + + 0 -1 1992 3.1766999512910843e-02 + + 1.6364000737667084e-02 5.8723700046539307e-01 + <_> + + 0 -1 1993 -1.8419999629259109e-02 + + 1.9993899762630463e-01 -3.2056498527526855e-01 + <_> + + 0 -1 1994 1.9543999806046486e-02 + + 1.8450200557708740e-01 -2.3793600499629974e-01 + <_> + + 0 -1 1995 4.1159498691558838e-01 + + -6.0382001101970673e-02 -1.6072119474411011e+00 + <_> + + 0 -1 1996 -4.1595999151468277e-02 + + -3.2756200432777405e-01 1.5058000385761261e-01 + <_> + + 0 -1 1997 -1.0335999540984631e-02 + + -6.2394398450851440e-01 1.3112000189721584e-02 + <_> + + 0 -1 1998 1.2392999604344368e-02 + + -3.3114999532699585e-02 5.5579900741577148e-01 + <_> + + 0 -1 1999 -8.7270000949501991e-03 + + 1.9883200526237488e-01 -3.7635600566864014e-01 + <_> + + 0 -1 2000 1.6295000910758972e-02 + + 2.0373000204563141e-01 -4.2800799012184143e-01 + <_> + + 0 -1 2001 -1.0483999736607075e-02 + + -5.6847000122070312e-01 4.4199001044034958e-02 + <_> + + 0 -1 2002 -1.2431999668478966e-02 + + 7.4641901254653931e-01 4.3678998947143555e-02 + <_> + + 0 -1 2003 -5.0374999642372131e-02 + + 8.5090100765228271e-01 -1.7773799598217010e-01 + <_> + + 0 -1 2004 4.9548000097274780e-02 + + 1.6784900426864624e-01 -2.9877498745918274e-01 + <_> + + 0 -1 2005 -4.1085001081228256e-02 + + -1.3302919864654541e+00 -4.9182001501321793e-02 + <_> + + 0 -1 2006 1.0069999843835831e-03 + + -6.0538999736309052e-02 1.8483200669288635e-01 + <_> + + 0 -1 2007 -5.0142999738454819e-02 + + 7.6447701454162598e-01 -1.8356999754905701e-01 + <_> + + 0 -1 2008 -8.7879998609423637e-03 + + 2.2655999660491943e-01 -6.3156999647617340e-02 + <_> + + 0 -1 2009 -5.0170999020338058e-02 + + -1.5899070501327515e+00 -6.1255000531673431e-02 + <_> + + 0 -1 2010 1.0216099768877029e-01 + + 1.2071800231933594e-01 -1.4120110273361206e+00 + <_> + + 0 -1 2011 -1.4372999779880047e-02 + + -1.3116970062255859e+00 -5.1936000585556030e-02 + <_> + + 0 -1 2012 1.0281999595463276e-02 + + -2.1639999467879534e-03 4.4247201085090637e-01 + <_> + + 0 -1 2013 -1.1814000084996223e-02 + + 6.5378099679946899e-01 -1.8723699450492859e-01 + <_> + + 0 -1 2014 7.2114996612071991e-02 + + 7.1846999228000641e-02 8.1496298313140869e-01 + <_> + + 0 -1 2015 -1.9001999869942665e-02 + + -6.7427200078964233e-01 -4.3200000072829425e-04 + <_> + + 0 -1 2016 -4.6990001574158669e-03 + + 3.3311501145362854e-01 5.5794000625610352e-02 + <_> + + 0 -1 2017 -5.8157000690698624e-02 + + 4.5572298765182495e-01 -2.0305100083351135e-01 + <_> + + 0 -1 2018 1.1360000353306532e-03 + + -4.4686999171972275e-02 2.2681899368762970e-01 + <_> + + 0 -1 2019 -4.9414999783039093e-02 + + 2.6694598793983459e-01 -2.6116999983787537e-01 + <_> + + 0 -1 2020 -1.1913800239562988e-01 + + -8.3017998933792114e-01 1.3248500227928162e-01 + <_> + + 0 -1 2021 -1.8303999677300453e-02 + + -6.7499202489852905e-01 1.7092000693082809e-02 + <_> + + 0 -1 2022 -7.9199997708201408e-03 + + -7.2287000715732574e-02 1.4425800740718842e-01 + <_> + + 0 -1 2023 5.1925998181104660e-02 + + 3.0921999365091324e-02 -5.5860602855682373e-01 + <_> + + 0 -1 2024 6.6724002361297607e-02 + + 1.3666400313377380e-01 -2.9411000013351440e-01 + <_> + + 0 -1 2025 -1.3778000138700008e-02 + + -5.9443902969360352e-01 1.5300000086426735e-02 + <_> + + 0 -1 2026 -1.7760999500751495e-02 + + 4.0496501326560974e-01 -3.3559999428689480e-03 + <_> + + 0 -1 2027 -4.2234998196363449e-02 + + -1.0897940397262573e+00 -4.0224999189376831e-02 + <_> + + 0 -1 2028 -1.3524999842047691e-02 + + 2.8921899199485779e-01 -2.5194799900054932e-01 + <_> + + 0 -1 2029 -1.1106000281870365e-02 + + 6.5312802791595459e-01 -1.8053700029850006e-01 + <_> + + 0 -1 2030 -1.2284599989652634e-01 + + -1.9570649862289429e+00 1.4815400540828705e-01 + <_> + + 0 -1 2031 4.7715999186038971e-02 + + -2.2875599563121796e-01 3.4233701229095459e-01 + <_> + + 0 -1 2032 3.1817000359296799e-02 + + 1.5976299345493317e-01 -1.0091969966888428e+00 + <_> + + 0 -1 2033 4.2570000514388084e-03 + + -3.8881298899650574e-01 8.4210000932216644e-02 + <_> + + 0 -1 2034 -6.1372999101877213e-02 + + 1.7152810096740723e+00 5.9324998408555984e-02 + <_> + + 0 -1 2035 -2.7030000928789377e-03 + + -3.8161700963973999e-01 8.5127003490924835e-02 + <_> + + 0 -1 2036 -6.8544000387191772e-02 + + -3.0925889015197754e+00 1.1788000166416168e-01 + <_> + + 0 -1 2037 1.0372500121593475e-01 + + -1.3769300282001495e-01 1.9009410142898560e+00 + <_> + + 0 -1 2038 1.5799000859260559e-02 + + -6.2660001218318939e-02 2.5917699933052063e-01 + <_> + + 0 -1 2039 -9.8040001466870308e-03 + + -5.6291598081588745e-01 4.3923001736402512e-02 + <_> + + 0 -1 2040 -9.0229995548725128e-03 + + 2.5287100672721863e-01 -4.1225999593734741e-02 + <_> + + 0 -1 2041 -6.3754998147487640e-02 + + -2.6178569793701172e+00 -7.4005998671054840e-02 + <_> + + 0 -1 2042 3.8954999297857285e-02 + + 5.9032998979091644e-02 8.5945600271224976e-01 + <_> + + 0 -1 2043 -3.9802998304367065e-02 + + 9.3600499629974365e-01 -1.5639400482177734e-01 + <_> + + 0 -1 2044 5.0301998853683472e-02 + + 1.3725900650024414e-01 -2.5549728870391846e+00 + <_> + + 0 -1 2045 4.6250000596046448e-02 + + -1.3964000158011913e-02 -7.1026200056076050e-01 + <_> + + 0 -1 2046 6.2196001410484314e-02 + + 5.9526000171899796e-02 1.6509100198745728e+00 + <_> + + 0 -1 2047 -6.4776003360748291e-02 + + 7.1368998289108276e-01 -1.7270000278949738e-01 + <_> + + 0 -1 2048 2.7522999793291092e-02 + + 1.4631600677967072e-01 -8.1428997218608856e-02 + <_> + + 0 -1 2049 3.9900001138448715e-04 + + -3.7144500017166138e-01 1.0152699798345566e-01 + <_> + + 0 -1 2050 -4.3299999088048935e-03 + + -2.3756299912929535e-01 2.6798400282859802e-01 + <_> + + 0 -1 2051 4.7297000885009766e-02 + + -2.7682000771164894e-02 -8.4910297393798828e-01 + <_> + + 0 -1 2052 1.2508999556303024e-02 + + 1.8730199337005615e-01 -5.6001102924346924e-01 + <_> + + 0 -1 2053 4.5899000018835068e-02 + + -1.5601199865341187e-01 9.7073000669479370e-01 + <_> + + 0 -1 2054 1.9853399693965912e-01 + + 1.4895500242710114e-01 -1.1015529632568359e+00 + <_> + + 0 -1 2055 1.6674999147653580e-02 + + -1.6615299880504608e-01 8.2210999727249146e-01 + <_> + + 0 -1 2056 1.9829999655485153e-03 + + -7.1249999105930328e-02 2.8810900449752808e-01 + <_> + + 0 -1 2057 2.2447999566793442e-02 + + -2.0981000736355782e-02 -7.8416502475738525e-01 + <_> + + 0 -1 2058 -1.3913000002503395e-02 + + -1.8165799975395203e-01 2.0491799712181091e-01 + <_> + + 0 -1 2059 -7.7659999951720238e-03 + + -4.5595899224281311e-01 6.3576996326446533e-02 + <_> + + 0 -1 2060 -1.3209000229835510e-02 + + 2.6632300019264221e-01 -1.7795999348163605e-01 + <_> + + 0 -1 2061 4.9052998423576355e-02 + + -1.5476800501346588e-01 1.1069979667663574e+00 + <_> + + 0 -1 2062 2.0263999700546265e-02 + + 6.8915002048015594e-02 6.9867497682571411e-01 + <_> + + 0 -1 2063 -1.6828000545501709e-02 + + 2.7607199549674988e-01 -2.5139200687408447e-01 + <_> + + 0 -1 2064 -1.6939499974250793e-01 + + -3.0767529010772705e+00 1.1617500334978104e-01 + <_> + + 0 -1 2065 -1.1336100101470947e-01 + + -1.4639229774475098e+00 -5.1447000354528427e-02 + <_> + + 0 -1 2066 -7.7685996890068054e-02 + + 8.8430202007293701e-01 4.3306998908519745e-02 + <_> + + 0 -1 2067 -1.5568000264465809e-02 + + 1.3672499358654022e-01 -3.4505501389503479e-01 + <_> + + 0 -1 2068 -6.6018998622894287e-02 + + -1.0300110578536987e+00 1.1601399630308151e-01 + <_> + + 0 -1 2069 8.3699999377131462e-03 + + 7.6429001986980438e-02 -4.4002500176429749e-01 + <_> + + 0 -1 2070 3.5402998328208923e-02 + + 1.1979500204324722e-01 -7.2668302059173584e-01 + <_> + + 0 -1 2071 -3.9051000028848648e-02 + + 6.7375302314758301e-01 -1.8196000158786774e-01 + <_> + + 0 -1 2072 -9.7899995744228363e-03 + + 2.1264599263668060e-01 3.6756001412868500e-02 + <_> + + 0 -1 2073 -2.3047000169754028e-02 + + 4.4742199778556824e-01 -2.0986700057983398e-01 + <_> + + 0 -1 2074 3.1169999856501818e-03 + + 3.7544000893831253e-02 2.7808201313018799e-01 + <_> + + 0 -1 2075 1.3136000372469425e-02 + + -1.9842399656772614e-01 5.4335701465606689e-01 + <_> + + 0 -1 2076 1.4782000333070755e-02 + + 1.3530600070953369e-01 -1.1153600364923477e-01 + <_> + + 0 -1 2077 -6.0139000415802002e-02 + + 8.4039300680160522e-01 -1.6711600124835968e-01 + <_> + + 0 -1 2078 5.1998998969793320e-02 + + 1.7372000217437744e-01 -7.8547602891921997e-01 + <_> + + 0 -1 2079 2.4792000651359558e-02 + + -1.7739200592041016e-01 6.6752600669860840e-01 + <_> + + 0 -1 2080 -1.2014999985694885e-02 + + -1.4263699948787689e-01 1.6070500016212463e-01 + <_> + + 0 -1 2081 -9.8655998706817627e-02 + + 1.0429769754409790e+00 -1.5770199894905090e-01 + <_> + + 0 -1 2082 1.1758299916982651e-01 + + 1.0955700278282166e-01 -4.4920377731323242e+00 + <_> + + 0 -1 2083 -1.8922999501228333e-02 + + -7.8543400764465332e-01 1.2984000146389008e-02 + <_> + + 0 -1 2084 -2.8390999883413315e-02 + + -6.0569900274276733e-01 1.2903499603271484e-01 + <_> + + 0 -1 2085 1.3182999566197395e-02 + + -1.4415999874472618e-02 -7.3210501670837402e-01 + <_> + + 0 -1 2086 -1.1653000116348267e-01 + + -2.0442469120025635e+00 1.4053100347518921e-01 + <_> + + 0 -1 2087 -3.8880000356584787e-03 + + -4.1861599683761597e-01 7.8704997897148132e-02 + <_> + + 0 -1 2088 3.1229000538587570e-02 + + 2.4632999673485756e-02 4.1870400309562683e-01 + <_> + + 0 -1 2089 2.5198999792337418e-02 + + -1.7557799816131592e-01 6.4710599184036255e-01 + <_> + + 0 -1 2090 -2.8124000877141953e-02 + + -2.2005599737167358e-01 1.4121000468730927e-01 + <_> + + 0 -1 2091 3.6499001085758209e-02 + + -6.8426996469497681e-02 -2.3410849571228027e+00 + <_> + + 0 -1 2092 -7.2292998433113098e-02 + + 1.2898750305175781e+00 8.4875002503395081e-02 + <_> + + 0 -1 2093 -4.1671000421047211e-02 + + -1.1630970239639282e+00 -5.3752999752759933e-02 + <_> + + 0 -1 2094 4.7703001648187637e-02 + + 7.0101000368595123e-02 7.3676502704620361e-01 + <_> + + 0 -1 2095 6.5793000161647797e-02 + + -1.7755299806594849e-01 6.9780498743057251e-01 + <_> + + 0 -1 2096 1.3904999941587448e-02 + + 2.1936799585819244e-01 -2.0390799641609192e-01 + <_> + + 0 -1 2097 -2.7730999514460564e-02 + + 6.1867898702621460e-01 -1.7804099619388580e-01 + <_> + + 0 -1 2098 -1.5879999846220016e-02 + + -4.6484100818634033e-01 1.8828600645065308e-01 + <_> + + 0 -1 2099 7.4128001928329468e-02 + + -1.2858100235462189e-01 3.2792479991912842e+00 + <_> + + 0 -1 2100 -8.9000002481043339e-04 + + -3.0117601156234741e-01 2.3818799853324890e-01 + <_> + + 0 -1 2101 1.7965000122785568e-02 + + -2.2284999489784241e-01 2.9954001307487488e-01 + <_> + + 0 -1 2102 -2.5380000006407499e-03 + + 2.5064399838447571e-01 -1.3665600121021271e-01 + <_> + + 0 -1 2103 -9.0680001303553581e-03 + + 2.9017499089241028e-01 -2.8929701447486877e-01 + <_> + + 0 -1 2104 4.9169998615980148e-02 + + 1.9156399369239807e-01 -6.8328702449798584e-01 + <_> + + 0 -1 2105 -3.0680999159812927e-02 + + -7.5677001476287842e-01 -1.3279999606311321e-02 + <_> + + 0 -1 2106 1.0017400234937668e-01 + + 8.4453999996185303e-02 1.0888710021972656e+00 + <_> + + 0 -1 2107 3.1950001139193773e-03 + + -2.6919400691986084e-01 1.9537900388240814e-01 + <_> + + 0 -1 2108 3.5503000020980835e-02 + + 1.3632300496101379e-01 -5.6917202472686768e-01 + <_> + + 0 -1 2109 4.5900000259280205e-04 + + -4.0443998575210571e-01 1.4074799418449402e-01 + <_> + + 0 -1 2110 2.5258999317884445e-02 + + 1.6243200004100800e-01 -5.5741798877716064e-01 + <_> + + 0 -1 2111 -5.1549999043345451e-03 + + 3.1132599711418152e-01 -2.2756099700927734e-01 + <_> + + 0 -1 2112 1.5869999770075083e-03 + + -2.6867699623107910e-01 1.9565400481224060e-01 + <_> + + 0 -1 2113 -1.6204999759793282e-02 + + 1.5486499667167664e-01 -3.4057798981666565e-01 + <_> + + 0 -1 2114 -2.9624000191688538e-02 + + 1.1466799974441528e+00 9.0557999908924103e-02 + <_> + + 0 -1 2115 -1.5930000226944685e-03 + + -7.1257501840591431e-01 -7.0400000549852848e-04 + <_> + + 0 -1 2116 -5.4019000381231308e-02 + + 4.1537499427795410e-01 2.7246000245213509e-02 + <_> + + 0 -1 2117 -6.6211000084877014e-02 + + -1.3340090513229370e+00 -4.7352999448776245e-02 + <_> + + 0 -1 2118 2.7940999716520309e-02 + + 1.4446300268173218e-01 -5.1518398523330688e-01 + <_> + + 0 -1 2119 2.8957000002264977e-02 + + -4.9966000020503998e-02 -1.1929039955139160e+00 + <_> + + 0 -1 2120 -2.0424999296665192e-02 + + 6.3881301879882812e-01 3.8141001015901566e-02 + <_> + + 0 -1 2121 1.2416999787092209e-02 + + -2.1547000110149384e-01 4.9477699398994446e-01 + <_> + 181 + -3.3196411132812500e+00 + + <_> + + 0 -1 2122 4.3274000287055969e-02 + + -8.0494397878646851e-01 3.9897298812866211e-01 + <_> + + 0 -1 2123 1.8615500628948212e-01 + + -3.1655299663543701e-01 6.8877297639846802e-01 + <_> + + 0 -1 2124 3.1860999763011932e-02 + + -6.4266198873519897e-01 2.5550898909568787e-01 + <_> + + 0 -1 2125 1.4022000133991241e-02 + + -4.5926600694656372e-01 3.1171199679374695e-01 + <_> + + 0 -1 2126 -6.3029997982084751e-03 + + 4.6026900410652161e-01 -2.7438500523567200e-01 + <_> + + 0 -1 2127 -5.4310001432895660e-03 + + 3.6608600616455078e-01 -2.7205801010131836e-01 + <_> + + 0 -1 2128 1.6822999343276024e-02 + + 2.3476999253034592e-02 -8.8443797826766968e-01 + <_> + + 0 -1 2129 2.6039000600576401e-02 + + 1.7488799989223480e-01 -5.4564702510833740e-01 + <_> + + 0 -1 2130 -2.6720000430941582e-02 + + -9.6396499872207642e-01 2.3524999618530273e-02 + <_> + + 0 -1 2131 -1.7041999846696854e-02 + + -7.0848798751831055e-01 2.1468099951744080e-01 + <_> + + 0 -1 2132 5.9569999575614929e-03 + + 7.3601000010967255e-02 -6.8225598335266113e-01 + <_> + + 0 -1 2133 -2.8679999522864819e-03 + + -7.4935001134872437e-01 2.3803399503231049e-01 + <_> + + 0 -1 2134 -4.3774999678134918e-02 + + 6.8323302268981934e-01 -2.1380299329757690e-01 + <_> + + 0 -1 2135 5.1633000373840332e-02 + + -1.2566499412059784e-01 6.7523801326751709e-01 + <_> + + 0 -1 2136 8.1780003383755684e-03 + + 7.0689998567104340e-02 -8.0665898323059082e-01 + <_> + + 0 -1 2137 -5.2841998636722565e-02 + + 9.5433902740478516e-01 1.6548000276088715e-02 + <_> + + 0 -1 2138 5.2583999931812286e-02 + + -2.8414401412010193e-01 4.7129800915718079e-01 + <_> + + 0 -1 2139 -1.2659000232815742e-02 + + 3.8445401191711426e-01 -6.2288001179695129e-02 + <_> + + 0 -1 2140 1.1694000102579594e-02 + + 5.6000000768108293e-05 -1.0173139572143555e+00 + <_> + + 0 -1 2141 -2.3918999359011650e-02 + + 8.4921300411224365e-01 5.7399999350309372e-03 + <_> + + 0 -1 2142 -6.1673998832702637e-02 + + -9.2571401596069336e-01 -1.7679999582469463e-03 + <_> + + 0 -1 2143 -1.8279999494552612e-03 + + -5.4372298717498779e-01 2.4932399392127991e-01 + <_> + + 0 -1 2144 3.5257998853921890e-02 + + -7.3719997890293598e-03 -9.3963998556137085e-01 + <_> + + 0 -1 2145 -1.8438000231981277e-02 + + 7.2136700153350830e-01 1.0491999797523022e-02 + <_> + + 0 -1 2146 -3.8389001041650772e-02 + + 1.9272600114345551e-01 -3.5832101106643677e-01 + <_> + + 0 -1 2147 9.9720999598503113e-02 + + 1.1354199796915054e-01 -1.6304190158843994e+00 + <_> + + 0 -1 2148 8.4462001919746399e-02 + + -5.3420998156070709e-02 -1.6981120109558105e+00 + <_> + + 0 -1 2149 4.0270000696182251e-02 + + -1.0783199965953827e-01 5.1926600933074951e-01 + <_> + + 0 -1 2150 5.8935999870300293e-02 + + -1.8053700029850006e-01 9.5119798183441162e-01 + <_> + + 0 -1 2151 1.4957000315189362e-01 + + 1.6785299777984619e-01 -1.1591869592666626e+00 + <_> + + 0 -1 2152 6.9399998756125569e-04 + + 2.0491400361061096e-01 -3.3118200302124023e-01 + <_> + + 0 -1 2153 -3.3369001001119614e-02 + + 9.3468099832534790e-01 -2.9639999847859144e-03 + <_> + + 0 -1 2154 9.3759996816515923e-03 + + 3.7000000011175871e-03 -7.7549797296524048e-01 + <_> + + 0 -1 2155 4.3193999677896500e-02 + + -2.2040000185370445e-03 7.4589699506759644e-01 + <_> + + 0 -1 2156 -6.7555002868175507e-02 + + 7.2292101383209229e-01 -1.8404200673103333e-01 + <_> + + 0 -1 2157 -3.1168600916862488e-01 + + 1.0014270544052124e+00 3.4003000706434250e-02 + <_> + + 0 -1 2158 2.9743999242782593e-02 + + -4.6356000006198883e-02 -1.2781809568405151e+00 + <_> + + 0 -1 2159 1.0737000033259392e-02 + + 1.4812000095844269e-02 6.6649997234344482e-01 + <_> + + 0 -1 2160 -2.8841000050306320e-02 + + -9.4222599267959595e-01 -2.0796999335289001e-02 + <_> + + 0 -1 2161 -5.7649998925626278e-03 + + -4.3541899323463440e-01 2.3386000096797943e-01 + <_> + + 0 -1 2162 2.8410999104380608e-02 + + -1.7615799605846405e-01 8.5765302181243896e-01 + <_> + + 0 -1 2163 -2.9007999226450920e-02 + + 5.7978099584579468e-01 2.8565999120473862e-02 + <_> + + 0 -1 2164 2.4965999647974968e-02 + + -2.2729000076651573e-02 -9.6773099899291992e-01 + <_> + + 0 -1 2165 1.2036000378429890e-02 + + -1.4214700460433960e-01 5.1687997579574585e-01 + <_> + + 0 -1 2166 -4.2514000087976456e-02 + + 9.7273802757263184e-01 -1.8119800090789795e-01 + <_> + + 0 -1 2167 1.0276000015437603e-02 + + -8.3099998533725739e-02 3.1762799620628357e-01 + <_> + + 0 -1 2168 -6.9191999733448029e-02 + + -2.0668580532073975e+00 -6.0173999518156052e-02 + <_> + + 0 -1 2169 -4.6769999898970127e-03 + + 4.4131800532341003e-01 2.3209000006318092e-02 + <_> + + 0 -1 2170 -1.3923999853432178e-02 + + 2.8606700897216797e-01 -2.9152700304985046e-01 + <_> + + 0 -1 2171 -1.5333999879658222e-02 + + -5.7414501905441284e-01 2.3063300549983978e-01 + <_> + + 0 -1 2172 -1.0239000432193279e-02 + + 3.4479200839996338e-01 -2.6080399751663208e-01 + <_> + + 0 -1 2173 -5.0988998264074326e-02 + + 5.6154102087020874e-01 6.1218999326229095e-02 + <_> + + 0 -1 2174 3.0689999461174011e-02 + + -1.4772799611091614e-01 1.6378489732742310e+00 + <_> + + 0 -1 2175 -1.1223999783396721e-02 + + 2.4006199836730957e-01 -4.4864898920059204e-01 + <_> + + 0 -1 2176 -6.2899999320507050e-03 + + 4.3119499087333679e-01 -2.3808999359607697e-01 + <_> + + 0 -1 2177 7.8590996563434601e-02 + + 1.9865000620484352e-02 8.0853801965713501e-01 + <_> + + 0 -1 2178 -1.0178999975323677e-02 + + 1.8193200230598450e-01 -3.2877799868583679e-01 + <_> + + 0 -1 2179 3.1227000057697296e-02 + + 1.4973899722099304e-01 -1.4180339574813843e+00 + <_> + + 0 -1 2180 4.0196999907493591e-02 + + -1.9760499894618988e-01 5.8508199453353882e-01 + <_> + + 0 -1 2181 1.6138000413775444e-02 + + 5.0000002374872565e-04 3.9050000905990601e-01 + <_> + + 0 -1 2182 -4.5519001781940460e-02 + + 1.2646820545196533e+00 -1.5632599592208862e-01 + <_> + + 0 -1 2183 -1.8130000680685043e-02 + + 6.5148502588272095e-01 1.0235999710857868e-02 + <_> + + 0 -1 2184 -1.4001999981701374e-02 + + -1.0344820022583008e+00 -3.2182998955249786e-02 + <_> + + 0 -1 2185 -3.8816001266241074e-02 + + -4.7874298691749573e-01 1.6290700435638428e-01 + <_> + + 0 -1 2186 3.1656000763177872e-02 + + -2.0983399450778961e-01 5.4575902223587036e-01 + <_> + + 0 -1 2187 -1.0839999653398991e-02 + + 5.1898801326751709e-01 -1.5080000273883343e-02 + <_> + + 0 -1 2188 1.2032999657094479e-02 + + -2.1107600629329681e-01 7.5937002897262573e-01 + <_> + + 0 -1 2189 7.0772998034954071e-02 + + 1.8048800528049469e-01 -7.4048501253128052e-01 + <_> + + 0 -1 2190 5.3139799833297729e-01 + + -1.4491699635982513e-01 1.5360039472579956e+00 + <_> + + 0 -1 2191 -1.4774000272154808e-02 + + -2.8153699636459351e-01 2.0407299697399139e-01 + <_> + + 0 -1 2192 -2.2410000674426556e-03 + + -4.4876301288604736e-01 5.3989000618457794e-02 + <_> + + 0 -1 2193 4.9968000501394272e-02 + + 4.1514001786708832e-02 2.9417100548744202e-01 + <_> + + 0 -1 2194 -4.7701999545097351e-02 + + 3.9674299955368042e-01 -2.8301799297332764e-01 + <_> + + 0 -1 2195 -9.1311000287532806e-02 + + 2.1994259357452393e+00 8.7964996695518494e-02 + <_> + + 0 -1 2196 3.8070000708103180e-02 + + -2.8025600314140320e-01 2.5156199932098389e-01 + <_> + + 0 -1 2197 -1.5538999810814857e-02 + + 3.4157499670982361e-01 1.7924999818205833e-02 + <_> + + 0 -1 2198 -1.5445999801158905e-02 + + 2.8680199384689331e-01 -2.5135898590087891e-01 + <_> + + 0 -1 2199 -5.7388000190258026e-02 + + 6.3830000162124634e-01 8.8597998023033142e-02 + <_> + + 0 -1 2200 -5.9440000914037228e-03 + + 7.9016998410224915e-02 -4.0774899721145630e-01 + <_> + + 0 -1 2201 -6.9968998432159424e-02 + + -4.4644200801849365e-01 1.7219600081443787e-01 + <_> + + 0 -1 2202 -2.5064999237656593e-02 + + -9.8270201683044434e-01 -3.5388000309467316e-02 + <_> + + 0 -1 2203 1.7216000705957413e-02 + + 2.2705900669097900e-01 -8.0550098419189453e-01 + <_> + + 0 -1 2204 -4.4279001653194427e-02 + + 8.3951997756958008e-01 -1.7429600656032562e-01 + <_> + + 0 -1 2205 4.3988998979330063e-02 + + 1.1557199805974960e-01 -1.9666889905929565e+00 + <_> + + 0 -1 2206 1.5907000750303268e-02 + + -3.7576001137495041e-02 -1.0311100482940674e+00 + <_> + + 0 -1 2207 -9.2754997313022614e-02 + + -1.3530019521713257e+00 1.2141299992799759e-01 + <_> + + 0 -1 2208 7.1037001907825470e-02 + + -1.7684300243854523e-01 7.4485200643539429e-01 + <_> + + 0 -1 2209 5.7762000709772110e-02 + + 1.2835599482059479e-01 -4.4444200396537781e-01 + <_> + + 0 -1 2210 -1.6432000324130058e-02 + + 8.0152702331542969e-01 -1.7491699755191803e-01 + <_> + + 0 -1 2211 2.3939000442624092e-02 + + 1.6144999861717224e-01 -1.2364500015974045e-01 + <_> + + 0 -1 2212 1.2636000290513039e-02 + + 1.5411999821662903e-01 -3.3293798565864563e-01 + <_> + + 0 -1 2213 -5.4347999393939972e-02 + + -1.8400700092315674e+00 1.4835999906063080e-01 + <_> + + 0 -1 2214 -1.3261999934911728e-02 + + -8.0838799476623535e-01 -2.7726000174880028e-02 + <_> + + 0 -1 2215 6.1340001411736012e-03 + + -1.3785000145435333e-01 3.2858499884605408e-01 + <_> + + 0 -1 2216 2.8991000726819038e-02 + + -2.5516999885439873e-02 -8.3387202024459839e-01 + <_> + + 0 -1 2217 -2.1986000239849091e-02 + + -7.3739999532699585e-01 1.7887100577354431e-01 + <_> + + 0 -1 2218 5.3269998170435429e-03 + + -4.5449298620223999e-01 6.8791002035140991e-02 + <_> + + 0 -1 2219 8.6047999560832977e-02 + + 2.1008500456809998e-01 -3.7808901071548462e-01 + <_> + + 0 -1 2220 -8.5549997165799141e-03 + + 4.0134999155998230e-01 -2.1074099838733673e-01 + <_> + + 0 -1 2221 6.7790001630783081e-03 + + -2.1648999303579330e-02 4.5421499013900757e-01 + <_> + + 0 -1 2222 -6.3959998078644276e-03 + + -4.9818599224090576e-01 7.5907997786998749e-02 + <_> + + 0 -1 2223 8.9469999074935913e-03 + + 1.7857700586318970e-01 -2.8454899787902832e-01 + <_> + + 0 -1 2224 3.2589999027550220e-03 + + 4.6624999493360519e-02 -5.5206298828125000e-01 + <_> + + 0 -1 2225 4.1476998478174210e-02 + + 1.7550499737262726e-01 -2.0703999698162079e-01 + <_> + + 0 -1 2226 -6.7449999041855335e-03 + + -4.6392598748207092e-01 6.9303996860980988e-02 + <_> + + 0 -1 2227 3.0564999207854271e-02 + + 5.1734998822212219e-02 7.5550502538681030e-01 + <_> + + 0 -1 2228 -7.4780001305043697e-03 + + 1.4893899857997894e-01 -3.1906801462173462e-01 + <_> + + 0 -1 2229 8.9088998734951019e-02 + + 1.3738800585269928e-01 -1.1379710435867310e+00 + <_> + + 0 -1 2230 7.3230001144111156e-03 + + -2.8829199075698853e-01 1.9088600575923920e-01 + <_> + + 0 -1 2231 -1.8205000087618828e-02 + + -3.0178600549697876e-01 1.6795800626277924e-01 + <_> + + 0 -1 2232 -2.5828000158071518e-02 + + -9.8137998580932617e-01 -1.9860999658703804e-02 + <_> + + 0 -1 2233 1.0936199873685837e-01 + + 4.8790000379085541e-02 5.3118300437927246e-01 + <_> + + 0 -1 2234 -1.1424999684095383e-02 + + 2.3705999553203583e-01 -2.7925300598144531e-01 + <_> + + 0 -1 2235 -5.7565998286008835e-02 + + 4.7255399823188782e-01 6.5171003341674805e-02 + <_> + + 0 -1 2236 1.0278300195932388e-01 + + -2.0765100419521332e-01 5.0947701930999756e-01 + <_> + + 0 -1 2237 2.7041999623179436e-02 + + 1.6421200335025787e-01 -1.4508620500564575e+00 + <_> + + 0 -1 2238 -1.3635000213980675e-02 + + -5.6543898582458496e-01 2.3788999766111374e-02 + <_> + + 0 -1 2239 -3.2158198952674866e-01 + + -3.5602829456329346e+00 1.1801300197839737e-01 + <_> + + 0 -1 2240 2.0458100736141205e-01 + + -3.7016000598669052e-02 -1.0225499868392944e+00 + <_> + + 0 -1 2241 -7.0347003638744354e-02 + + -5.6491899490356445e-01 1.8525199592113495e-01 + <_> + + 0 -1 2242 3.7831000983715057e-02 + + -2.9901999980211258e-02 -8.2921499013900757e-01 + <_> + + 0 -1 2243 -7.0298001170158386e-02 + + -5.3172302246093750e-01 1.4430199563503265e-01 + <_> + + 0 -1 2244 6.3221000134944916e-02 + + -2.2041200101375580e-01 4.7952198982238770e-01 + <_> + + 0 -1 2245 3.6393001675605774e-02 + + 1.4222699403762817e-01 -6.1193901300430298e-01 + <_> + + 0 -1 2246 4.0099998004734516e-03 + + -3.4560799598693848e-01 1.1738699674606323e-01 + <_> + + 0 -1 2247 -4.9106001853942871e-02 + + 9.5984101295471191e-01 6.4934998750686646e-02 + <_> + + 0 -1 2248 -7.1583002805709839e-02 + + 1.7385669946670532e+00 -1.4252899587154388e-01 + <_> + + 0 -1 2249 -3.8008999079465866e-02 + + 1.3872820138931274e+00 6.6188000142574310e-02 + <_> + + 0 -1 2250 -3.1570000573992729e-03 + + 5.3677000105381012e-02 -5.4048001766204834e-01 + <_> + + 0 -1 2251 1.9458999857306480e-02 + + -9.3620002269744873e-02 3.9131000638008118e-01 + <_> + + 0 -1 2252 1.1293999850749969e-02 + + 3.7223998457193375e-02 -5.4251801967620850e-01 + <_> + + 0 -1 2253 -3.3495001494884491e-02 + + 9.5307898521423340e-01 3.7696998566389084e-02 + <_> + + 0 -1 2254 9.2035003006458282e-02 + + -1.3488399982452393e-01 2.2897069454193115e+00 + <_> + + 0 -1 2255 3.7529999390244484e-03 + + 2.2824199497699738e-01 -5.9983700513839722e-01 + <_> + + 0 -1 2256 1.2848000042140484e-02 + + -2.2005200386047363e-01 3.7221899628639221e-01 + <_> + + 0 -1 2257 -1.4316199719905853e-01 + + 1.2855789661407471e+00 4.7237001359462738e-02 + <_> + + 0 -1 2258 -9.6879996359348297e-02 + + -3.9550929069519043e+00 -7.2903998196125031e-02 + <_> + + 0 -1 2259 -8.8459998369216919e-03 + + 3.7674999237060547e-01 -4.6484000980854034e-02 + <_> + + 0 -1 2260 1.5900000929832458e-02 + + -2.4457000195980072e-02 -8.0034798383712769e-01 + <_> + + 0 -1 2261 7.0372000336647034e-02 + + 1.7019000649452209e-01 -6.3068997859954834e-01 + <_> + + 0 -1 2262 -3.7953998893499374e-02 + + -9.3667197227478027e-01 -4.1214000433683395e-02 + <_> + + 0 -1 2263 5.1597899198532104e-01 + + 1.3080599904060364e-01 -1.5802290439605713e+00 + <_> + + 0 -1 2264 -3.2843001186847687e-02 + + -1.1441620588302612e+00 -4.9173999577760696e-02 + <_> + + 0 -1 2265 -3.6357000470161438e-02 + + 4.9606400728225708e-01 -3.4458998590707779e-02 + <_> + + 0 -1 2266 6.8080001510679722e-03 + + -3.0997800827026367e-01 1.7054800689220428e-01 + <_> + + 0 -1 2267 -1.6114000231027603e-02 + + -3.7904599308967590e-01 1.6078999638557434e-01 + <_> + + 0 -1 2268 8.4530003368854523e-03 + + -1.8655499815940857e-01 5.6367701292037964e-01 + <_> + + 0 -1 2269 -1.3752399384975433e-01 + + -5.8989900350570679e-01 1.1749500036239624e-01 + <_> + + 0 -1 2270 1.7688000202178955e-01 + + -1.5424899756908417e-01 9.2911100387573242e-01 + <_> + + 0 -1 2271 7.9309996217489243e-03 + + 3.2190701365470886e-01 -1.6392600536346436e-01 + <_> + + 0 -1 2272 1.0971800237894058e-01 + + -1.5876500308513641e-01 1.0186259746551514e+00 + <_> + + 0 -1 2273 -3.0293000862002373e-02 + + 7.5587302446365356e-01 3.1794998794794083e-02 + <_> + + 0 -1 2274 -2.3118000477552414e-02 + + -8.8451498746871948e-01 -9.5039997249841690e-03 + <_> + + 0 -1 2275 -3.0900000128895044e-03 + + 2.3838299512863159e-01 -1.1606200039386749e-01 + <_> + + 0 -1 2276 -3.3392000943422318e-02 + + -1.8738139867782593e+00 -6.8502999842166901e-02 + <_> + + 0 -1 2277 1.3190000317990780e-02 + + 1.2919899821281433e-01 -6.7512202262878418e-01 + <_> + + 0 -1 2278 1.4661000110208988e-02 + + -2.4829000234603882e-02 -7.4396800994873047e-01 + <_> + + 0 -1 2279 -1.3248000293970108e-02 + + 4.6820199489593506e-01 -2.4165000766515732e-02 + <_> + + 0 -1 2280 -1.6218999400734901e-02 + + 4.0083798766136169e-01 -2.1255700290203094e-01 + <_> + + 0 -1 2281 -2.9052000492811203e-02 + + -1.5650019645690918e+00 1.4375899732112885e-01 + <_> + + 0 -1 2282 -1.0153199732303619e-01 + + -1.9220689535140991e+00 -6.9559998810291290e-02 + <_> + + 0 -1 2283 3.7753999233245850e-02 + + 1.3396799564361572e-01 -2.2639141082763672e+00 + <_> + + 0 -1 2284 -2.8555598855018616e-01 + + 1.0215270519256592e+00 -1.5232199430465698e-01 + <_> + + 0 -1 2285 1.5360699594020844e-01 + + -9.7409002482891083e-02 4.1662400960922241e-01 + <_> + + 0 -1 2286 -2.1199999901000410e-04 + + 1.1271899938583374e-01 -4.1653999686241150e-01 + <_> + + 0 -1 2287 -2.0597999915480614e-02 + + 6.0540497303009033e-01 6.2467999756336212e-02 + <_> + + 0 -1 2288 3.7353999912738800e-02 + + -1.8919000029563904e-01 4.6464699506759644e-01 + <_> + + 0 -1 2289 5.7275000959634781e-02 + + 1.1565300077199936e-01 -1.3213009834289551e+00 + <_> + + 0 -1 2290 5.1029999740421772e-03 + + -2.8061500191688538e-01 1.9313399493694305e-01 + <_> + + 0 -1 2291 -5.4644998162984848e-02 + + 7.2428500652313232e-01 7.5447998940944672e-02 + <_> + + 0 -1 2292 2.5349000468850136e-02 + + -1.9481800496578217e-01 4.6032801270484924e-01 + <_> + + 0 -1 2293 2.4311000481247902e-02 + + 1.5564100444316864e-01 -4.9913901090621948e-01 + <_> + + 0 -1 2294 3.5962000489234924e-02 + + -5.8573000133037567e-02 -1.5418399572372437e+00 + <_> + + 0 -1 2295 -1.0000699758529663e-01 + + -1.6100039482116699e+00 1.1450500041246414e-01 + <_> + + 0 -1 2296 8.4435999393463135e-02 + + -6.1406999826431274e-02 -1.4673349857330322e+00 + <_> + + 0 -1 2297 1.5947999432682991e-02 + + 1.6287900507450104e-01 -1.1026400327682495e-01 + <_> + + 0 -1 2298 3.3824000507593155e-02 + + -1.7932699620723724e-01 5.7218402624130249e-01 + <_> + + 0 -1 2299 -6.1996001750230789e-02 + + 4.6511812210083008e+00 9.4534002244472504e-02 + <_> + + 0 -1 2300 6.9876998662948608e-02 + + -1.6985900700092316e-01 8.7028998136520386e-01 + <_> + + 0 -1 2301 -2.7916999533772469e-02 + + 9.1042500734329224e-01 5.6827001273632050e-02 + <_> + + 0 -1 2302 -1.2764000333845615e-02 + + 2.2066700458526611e-01 -2.7769100666046143e-01 + <_> + 199 + -3.2573320865631104e+00 + + <_> + + 0 -1 2303 2.1662000566720963e-02 + + -8.9868897199630737e-01 2.9436299204826355e-01 + <_> + + 0 -1 2304 1.0044500231742859e-01 + + -3.7659201025962830e-01 6.0891002416610718e-01 + <_> + + 0 -1 2305 2.6003999635577202e-02 + + -3.8128501176834106e-01 3.9217400550842285e-01 + <_> + + 0 -1 2306 2.8441000729799271e-02 + + -1.8182300031185150e-01 5.8927202224731445e-01 + <_> + + 0 -1 2307 3.8612000644207001e-02 + + -2.2399599850177765e-01 6.3779997825622559e-01 + <_> + + 0 -1 2308 -4.6594999730587006e-02 + + 7.0812201499938965e-01 -1.4666199684143066e-01 + <_> + + 0 -1 2309 -4.2791999876499176e-02 + + 4.7680398821830750e-01 -2.9233199357986450e-01 + <_> + + 0 -1 2310 3.7960000336170197e-03 + + -1.8510299921035767e-01 5.2626699209213257e-01 + <_> + + 0 -1 2311 4.2348999530076981e-02 + + 3.9244998246431351e-02 -8.9197701215744019e-01 + <_> + + 0 -1 2312 1.9598999992012978e-02 + + -2.3358400166034698e-01 4.4146499037742615e-01 + <_> + + 0 -1 2313 8.7400001939386129e-04 + + -4.6063598990440369e-01 1.7689600586891174e-01 + <_> + + 0 -1 2314 -4.3629999272525311e-03 + + 3.3493199944496155e-01 -2.9893401265144348e-01 + <_> + + 0 -1 2315 1.6973000019788742e-02 + + -1.6408699750900269e-01 1.5993679761886597e+00 + <_> + + 0 -1 2316 3.6063998937606812e-02 + + 2.2601699829101562e-01 -5.3186100721359253e-01 + <_> + + 0 -1 2317 -7.0864997804164886e-02 + + 1.5220500528812408e-01 -4.1914600133895874e-01 + <_> + + 0 -1 2318 -6.3075996935367584e-02 + + -1.4874019622802734e+00 1.2953700125217438e-01 + <_> + + 0 -1 2319 2.9670000076293945e-02 + + -1.9145900011062622e-01 9.8184901475906372e-01 + <_> + + 0 -1 2320 3.7873998284339905e-02 + + 1.3459500670433044e-01 -5.6316298246383667e-01 + <_> + + 0 -1 2321 -3.3289000391960144e-02 + + -1.0828030109405518e+00 -1.1504000052809715e-02 + <_> + + 0 -1 2322 -3.1608998775482178e-02 + + -5.9224498271942139e-01 1.3394799828529358e-01 + <_> + + 0 -1 2323 1.0740000288933516e-03 + + -4.9185800552368164e-01 9.4446003437042236e-02 + <_> + + 0 -1 2324 -7.1556001901626587e-02 + + 5.9710198640823364e-01 -3.9553001523017883e-02 + <_> + + 0 -1 2325 -8.1170000135898590e-02 + + -1.1817820072174072e+00 -2.8254000470042229e-02 + <_> + + 0 -1 2326 4.4860001653432846e-03 + + -6.1028099060058594e-01 2.2619099915027618e-01 + <_> + + 0 -1 2327 -4.2176000773906708e-02 + + -1.1435619592666626e+00 -2.9001999646425247e-02 + <_> + + 0 -1 2328 -6.5640002489089966e-02 + + -1.6470279693603516e+00 1.2810300290584564e-01 + <_> + + 0 -1 2329 1.8188999965786934e-02 + + -3.1149399280548096e-01 2.5739601254463196e-01 + <_> + + 0 -1 2330 -5.1520001143217087e-02 + + -6.9206899404525757e-01 1.5270799398422241e-01 + <_> + + 0 -1 2331 -4.7150999307632446e-02 + + -7.1868300437927246e-01 2.6879999786615372e-03 + <_> + + 0 -1 2332 1.7488999292254448e-02 + + 2.2371199727058411e-01 -5.5381798744201660e-01 + <_> + + 0 -1 2333 -2.5264000520110130e-02 + + 1.0319819450378418e+00 -1.7496499419212341e-01 + <_> + + 0 -1 2334 -4.0745001286268234e-02 + + 4.4961598515510559e-01 3.9349000900983810e-02 + <_> + + 0 -1 2335 -3.7666998803615570e-02 + + -8.5475701093673706e-01 -1.2463999912142754e-02 + <_> + + 0 -1 2336 -1.3411000370979309e-02 + + 5.7845598459243774e-01 -1.7467999830842018e-02 + <_> + + 0 -1 2337 -7.8999997640494257e-05 + + -3.7749201059341431e-01 1.3961799442768097e-01 + <_> + + 0 -1 2338 -1.1415000073611736e-02 + + -2.6186600327491760e-01 2.3712499439716339e-01 + <_> + + 0 -1 2339 3.7200000137090683e-02 + + -2.8626000508666039e-02 -1.2945239543914795e+00 + <_> + + 0 -1 2340 3.4050000831484795e-03 + + 2.0531399548053741e-01 -1.8747499585151672e-01 + <_> + + 0 -1 2341 -2.2483000531792641e-02 + + 6.7027199268341064e-01 -1.9594000279903412e-01 + <_> + + 0 -1 2342 2.3274999111890793e-02 + + 1.7405399680137634e-01 -3.2746300101280212e-01 + <_> + + 0 -1 2343 -1.3917000032961369e-02 + + -8.3954298496246338e-01 -6.3760001212358475e-03 + <_> + + 0 -1 2344 7.5429999269545078e-03 + + -3.4194998443126678e-02 5.8998197317123413e-01 + <_> + + 0 -1 2345 -1.1539000086486340e-02 + + 4.2142799496650696e-01 -2.3510499298572540e-01 + <_> + + 0 -1 2346 5.2501998841762543e-02 + + 6.9303996860980988e-02 7.3226499557495117e-01 + <_> + + 0 -1 2347 5.2715998142957687e-02 + + -1.5688100457191467e-01 1.0907289981842041e+00 + <_> + + 0 -1 2348 -1.1726000346243382e-02 + + -7.0934301614761353e-01 1.6828800737857819e-01 + <_> + + 0 -1 2349 9.5945999026298523e-02 + + -1.6192899644374847e-01 1.0072519779205322e+00 + <_> + + 0 -1 2350 -1.5871999785304070e-02 + + 3.9008399844169617e-01 -5.3777001798152924e-02 + <_> + + 0 -1 2351 3.4818001091480255e-02 + + 1.7179999500513077e-02 -9.3941801786422729e-01 + <_> + + 0 -1 2352 3.4791998565196991e-02 + + 5.0462998449802399e-02 5.4465699195861816e-01 + <_> + + 0 -1 2353 1.6284000128507614e-02 + + -2.6981300115585327e-01 4.0365299582481384e-01 + <_> + + 0 -1 2354 -4.4319000095129013e-02 + + 8.4399998188018799e-01 3.2882999628782272e-02 + <_> + + 0 -1 2355 -5.5689997971057892e-03 + + 1.5309399366378784e-01 -3.4959799051284790e-01 + <_> + + 0 -1 2356 -6.5842002630233765e-02 + + -9.2711198329925537e-01 1.6800999641418457e-01 + <_> + + 0 -1 2357 -7.3337003588676453e-02 + + 5.1614499092102051e-01 -2.0236000418663025e-01 + <_> + + 0 -1 2358 1.6450000926852226e-02 + + 1.3950599730014801e-01 -4.9301299452781677e-01 + <_> + + 0 -1 2359 -9.2630004510283470e-03 + + -9.0101999044418335e-01 -1.6116000711917877e-02 + <_> + + 0 -1 2360 5.9139998629689217e-03 + + 1.9858199357986450e-01 -1.6731299459934235e-01 + <_> + + 0 -1 2361 -8.4699998842552304e-04 + + 9.4005003571510315e-02 -4.1570898890495300e-01 + <_> + + 0 -1 2362 2.0532900094985962e-01 + + -6.0022000223398209e-02 7.0993602275848389e-01 + <_> + + 0 -1 2363 -1.6883000731468201e-02 + + 2.4392199516296387e-01 -3.0551800131797791e-01 + <_> + + 0 -1 2364 -1.9111000001430511e-02 + + 6.1229902505874634e-01 2.4252999573945999e-02 + <_> + + 0 -1 2365 -2.5962999090552330e-02 + + 9.0764999389648438e-01 -1.6722099483013153e-01 + <_> + + 0 -1 2366 -2.1762000396847725e-02 + + -3.1384700536727905e-01 2.0134599506855011e-01 + <_> + + 0 -1 2367 -2.4119999259710312e-02 + + -6.6588401794433594e-01 7.4559999629855156e-03 + <_> + + 0 -1 2368 4.7129999846220016e-02 + + 5.9533998370170593e-02 8.7804502248764038e-01 + <_> + + 0 -1 2369 -4.5984998345375061e-02 + + 8.0067998170852661e-01 -1.7252300679683685e-01 + <_> + + 0 -1 2370 2.6507999747991562e-02 + + 1.8774099647998810e-01 -6.0850602388381958e-01 + <_> + + 0 -1 2371 -4.8615001142024994e-02 + + 5.8644098043441772e-01 -1.9427700340747833e-01 + <_> + + 0 -1 2372 -1.8562000244855881e-02 + + -2.5587901473045349e-01 1.6326199471950531e-01 + <_> + + 0 -1 2373 1.2678000144660473e-02 + + -1.4228000305593014e-02 -7.6738101243972778e-01 + <_> + + 0 -1 2374 -1.1919999960809946e-03 + + 2.0495000481605530e-01 -1.1404299736022949e-01 + <_> + + 0 -1 2375 -4.9088999629020691e-02 + + -1.0740849971771240e+00 -3.8940999656915665e-02 + <_> + + 0 -1 2376 -1.7436999827623367e-02 + + -5.7973802089691162e-01 1.8584500253200531e-01 + <_> + + 0 -1 2377 -1.4770000241696835e-02 + + -6.6150301694869995e-01 5.3119999356567860e-03 + <_> + + 0 -1 2378 -2.2905200719833374e-01 + + -4.8305100202560425e-01 1.2326399981975555e-01 + <_> + + 0 -1 2379 -1.2707099318504333e-01 + + 5.7452601194381714e-01 -1.9420400261878967e-01 + <_> + + 0 -1 2380 1.0339000262320042e-02 + + -5.4641999304294586e-02 2.4501800537109375e-01 + <_> + + 0 -1 2381 6.9010001607239246e-03 + + 1.2180600315332413e-01 -3.8797399401664734e-01 + <_> + + 0 -1 2382 2.9025399684906006e-01 + + 1.0966199636459351e-01 -30. + <_> + + 0 -1 2383 -2.3804999887943268e-01 + + -1.7352679967880249e+00 -6.3809998333454132e-02 + <_> + + 0 -1 2384 6.2481001019477844e-02 + + 1.3523000478744507e-01 -7.0301097631454468e-01 + <_> + + 0 -1 2385 4.7109997831285000e-03 + + -4.6984100341796875e-01 6.0341998934745789e-02 + <_> + + 0 -1 2386 -2.7815999463200569e-02 + + 6.9807600975036621e-01 1.3719999697059393e-03 + <_> + + 0 -1 2387 -1.7020000144839287e-02 + + 1.6870440244674683e+00 -1.4314800500869751e-01 + <_> + + 0 -1 2388 -4.9754999577999115e-02 + + 7.9497700929641724e-01 7.7199999941512942e-04 + <_> + + 0 -1 2389 -7.4732996523380280e-02 + + -1.0132360458374023e+00 -1.9388999789953232e-02 + <_> + + 0 -1 2390 3.2009001821279526e-02 + + 1.4412100613117218e-01 -4.2139101028442383e-01 + <_> + + 0 -1 2391 -9.4463996589183807e-02 + + 5.0682598352432251e-01 -2.0478899776935577e-01 + <_> + + 0 -1 2392 -1.5426999889314175e-02 + + -1.5811300277709961e-01 1.7806899547576904e-01 + <_> + + 0 -1 2393 -4.0540001355111599e-03 + + -5.4366701841354370e-01 3.1235000118613243e-02 + <_> + + 0 -1 2394 3.0080000869929790e-03 + + -1.7376799881458282e-01 3.0441701412200928e-01 + <_> + + 0 -1 2395 -1.0091999545693398e-02 + + 2.5103801488876343e-01 -2.6224100589752197e-01 + <_> + + 0 -1 2396 -3.8818001747131348e-02 + + 9.3226701021194458e-01 7.2659999132156372e-02 + <_> + + 0 -1 2397 3.4651998430490494e-02 + + -3.3934999257326126e-02 -8.5707902908325195e-01 + <_> + + 0 -1 2398 -4.6729999594390392e-03 + + 3.4969300031661987e-01 -4.8517998307943344e-02 + <_> + + 0 -1 2399 6.8499997723847628e-04 + + 6.6573001444339752e-02 -4.4973799586296082e-01 + <_> + + 0 -1 2400 3.5317000001668930e-02 + + 1.4275799691677094e-01 -4.6726399660110474e-01 + <_> + + 0 -1 2401 -2.3569999262690544e-02 + + -1.0286079645156860e+00 -4.5288000255823135e-02 + <_> + + 0 -1 2402 -1.9109999993816018e-03 + + -1.9652199745178223e-01 2.8661000728607178e-01 + <_> + + 0 -1 2403 -1.6659000888466835e-02 + + -7.7532202005386353e-01 -8.3280000835657120e-03 + <_> + + 0 -1 2404 6.6062200069427490e-01 + + 1.3232499361038208e-01 -3.5266680717468262e+00 + <_> + + 0 -1 2405 1.0970599949359894e-01 + + -1.5547199547290802e-01 1.4674140214920044e+00 + <_> + + 0 -1 2406 1.3500999659299850e-02 + + 1.5233400464057922e-01 -1.3020930290222168e+00 + <_> + + 0 -1 2407 -2.2871999070048332e-02 + + -7.1325999498367310e-01 -8.7040001526474953e-03 + <_> + + 0 -1 2408 -8.1821002066135406e-02 + + 1.1127580404281616e+00 8.3219997584819794e-02 + <_> + + 0 -1 2409 -5.2728001028299332e-02 + + 9.3165099620819092e-01 -1.7103999853134155e-01 + <_> + + 0 -1 2410 -2.5242000818252563e-02 + + -1.9733799993991852e-01 2.5359401106834412e-01 + <_> + + 0 -1 2411 -4.3818999081850052e-02 + + 4.1815200448036194e-01 -2.4585500359535217e-01 + <_> + + 0 -1 2412 -1.8188999965786934e-02 + + -5.1743197441101074e-01 2.0174199342727661e-01 + <_> + + 0 -1 2413 2.3466000333428383e-02 + + -4.3071001768112183e-02 -1.0636579990386963e+00 + <_> + + 0 -1 2414 3.4216001629829407e-02 + + 5.3780999034643173e-02 4.9707201123237610e-01 + <_> + + 0 -1 2415 2.5692999362945557e-02 + + -2.3800100386142731e-01 4.1651499271392822e-01 + <_> + + 0 -1 2416 -2.6565000414848328e-02 + + -8.8574802875518799e-01 1.3365900516510010e-01 + <_> + + 0 -1 2417 6.0942001640796661e-02 + + -2.0669700205326080e-01 5.8309000730514526e-01 + <_> + + 0 -1 2418 1.4474500715732574e-01 + + 1.3282300531864166e-01 -3.1449348926544189e+00 + <_> + + 0 -1 2419 5.3410999476909637e-02 + + -1.7325200140476227e-01 6.9190698862075806e-01 + <_> + + 0 -1 2420 1.1408000253140926e-02 + + 5.4822001606225967e-02 3.0240398645401001e-01 + <_> + + 0 -1 2421 -2.3179999552667141e-03 + + 1.5820899605751038e-01 -3.1973201036453247e-01 + <_> + + 0 -1 2422 -2.9695000499486923e-02 + + 7.1274799108505249e-01 5.8136001229286194e-02 + <_> + + 0 -1 2423 2.7249999344348907e-02 + + -1.5754100680351257e-01 9.2143797874450684e-01 + <_> + + 0 -1 2424 -3.6200000904500484e-03 + + -3.4548398852348328e-01 2.0220999419689178e-01 + <_> + + 0 -1 2425 -1.2578999623656273e-02 + + -5.5650299787521362e-01 2.0388999953866005e-02 + <_> + + 0 -1 2426 -8.8849000632762909e-02 + + -3.6100010871887207e+00 1.3164199888706207e-01 + <_> + + 0 -1 2427 -1.9256999716162682e-02 + + 5.1908999681472778e-01 -1.9284300506114960e-01 + <_> + + 0 -1 2428 -1.6666999086737633e-02 + + -8.7499998509883881e-02 1.5812499821186066e-01 + <_> + + 0 -1 2429 1.2931999750435352e-02 + + 2.7405999600887299e-02 -5.5123901367187500e-01 + <_> + + 0 -1 2430 -1.3431999832391739e-02 + + 2.3457799851894379e-01 -4.3235000222921371e-02 + <_> + + 0 -1 2431 1.8810000270605087e-02 + + -3.9680998772382736e-02 -9.4373297691345215e-01 + <_> + + 0 -1 2432 -6.4349998719990253e-03 + + 4.5703700184822083e-01 -4.0520001202821732e-03 + <_> + + 0 -1 2433 -2.4249000474810600e-02 + + -7.6248002052307129e-01 -1.9857000559568405e-02 + <_> + + 0 -1 2434 -2.9667999595403671e-02 + + -3.7412509918212891e+00 1.1250600218772888e-01 + <_> + + 0 -1 2435 5.1150000654160976e-03 + + -6.3781797885894775e-01 1.1223999783396721e-02 + <_> + + 0 -1 2436 -5.7819997891783714e-03 + + 1.9374400377273560e-01 -8.2042001187801361e-02 + <_> + + 0 -1 2437 1.6606999561190605e-02 + + -1.6192099452018738e-01 1.1334990262985229e+00 + <_> + + 0 -1 2438 3.8228001445531845e-02 + + 2.1105000749230385e-02 7.6264202594757080e-01 + <_> + + 0 -1 2439 -5.7094000279903412e-02 + + -1.6974929571151733e+00 -5.9762001037597656e-02 + <_> + + 0 -1 2440 -5.3883001208305359e-02 + + 1.1850190162658691e+00 9.0966999530792236e-02 + <_> + + 0 -1 2441 -2.6110000908374786e-03 + + -4.0941199660301208e-01 8.3820998668670654e-02 + <_> + + 0 -1 2442 2.9714399576187134e-01 + + 1.5529899299144745e-01 -1.0995409488677979e+00 + <_> + + 0 -1 2443 -8.9063003659248352e-02 + + 4.8947200179100037e-01 -2.0041200518608093e-01 + <_> + + 0 -1 2444 -5.6193001568317413e-02 + + -2.4581399559974670e-01 1.4365500211715698e-01 + <_> + + 0 -1 2445 3.7004999816417694e-02 + + -4.8168998211622238e-02 -1.2310709953308105e+00 + <_> + + 0 -1 2446 -8.4840003401041031e-03 + + 4.3372601270675659e-01 1.3779999688267708e-02 + <_> + + 0 -1 2447 -2.4379999376833439e-03 + + 1.8949699401855469e-01 -3.2294198870658875e-01 + <_> + + 0 -1 2448 -7.1639999747276306e-02 + + -4.3979001045227051e-01 2.2730199992656708e-01 + <_> + + 0 -1 2449 5.2260002121329308e-03 + + -2.0548400282859802e-01 5.0933301448822021e-01 + <_> + + 0 -1 2450 -6.1360001564025879e-03 + + 3.1157198548316956e-01 7.0680998265743256e-02 + <_> + + 0 -1 2451 1.5595000237226486e-02 + + -3.0934798717498779e-01 1.5627700090408325e-01 + <_> + + 0 -1 2452 2.5995999574661255e-02 + + 1.3821600377559662e-01 -1.7616599798202515e-01 + <_> + + 0 -1 2453 -1.2085000053048134e-02 + + -5.1070201396942139e-01 5.8440998196601868e-02 + <_> + + 0 -1 2454 -6.7836001515388489e-02 + + 4.7757101058959961e-01 -7.1446001529693604e-02 + <_> + + 0 -1 2455 -1.4715000055730343e-02 + + 4.5238900184631348e-01 -1.9861400127410889e-01 + <_> + + 0 -1 2456 2.5118999183177948e-02 + + 1.2954899668693542e-01 -8.6266398429870605e-01 + <_> + + 0 -1 2457 1.8826000392436981e-02 + + -4.1570000350475311e-02 -1.1354700326919556e+00 + <_> + + 0 -1 2458 -2.1263999864459038e-02 + + -3.4738001227378845e-01 1.5779499709606171e-01 + <_> + + 0 -1 2459 9.4609996303915977e-03 + + 4.8639997839927673e-03 -6.1654800176620483e-01 + <_> + + 0 -1 2460 2.2957700490951538e-01 + + 8.1372998654842377e-02 6.9841402769088745e-01 + <_> + + 0 -1 2461 -3.8061998784542084e-02 + + 1.1616369485855103e+00 -1.4976699650287628e-01 + <_> + + 0 -1 2462 -1.3484999537467957e-02 + + -3.2036399841308594e-01 1.7365099489688873e-01 + <_> + + 0 -1 2463 3.6238998174667358e-02 + + -1.8158499896526337e-01 6.1956697702407837e-01 + <_> + + 0 -1 2464 6.7210001870989799e-03 + + 7.9600000753998756e-04 4.2441400885581970e-01 + <_> + + 0 -1 2465 9.6525996923446655e-02 + + -1.4696800708770752e-01 1.2525680065155029e+00 + <_> + + 0 -1 2466 -3.5656999796628952e-02 + + -3.9781698584556580e-01 1.4191399514675140e-01 + <_> + + 0 -1 2467 1.0772000066936016e-02 + + -1.8194000422954559e-01 5.9762197732925415e-01 + <_> + + 0 -1 2468 7.9279996454715729e-02 + + 1.4642499387264252e-01 -7.8836899995803833e-01 + <_> + + 0 -1 2469 3.2841000705957413e-02 + + -6.2408000230789185e-02 -1.4227490425109863e+00 + <_> + + 0 -1 2470 -2.7781000360846519e-02 + + 3.4033098816871643e-01 3.0670000240206718e-02 + <_> + + 0 -1 2471 -4.0339999832212925e-03 + + 3.1084701418876648e-01 -2.2595700621604919e-01 + <_> + + 0 -1 2472 7.4260002002120018e-03 + + -3.8936998695135117e-02 3.1702101230621338e-01 + <_> + + 0 -1 2473 1.1213999986648560e-01 + + -1.7578299343585968e-01 6.5056598186492920e-01 + <_> + + 0 -1 2474 -1.1878100037574768e-01 + + -1.0092990398406982e+00 1.1069700121879578e-01 + <_> + + 0 -1 2475 -4.1584998369216919e-02 + + -5.3806400299072266e-01 1.9905000925064087e-02 + <_> + + 0 -1 2476 -2.7966000139713287e-02 + + 4.8143199086189270e-01 3.3590998500585556e-02 + <_> + + 0 -1 2477 -1.2506400048732758e-01 + + 2.6352199912071228e-01 -2.5737899541854858e-01 + <_> + + 0 -1 2478 2.3666900396347046e-01 + + 3.6508001387119293e-02 9.0655601024627686e-01 + <_> + + 0 -1 2479 -2.9475999996066093e-02 + + -6.0048800706863403e-01 9.5880003646016121e-03 + <_> + + 0 -1 2480 3.7792999297380447e-02 + + 1.5506200492382050e-01 -9.5733499526977539e-01 + <_> + + 0 -1 2481 7.2044000029563904e-02 + + -1.4525899291038513e-01 1.3676730394363403e+00 + <_> + + 0 -1 2482 9.7759999334812164e-03 + + 1.2915999628603458e-02 2.1640899777412415e-01 + <_> + + 0 -1 2483 5.2154000848531723e-02 + + -1.6359999775886536e-02 -8.8356298208236694e-01 + <_> + + 0 -1 2484 -4.3790999799966812e-02 + + 3.5829600691795349e-01 6.5131001174449921e-02 + <_> + + 0 -1 2485 -3.8378998637199402e-02 + + 1.1961040496826172e+00 -1.4971500635147095e-01 + <_> + + 0 -1 2486 -9.8838999867439270e-02 + + -6.1834001541137695e-01 1.2786200642585754e-01 + <_> + + 0 -1 2487 -1.2190700322389603e-01 + + -1.8276120424270630e+00 -6.4862996339797974e-02 + <_> + + 0 -1 2488 -1.1981700360774994e-01 + + -30. 1.1323300004005432e-01 + <_> + + 0 -1 2489 3.0910000205039978e-02 + + -2.3934000730514526e-01 3.6332899332046509e-01 + <_> + + 0 -1 2490 1.0800999589264393e-02 + + -3.5140000283718109e-02 2.7707898616790771e-01 + <_> + + 0 -1 2491 5.6844998151063919e-02 + + -1.5524299442768097e-01 1.0802700519561768e+00 + <_> + + 0 -1 2492 1.0280000278726220e-03 + + -6.1202999204397202e-02 2.0508000254631042e-01 + <_> + + 0 -1 2493 -2.8273999691009521e-02 + + -6.4778000116348267e-01 2.3917000740766525e-02 + <_> + + 0 -1 2494 -1.6013599932193756e-01 + + 1.0892050266265869e+00 5.8389000594615936e-02 + <_> + + 0 -1 2495 4.9629998393356800e-03 + + -2.5806298851966858e-01 2.0834599435329437e-01 + <_> + + 0 -1 2496 4.6937000006437302e-02 + + 1.3886299729347229e-01 -1.5662620067596436e+00 + <_> + + 0 -1 2497 2.4286000058054924e-02 + + -2.0728300511837006e-01 5.2430999279022217e-01 + <_> + + 0 -1 2498 7.0202000439167023e-02 + + 1.4796899259090424e-01 -1.3095090389251709e+00 + <_> + + 0 -1 2499 9.8120002076029778e-03 + + 2.7906000614166260e-02 -5.0864601135253906e-01 + <_> + + 0 -1 2500 -5.6200999766588211e-02 + + 1.2618130445480347e+00 6.3801996409893036e-02 + <_> + + 0 -1 2501 1.0982800275087357e-01 + + -1.2850099802017212e-01 3.0776169300079346e+00 + <_> + 211 + -3.3703000545501709e+00 + + <_> + + 0 -1 2502 2.0910000428557396e-02 + + -6.8559402227401733e-01 3.8984298706054688e-01 + <_> + + 0 -1 2503 3.5032000392675400e-02 + + -4.7724398970603943e-01 4.5027199387550354e-01 + <_> + + 0 -1 2504 3.9799001067876816e-02 + + -4.7011101245880127e-01 4.2702499032020569e-01 + <_> + + 0 -1 2505 -4.8409998416900635e-03 + + 2.5614300370216370e-01 -6.6556298732757568e-01 + <_> + + 0 -1 2506 2.3439999204128981e-03 + + -4.8083499073982239e-01 2.8013798594474792e-01 + <_> + + 0 -1 2507 2.5312999263405800e-02 + + -2.3948200047016144e-01 4.4191798567771912e-01 + <_> + + 0 -1 2508 -3.2193001359701157e-02 + + 7.6086699962615967e-01 -2.5059100985527039e-01 + <_> + + 0 -1 2509 7.5409002602100372e-02 + + -3.4974598884582520e-01 3.4380298852920532e-01 + <_> + + 0 -1 2510 -1.8469000235199928e-02 + + -7.9085600376129150e-01 3.4788001328706741e-02 + <_> + + 0 -1 2511 -1.2802000157535076e-02 + + 4.7107800841331482e-01 -6.0006000101566315e-02 + <_> + + 0 -1 2512 -2.6598000898957253e-02 + + 6.7116099596023560e-01 -2.4257500469684601e-01 + <_> + + 0 -1 2513 2.1988999098539352e-02 + + 2.4717499315738678e-01 -4.8301699757575989e-01 + <_> + + 0 -1 2514 1.4654099941253662e-01 + + -2.1504099667072296e-01 7.2055900096893311e-01 + <_> + + 0 -1 2515 3.5310001112520695e-03 + + 2.7930998802185059e-01 -3.4339898824691772e-01 + <_> + + 0 -1 2516 9.4010001048445702e-03 + + 5.5861998349428177e-02 -8.2143598794937134e-01 + <_> + + 0 -1 2517 -8.6390003561973572e-03 + + -9.9620598554611206e-01 1.8874999880790710e-01 + <_> + + 0 -1 2518 -3.9193000644445419e-02 + + -1.1945559978485107e+00 -2.9198000207543373e-02 + <_> + + 0 -1 2519 2.4855000898241997e-02 + + 1.4987599849700928e-01 -5.4137802124023438e-01 + <_> + + 0 -1 2520 -3.4995000809431076e-02 + + -1.4210180044174194e+00 -4.2314000427722931e-02 + <_> + + 0 -1 2521 -1.8378999084234238e-02 + + -2.8242599964141846e-01 1.5581800043582916e-01 + <_> + + 0 -1 2522 -1.3592000119388103e-02 + + 4.7317099571228027e-01 -2.1937200427055359e-01 + <_> + + 0 -1 2523 6.2629999592900276e-03 + + -5.9714000672101974e-02 6.0625898838043213e-01 + <_> + + 0 -1 2524 -1.8478000536561012e-02 + + -8.5647201538085938e-01 -1.3783999718725681e-02 + <_> + + 0 -1 2525 1.4236000366508961e-02 + + 1.6654799878597260e-01 -2.7713999152183533e-01 + <_> + + 0 -1 2526 -3.2547000795602798e-02 + + -1.1728240251541138e+00 -4.0185000747442245e-02 + <_> + + 0 -1 2527 -2.6410000864416361e-03 + + 2.6514300704002380e-01 -5.6343000382184982e-02 + <_> + + 0 -1 2528 -8.7799999164417386e-04 + + 3.6556001752614975e-02 -5.5075198411941528e-01 + <_> + + 0 -1 2529 4.7371998429298401e-02 + + -4.2614001780748367e-02 4.8194900155067444e-01 + <_> + + 0 -1 2530 -7.0790001191198826e-03 + + 2.8698998689651489e-01 -3.2923001050949097e-01 + <_> + + 0 -1 2531 -4.3145999312400818e-02 + + -1.4065419435501099e+00 1.2836399674415588e-01 + <_> + + 0 -1 2532 2.0592000335454941e-02 + + -2.1435299515724182e-01 5.3981798887252808e-01 + <_> + + 0 -1 2533 -2.2367000579833984e-02 + + 3.3718299865722656e-01 4.5212000608444214e-02 + <_> + + 0 -1 2534 5.0039999186992645e-02 + + -2.5121700763702393e-01 4.1750499606132507e-01 + <_> + + 0 -1 2535 6.1794999986886978e-02 + + 4.0084999054670334e-02 6.8779802322387695e-01 + <_> + + 0 -1 2536 -4.1861999779939651e-02 + + 5.3027397394180298e-01 -2.2901999950408936e-01 + <_> + + 0 -1 2537 -3.1959998887032270e-03 + + 2.5161498785018921e-01 -2.1514600515365601e-01 + <_> + + 0 -1 2538 2.4255000054836273e-02 + + 7.2320001199841499e-03 -7.2519099712371826e-01 + <_> + + 0 -1 2539 -1.7303999513387680e-02 + + -4.9958199262619019e-01 1.8394500017166138e-01 + <_> + + 0 -1 2540 -4.1470001451671124e-03 + + 8.5211999714374542e-02 -4.6364700794219971e-01 + <_> + + 0 -1 2541 -1.4369999989867210e-02 + + -5.2258902788162231e-01 2.3892599344253540e-01 + <_> + + 0 -1 2542 -9.0399999171495438e-03 + + -6.3250398635864258e-01 3.2551001757383347e-02 + <_> + + 0 -1 2543 -1.2373100221157074e-01 + + 1.2856210470199585e+00 7.6545000076293945e-02 + <_> + + 0 -1 2544 -8.2221999764442444e-02 + + 8.3208197355270386e-01 -1.8590599298477173e-01 + <_> + + 0 -1 2545 6.5659001469612122e-02 + + 1.1298800259828568e-01 -30. + <_> + + 0 -1 2546 -3.1582999974489212e-02 + + -1.3485900163650513e+00 -4.7097001224756241e-02 + <_> + + 0 -1 2547 -7.9636000096797943e-02 + + -1.3533639907836914e+00 1.5668800473213196e-01 + <_> + + 0 -1 2548 -1.8880000337958336e-02 + + 4.0300300717353821e-01 -2.5148901343345642e-01 + <_> + + 0 -1 2549 -5.0149997696280479e-03 + + -2.6287099719047546e-01 1.8582500517368317e-01 + <_> + + 0 -1 2550 -1.2218000367283821e-02 + + 5.8692401647567749e-01 -1.9427700340747833e-01 + <_> + + 0 -1 2551 1.2710000155493617e-03 + + -1.6688999533653259e-01 2.3006899654865265e-01 + <_> + + 0 -1 2552 2.9743999242782593e-02 + + 1.2520000338554382e-02 -6.6723597049713135e-01 + <_> + + 0 -1 2553 2.8175000101327896e-02 + + -1.7060000449419022e-02 6.4579397439956665e-01 + <_> + + 0 -1 2554 3.0345000326633453e-02 + + -2.4178700149059296e-01 3.4878900647163391e-01 + <_> + + 0 -1 2555 -1.7325999215245247e-02 + + -5.3599399328231812e-01 2.0995999872684479e-01 + <_> + + 0 -1 2556 -8.4178000688552856e-02 + + 7.5093299150466919e-01 -1.7593200504779816e-01 + <_> + + 0 -1 2557 7.4950000271201134e-03 + + -1.6188099980354309e-01 3.0657500028610229e-01 + <_> + + 0 -1 2558 5.6494999676942825e-02 + + -1.7318800091743469e-01 1.0016150474548340e+00 + <_> + + 0 -1 2559 -5.2939997985959053e-03 + + 2.3417599499225616e-01 -6.5347000956535339e-02 + <_> + + 0 -1 2560 -1.4945000410079956e-02 + + 2.5018900632858276e-01 -3.0591198801994324e-01 + <_> + + 0 -1 2561 5.4919000715017319e-02 + + 1.3121999800205231e-01 -9.3765097856521606e-01 + <_> + + 0 -1 2562 -1.9721999764442444e-02 + + -8.3978497982025146e-01 -2.3473000153899193e-02 + <_> + + 0 -1 2563 -6.7158997058868408e-02 + + 2.3586840629577637e+00 8.2970999181270599e-02 + <_> + + 0 -1 2564 -1.4325999654829502e-02 + + 1.8814499676227570e-01 -3.1221601366996765e-01 + <_> + + 0 -1 2565 2.9841000214219093e-02 + + 1.4825099706649780e-01 -8.4681701660156250e-01 + <_> + + 0 -1 2566 5.1883000880479813e-02 + + -4.3731000274419785e-02 -1.3366169929504395e+00 + <_> + + 0 -1 2567 4.1127000004053116e-02 + + 1.7660099267959595e-01 -6.0904097557067871e-01 + <_> + + 0 -1 2568 -1.2865099310874939e-01 + + -9.8701000213623047e-01 -3.7785001099109650e-02 + <_> + + 0 -1 2569 2.4170000106096268e-03 + + -1.6119599342346191e-01 3.2675701379776001e-01 + <_> + + 0 -1 2570 7.7030002139508724e-03 + + -2.3841500282287598e-01 2.9319399595260620e-01 + <_> + + 0 -1 2571 4.5520000159740448e-02 + + 1.4424599707126617e-01 -1.5010160207748413e+00 + <_> + + 0 -1 2572 -7.8700996935367584e-02 + + -1.0394560098648071e+00 -4.5375999063253403e-02 + <_> + + 0 -1 2573 7.8619997948408127e-03 + + 1.9633600115776062e-01 -1.4472399652004242e-01 + <_> + + 0 -1 2574 -1.3458999805152416e-02 + + -9.0634697675704956e-01 -3.8049001246690750e-02 + <_> + + 0 -1 2575 2.8827000409364700e-02 + + -2.9473999515175819e-02 6.0058397054672241e-01 + <_> + + 0 -1 2576 -2.7365999296307564e-02 + + -9.9804002046585083e-01 -3.8653001189231873e-02 + <_> + + 0 -1 2577 -7.2917997837066650e-02 + + 7.3361498117446899e-01 5.7440001517534256e-02 + <_> + + 0 -1 2578 -1.3988999649882317e-02 + + 2.7892601490020752e-01 -2.6516300439834595e-01 + <_> + + 0 -1 2579 4.3242998421192169e-02 + + 4.7760000452399254e-03 3.5925900936126709e-01 + <_> + + 0 -1 2580 2.9533000662922859e-02 + + -2.0083999633789062e-01 5.1202899217605591e-01 + <_> + + 0 -1 2581 -3.1897000968456268e-02 + + 6.4721697568893433e-01 -1.3760000001639128e-03 + <_> + + 0 -1 2582 3.7868998944759369e-02 + + -1.8363800644874573e-01 6.1343097686767578e-01 + <_> + + 0 -1 2583 -2.2417999804019928e-02 + + -2.9187899827957153e-01 1.8194800615310669e-01 + <_> + + 0 -1 2584 5.8958999812602997e-02 + + -6.6451996564865112e-02 -1.9290030002593994e+00 + <_> + + 0 -1 2585 3.1222999095916748e-02 + + -1.2732000090181828e-02 6.1560797691345215e-01 + <_> + + 0 -1 2586 3.7484999746084213e-02 + + -2.0856900513172150e-01 4.4363999366760254e-01 + <_> + + 0 -1 2587 -2.0966000854969025e-02 + + -3.5712799429893494e-01 2.4252200126647949e-01 + <_> + + 0 -1 2588 -2.5477999821305275e-02 + + 1.0846560001373291e+00 -1.5054400265216827e-01 + <_> + + 0 -1 2589 -7.2570000775158405e-03 + + 2.1302600204944611e-01 -1.8308199942111969e-01 + <_> + + 0 -1 2590 -5.0983000546693802e-02 + + 5.1736801862716675e-01 -1.8833099305629730e-01 + <_> + + 0 -1 2591 -2.0640000700950623e-02 + + -4.4030201435089111e-01 2.2745999693870544e-01 + <_> + + 0 -1 2592 1.0672999545931816e-02 + + 3.5059999674558640e-02 -5.1665002107620239e-01 + <_> + + 0 -1 2593 3.1895998865365982e-02 + + 1.3228000141680241e-02 3.4915199875831604e-01 + <_> + + 0 -1 2594 -2.3824999108910561e-02 + + 3.4118801355361938e-01 -2.1510200202465057e-01 + <_> + + 0 -1 2595 -6.0680001042783260e-03 + + 3.2937398552894592e-01 -2.8523799777030945e-01 + <_> + + 0 -1 2596 2.3881999775767326e-02 + + -2.5333800911903381e-01 2.6296100020408630e-01 + <_> + + 0 -1 2597 2.7966000139713287e-02 + + 1.4049099385738373e-01 -4.9887099862098694e-01 + <_> + + 0 -1 2598 1.4603000134229660e-02 + + -1.5395999886095524e-02 -7.6958000659942627e-01 + <_> + + 0 -1 2599 1.0872399806976318e-01 + + 1.9069600105285645e-01 -3.2393100857734680e-01 + <_> + + 0 -1 2600 -1.4038000255823135e-02 + + 3.4924700856208801e-01 -2.2358700633049011e-01 + <_> + + 0 -1 2601 4.0440000593662262e-03 + + -3.8329001516103745e-02 5.1177299022674561e-01 + <_> + + 0 -1 2602 -4.9769999459385872e-03 + + -4.2888298630714417e-01 4.9173999577760696e-02 + <_> + + 0 -1 2603 -8.5183002054691315e-02 + + 6.6624599695205688e-01 7.8079998493194580e-03 + <_> + + 0 -1 2604 2.1559998858720064e-03 + + -4.9135199189186096e-01 6.9555997848510742e-02 + <_> + + 0 -1 2605 3.6384499073028564e-01 + + 1.2997099757194519e-01 -1.8949509859085083e+00 + <_> + + 0 -1 2606 2.2082500159740448e-01 + + -5.7211998850107193e-02 -1.4281120300292969e+00 + <_> + + 0 -1 2607 -1.6140000894665718e-02 + + -5.7589399814605713e-01 1.8062500655651093e-01 + <_> + + 0 -1 2608 -4.8330001533031464e-02 + + 9.7308498620986938e-01 -1.6513000428676605e-01 + <_> + + 0 -1 2609 1.7529999837279320e-02 + + 1.7932699620723724e-01 -2.7948901057243347e-01 + <_> + + 0 -1 2610 -3.4309998154640198e-02 + + -8.1072497367858887e-01 -1.6596000641584396e-02 + <_> + + 0 -1 2611 -4.5830002054572105e-03 + + 2.7908998727798462e-01 -7.4519999325275421e-03 + <_> + + 0 -1 2612 1.2896400690078735e-01 + + -1.3508500158786774e-01 2.5411539077758789e+00 + <_> + + 0 -1 2613 3.0361000448465347e-02 + + -6.8419001996517181e-02 2.8734099864959717e-01 + <_> + + 0 -1 2614 4.4086001813411713e-02 + + -1.8135899305343628e-01 6.5413200855255127e-01 + <_> + + 0 -1 2615 3.0159999150782824e-03 + + -1.5690499544143677e-01 2.6963800191879272e-01 + <_> + + 0 -1 2616 -2.6336999610066414e-02 + + 2.9175600409507751e-01 -2.5274100899696350e-01 + <_> + + 0 -1 2617 -2.7866000309586525e-02 + + 4.4387501478195190e-01 5.5038001388311386e-02 + <_> + + 0 -1 2618 1.1725000105798244e-02 + + -1.9346499443054199e-01 4.6656700968742371e-01 + <_> + + 0 -1 2619 1.5689999563619494e-03 + + -8.2360003143548965e-03 2.5700899958610535e-01 + <_> + + 0 -1 2620 -3.5550000611692667e-03 + + -4.2430898547172546e-01 7.1174003183841705e-02 + <_> + + 0 -1 2621 -3.1695000827312469e-02 + + -8.5393500328063965e-01 1.6916200518608093e-01 + <_> + + 0 -1 2622 -3.2097000628709793e-02 + + 8.3784902095794678e-01 -1.7597299814224243e-01 + <_> + + 0 -1 2623 1.5544199943542480e-01 + + 9.9550001323223114e-02 2.3873300552368164e+00 + <_> + + 0 -1 2624 8.8045999407768250e-02 + + -1.8725299835205078e-01 6.2384301424026489e-01 + <_> + + 0 -1 2625 -1.6720000421628356e-03 + + 2.5008699297904968e-01 -6.5118998289108276e-02 + <_> + + 0 -1 2626 9.3409996479749680e-03 + + -3.5378900170326233e-01 1.0715000331401825e-01 + <_> + + 0 -1 2627 3.7138000130653381e-02 + + 1.6387000679969788e-01 -9.1718399524688721e-01 + <_> + + 0 -1 2628 8.0183997750282288e-02 + + -1.4812999963760376e-01 1.4895190000534058e+00 + <_> + + 0 -1 2629 -7.9100002767518163e-04 + + -2.1326899528503418e-01 1.9676400721073151e-01 + <_> + + 0 -1 2630 -5.0400001928210258e-03 + + -7.1318697929382324e-01 1.8240000354126096e-03 + <_> + + 0 -1 2631 1.1962399631738663e-01 + + 3.3098999410867691e-02 1.0441709756851196e+00 + <_> + + 0 -1 2632 -4.5280000194907188e-03 + + -2.7308499813079834e-01 2.7229800820350647e-01 + <_> + + 0 -1 2633 -2.9639000073075294e-02 + + 3.6225798726081848e-01 5.6795001029968262e-02 + <_> + + 0 -1 2634 2.6650000363588333e-02 + + -4.8041000962257385e-02 -9.6723502874374390e-01 + <_> + + 0 -1 2635 4.4422000646591187e-02 + + 1.3052900135517120e-01 -3.5077300667762756e-01 + <_> + + 0 -1 2636 -2.4359999224543571e-02 + + -1.0766899585723877e+00 -5.1222998648881912e-02 + <_> + + 0 -1 2637 1.9734999164938927e-02 + + 2.6238000020384789e-02 2.8070500493049622e-01 + <_> + + 0 -1 2638 5.4930001497268677e-03 + + -2.6111298799514771e-01 2.1011400222778320e-01 + <_> + + 0 -1 2639 -2.3200300335884094e-01 + + -1.7748440504074097e+00 1.1482600122690201e-01 + <_> + + 0 -1 2640 -2.5614000856876373e-02 + + 2.9900801181793213e-01 -2.2502499818801880e-01 + <_> + + 0 -1 2641 -6.4949998632073402e-03 + + 1.9563800096511841e-01 -9.9762998521327972e-02 + <_> + + 0 -1 2642 3.9840000681579113e-03 + + -4.3021500110626221e-01 8.1261001527309418e-02 + <_> + + 0 -1 2643 -3.5813000053167343e-02 + + -5.0987398624420166e-01 1.6345900297164917e-01 + <_> + + 0 -1 2644 -1.4169000089168549e-02 + + 7.7978098392486572e-01 -1.7476299405097961e-01 + <_> + + 0 -1 2645 -1.2642100453376770e-01 + + -6.3047897815704346e-01 1.2728300690650940e-01 + <_> + + 0 -1 2646 6.8677999079227448e-02 + + -4.6447999775409698e-02 -1.1128979921340942e+00 + <_> + + 0 -1 2647 8.5864998400211334e-02 + + 1.1835400015115738e-01 -4.8235158920288086e+00 + <_> + + 0 -1 2648 1.5511999838054180e-02 + + -1.7467999830842018e-02 -6.3693398237228394e-01 + <_> + + 0 -1 2649 8.1091001629829407e-02 + + 8.6133003234863281e-02 2.4559431076049805e+00 + <_> + + 0 -1 2650 1.8495000898838043e-02 + + 4.0229000151157379e-02 -5.0858199596405029e-01 + <_> + + 0 -1 2651 -8.6320996284484863e-02 + + -1.9006760120391846e+00 1.1019100248813629e-01 + <_> + + 0 -1 2652 7.2355002164840698e-02 + + -6.2111999839544296e-02 -1.4165179729461670e+00 + <_> + + 0 -1 2653 -7.8179001808166504e-02 + + 8.8849300146102905e-01 4.2369998991489410e-02 + <_> + + 0 -1 2654 9.6681997179985046e-02 + + -2.2094200551509857e-01 3.3575099706649780e-01 + <_> + + 0 -1 2655 -3.9875999093055725e-02 + + 5.7804799079895020e-01 4.5347999781370163e-02 + <_> + + 0 -1 2656 -9.5349997282028198e-03 + + -5.4175698757171631e-01 3.2399999909102917e-03 + <_> + + 0 -1 2657 4.0600000647827983e-04 + + -8.1549003720283508e-02 3.5837900638580322e-01 + <_> + + 0 -1 2658 1.2107999995350838e-02 + + -2.0280399918556213e-01 4.3768000602722168e-01 + <_> + + 0 -1 2659 -2.0873999223113060e-02 + + 4.1469898819923401e-01 -4.5568000525236130e-02 + <_> + + 0 -1 2660 5.7888001203536987e-02 + + -2.9009999707341194e-02 -9.1822302341461182e-01 + <_> + + 0 -1 2661 1.3200000103097409e-04 + + -1.1772400140762329e-01 2.0000000298023224e-01 + <_> + + 0 -1 2662 -1.7137000337243080e-02 + + 3.3004799485206604e-01 -2.3055200278759003e-01 + <_> + + 0 -1 2663 3.0655000358819962e-02 + + -2.1545000374317169e-02 2.6878198981285095e-01 + <_> + + 0 -1 2664 -7.8699999721720815e-04 + + -4.4100698828697205e-01 4.9157999455928802e-02 + <_> + + 0 -1 2665 8.8036999106407166e-02 + + 1.1782000213861465e-01 -2.8293309211730957e+00 + <_> + + 0 -1 2666 -3.9028998464345932e-02 + + 9.1777199506759644e-01 -1.5827399492263794e-01 + <_> + + 0 -1 2667 8.0105997622013092e-02 + + 1.1289200186729431e-01 -1.9937280416488647e+00 + <_> + + 0 -1 2668 3.9538998156785965e-02 + + -1.4357399940490723e-01 1.3085240125656128e+00 + <_> + + 0 -1 2669 2.0684000104665756e-02 + + 2.0048099756240845e-01 -4.4186998158693314e-02 + <_> + + 0 -1 2670 -6.7037999629974365e-02 + + 3.2618600130081177e-01 -2.0550400018692017e-01 + <_> + + 0 -1 2671 4.6815000474452972e-02 + + 1.5825299918651581e-01 -9.5535099506378174e-01 + <_> + + 0 -1 2672 7.8443996608257294e-02 + + -7.4651002883911133e-02 -2.1161499023437500e+00 + <_> + + 0 -1 2673 6.6380001604557037e-02 + + 1.1641900241374969e-01 -1.6113519668579102e+00 + <_> + + 0 -1 2674 3.0053999274969101e-02 + + -1.6562600433826447e-01 7.0025402307510376e-01 + <_> + + 0 -1 2675 1.7119999974966049e-02 + + 2.2627699375152588e-01 -4.0114998817443848e-01 + <_> + + 0 -1 2676 2.0073000341653824e-02 + + -1.9389699399471283e-01 4.4420298933982849e-01 + <_> + + 0 -1 2677 3.3101998269557953e-02 + + 1.1637499928474426e-01 -1.5771679878234863e+00 + <_> + + 0 -1 2678 -1.4882000163197517e-02 + + -8.9680302143096924e-01 -4.2010001838207245e-02 + <_> + + 0 -1 2679 -1.0281000286340714e-02 + + 3.5602998733520508e-01 -1.3124000281095505e-02 + <_> + + 0 -1 2680 -2.8695000335574150e-02 + + -4.6039599180221558e-01 2.6801999658346176e-02 + <_> + + 0 -1 2681 -4.7189998440444469e-03 + + 2.3788799345493317e-01 -6.5518997609615326e-02 + <_> + + 0 -1 2682 3.2201600074768066e-01 + + -2.8489999473094940e-02 -8.4234601259231567e-01 + <_> + + 0 -1 2683 -1.7045000568032265e-02 + + -5.0938802957534790e-01 1.6057600080966949e-01 + <_> + + 0 -1 2684 -7.3469998314976692e-03 + + -5.4154998064041138e-01 4.7320001758635044e-03 + <_> + + 0 -1 2685 -3.0001999810338020e-02 + + -8.8785797357559204e-01 1.3621799647808075e-01 + <_> + + 0 -1 2686 -1.1292999610304832e-02 + + 8.0615198612213135e-01 -1.6159500181674957e-01 + <_> + + 0 -1 2687 4.7749998047947884e-03 + + 1.2968000024557114e-02 5.5079901218414307e-01 + <_> + + 0 -1 2688 5.0710001960396767e-03 + + -4.5728001743555069e-02 -1.0766259431838989e+00 + <_> + + 0 -1 2689 1.9344100356101990e-01 + + 7.1262001991271973e-02 1.1694519519805908e+00 + <_> + + 0 -1 2690 5.3750001825392246e-03 + + -1.9736200571060181e-01 3.8206899166107178e-01 + <_> + + 0 -1 2691 -6.8276003003120422e-02 + + -5.4372339248657227e+00 1.1151900142431259e-01 + <_> + + 0 -1 2692 -3.4933000802993774e-02 + + 4.4793400168418884e-01 -1.8657900393009186e-01 + <_> + + 0 -1 2693 5.1219998858869076e-03 + + -1.4871999621391296e-02 1.8413899838924408e-01 + <_> + + 0 -1 2694 9.5311999320983887e-02 + + -1.5117099881172180e-01 9.4991499185562134e-01 + <_> + + 0 -1 2695 -6.2849000096321106e-02 + + 4.6473601460456848e-01 3.8405001163482666e-02 + <_> + + 0 -1 2696 -1.7040699720382690e-01 + + -1.6499999761581421e+00 -6.3236996531486511e-02 + <_> + + 0 -1 2697 1.0583999566733837e-02 + + -3.8348998874425888e-02 4.1913801431655884e-01 + <_> + + 0 -1 2698 -4.1579000651836395e-02 + + 3.4461900591850281e-01 -2.1187700331211090e-01 + <_> + + 0 -1 2699 1.2718600034713745e-01 + + 1.2398199737071991e-01 -2.1254889965057373e+00 + <_> + + 0 -1 2700 8.2557000219821930e-02 + + -6.2024001032114029e-02 -1.4875819683074951e+00 + <_> + + 0 -1 2701 8.5293002426624298e-02 + + 1.7087999731302261e-02 3.2076600193977356e-01 + <_> + + 0 -1 2702 5.5544000118970871e-02 + + -2.7414000034332275e-01 1.8976399302482605e-01 + <_> + + 0 -1 2703 4.5650000683963299e-03 + + -1.7920200526714325e-01 2.7967301011085510e-01 + <_> + + 0 -1 2704 1.2997999787330627e-02 + + -3.2297500967979431e-01 2.6941800117492676e-01 + <_> + + 0 -1 2705 5.7891998440027237e-02 + + 1.2644399702548981e-01 -6.0713499784469604e-01 + <_> + + 0 -1 2706 -2.2824000567197800e-02 + + -4.9682098627090454e-01 2.2376999258995056e-02 + <_> + + 0 -1 2707 4.8312000930309296e-02 + + 4.3607000261545181e-02 4.8537799715995789e-01 + <_> + + 0 -1 2708 2.5714000687003136e-02 + + -4.2950998991727829e-02 -9.3023502826690674e-01 + <_> + + 0 -1 2709 6.9269998930394650e-03 + + -2.9680000152438879e-03 3.4296301007270813e-01 + <_> + + 0 -1 2710 -3.4446999430656433e-02 + + -1.5299769639968872e+00 -6.1014998704195023e-02 + <_> + + 0 -1 2711 2.9387999325990677e-02 + + 3.7595998495817184e-02 6.4172399044036865e-01 + <_> + + 0 -1 2712 -2.4319998919963837e-03 + + 9.9088996648788452e-02 -3.9688101410865784e-01 + <_> + 200 + -2.9928278923034668e+00 + + <_> + + 0 -1 2713 -9.5944002270698547e-02 + + 6.2419098615646362e-01 -4.5875200629234314e-01 + <_> + + 0 -1 2714 1.6834000125527382e-02 + + -9.3072801828384399e-01 2.1563600003719330e-01 + <_> + + 0 -1 2715 2.6049999520182610e-02 + + -4.0532299876213074e-01 4.2256599664688110e-01 + <_> + + 0 -1 2716 3.6500001442618668e-04 + + 9.5288001000881195e-02 -6.3298100233078003e-01 + <_> + + 0 -1 2717 -6.6940002143383026e-03 + + 3.7243801355361938e-01 -3.0332401394844055e-01 + <_> + + 0 -1 2718 1.8874000757932663e-02 + + -2.3357200622558594e-01 4.0330699086189270e-01 + <_> + + 0 -1 2719 -1.6300000424962491e-04 + + 4.2886998504400253e-02 -7.7796798944473267e-01 + <_> + + 0 -1 2720 -7.6259002089500427e-02 + + -4.9628499150276184e-01 1.6335399448871613e-01 + <_> + + 0 -1 2721 5.0149001181125641e-02 + + 3.2747000455856323e-02 -8.0047899484634399e-01 + <_> + + 0 -1 2722 -2.9239999130368233e-03 + + -5.0002801418304443e-01 2.5480601191520691e-01 + <_> + + 0 -1 2723 1.6243999823927879e-02 + + 3.8913000375032425e-02 -7.0724898576736450e-01 + <_> + + 0 -1 2724 3.7811998277902603e-02 + + -6.6267997026443481e-02 7.3868799209594727e-01 + <_> + + 0 -1 2725 -1.2319999746978283e-02 + + 4.8696398735046387e-01 -2.4485599994659424e-01 + <_> + + 0 -1 2726 5.8003999292850494e-02 + + 1.3459099829196930e-01 -1.3232100009918213e-01 + <_> + + 0 -1 2727 4.8630000092089176e-03 + + -4.4172900915145874e-01 1.4005599915981293e-01 + <_> + + 0 -1 2728 4.5690998435020447e-02 + + 3.1217999756336212e-02 8.9818298816680908e-01 + <_> + + 0 -1 2729 2.1321000531315804e-02 + + 1.2008000165224075e-02 -8.6066198348999023e-01 + <_> + + 0 -1 2730 1.5679100155830383e-01 + + 1.4055999927222729e-02 8.5332900285720825e-01 + <_> + + 0 -1 2731 -1.0328999720513821e-02 + + 2.9022800922393799e-01 -2.9478800296783447e-01 + <_> + + 0 -1 2732 2.4290001019835472e-03 + + -4.0439900755882263e-01 1.9400200247764587e-01 + <_> + + 0 -1 2733 -2.3338999599218369e-02 + + 3.2945200800895691e-01 -2.5712698698043823e-01 + <_> + + 0 -1 2734 -6.8970001302659512e-03 + + -5.3352999687194824e-01 2.1635200083255768e-01 + <_> + + 0 -1 2735 -3.4403000026941299e-02 + + -1.4425489902496338e+00 -4.4682998210191727e-02 + <_> + + 0 -1 2736 -2.1235000342130661e-02 + + -7.9017502069473267e-01 1.9084100425243378e-01 + <_> + + 0 -1 2737 2.0620001014322042e-03 + + -2.6931199431419373e-01 3.1488001346588135e-01 + <_> + + 0 -1 2738 -4.2190002277493477e-03 + + -5.4464399814605713e-01 1.6574600338935852e-01 + <_> + + 0 -1 2739 -1.4334999956190586e-02 + + 2.2105000913143158e-02 -6.2342500686645508e-01 + <_> + + 0 -1 2740 -8.2120001316070557e-03 + + -4.9884998798370361e-01 1.9237099587917328e-01 + <_> + + 0 -1 2741 -9.3350000679492950e-03 + + -7.9131197929382324e-01 -1.4143999665975571e-02 + <_> + + 0 -1 2742 -3.7937998771667480e-02 + + 7.9841297864913940e-01 -3.3799000084400177e-02 + <_> + + 0 -1 2743 4.7059999778866768e-03 + + -3.3163401484489441e-01 2.0726299285888672e-01 + <_> + + 0 -1 2744 -4.4499998912215233e-03 + + -2.7256301045417786e-01 1.8402199447154999e-01 + <_> + + 0 -1 2745 5.2189999260008335e-03 + + -5.3096002340316772e-01 5.2607998251914978e-02 + <_> + + 0 -1 2746 -9.5399999991059303e-03 + + -5.6485402584075928e-01 1.9269399344921112e-01 + <_> + + 0 -1 2747 4.4969998300075531e-02 + + -1.7411500215530396e-01 9.5382601022720337e-01 + <_> + + 0 -1 2748 1.4209000393748283e-02 + + -9.1949000954627991e-02 2.4836100637912750e-01 + <_> + + 0 -1 2749 1.6380199790000916e-01 + + -5.8497000485658646e-02 -1.6404409408569336e+00 + <_> + + 0 -1 2750 2.5579999200999737e-03 + + 2.3447999358177185e-01 -9.2734001576900482e-02 + <_> + + 0 -1 2751 -3.8499999791383743e-03 + + 1.7880700528621674e-01 -3.5844099521636963e-01 + <_> + + 0 -1 2752 -2.5221999734640121e-02 + + -4.2903000116348267e-01 2.0244500041007996e-01 + <_> + + 0 -1 2753 -1.9415000453591347e-02 + + 5.8016300201416016e-01 -1.8806399405002594e-01 + <_> + + 0 -1 2754 1.4419999904930592e-02 + + 3.2846998423337936e-02 8.1980502605438232e-01 + <_> + + 0 -1 2755 5.1582999527454376e-02 + + 6.9176003336906433e-02 -4.5866298675537109e-01 + <_> + + 0 -1 2756 -3.7960000336170197e-02 + + -1.2553000450134277e+00 1.4332899451255798e-01 + <_> + + 0 -1 2757 -2.9560999944806099e-02 + + 5.3151798248291016e-01 -2.0596499741077423e-01 + <_> + + 0 -1 2758 -3.9110999554395676e-02 + + 1.1658719778060913e+00 5.3897000849246979e-02 + <_> + + 0 -1 2759 -2.9159000143408775e-02 + + 3.9307600259780884e-01 -2.2184500098228455e-01 + <_> + + 0 -1 2760 -8.3617001771926880e-02 + + -7.3744499683380127e-01 1.4268200099468231e-01 + <_> + + 0 -1 2761 4.2004001140594482e-01 + + -1.4277400076389313e-01 1.7894840240478516e+00 + <_> + + 0 -1 2762 6.0005001723766327e-02 + + 1.1976700276136398e-01 -1.8886189460754395e+00 + <_> + + 0 -1 2763 -1.8981000408530235e-02 + + -1.4148449897766113e+00 -5.6522998958826065e-02 + <_> + + 0 -1 2764 -6.0049998573958874e-03 + + 4.4170799851417542e-01 -1.0200800001621246e-01 + <_> + + 0 -1 2765 -5.8214001357555389e-02 + + -1.3918470144271851e+00 -4.8268999904394150e-02 + <_> + + 0 -1 2766 -1.2271000072360039e-02 + + 5.1317697763442993e-01 -9.3696996569633484e-02 + <_> + + 0 -1 2767 4.6585999429225922e-02 + + -5.7484000921249390e-02 -1.4283169507980347e+00 + <_> + + 0 -1 2768 1.2110000243410468e-03 + + -8.0891996622085571e-02 3.2333201169967651e-01 + <_> + + 0 -1 2769 -8.8642001152038574e-02 + + -8.6449098587036133e-01 -3.3146999776363373e-02 + <_> + + 0 -1 2770 -2.3184999823570251e-02 + + 5.2162200212478638e-01 -1.6168000176548958e-02 + <_> + + 0 -1 2771 4.3090000748634338e-02 + + -1.6153800487518311e-01 1.0915000438690186e+00 + <_> + + 0 -1 2772 2.0599999697878957e-04 + + -1.7091499269008636e-01 3.1236699223518372e-01 + <_> + + 0 -1 2773 8.9159999042749405e-03 + + -6.7039998248219490e-03 -6.8810397386550903e-01 + <_> + + 0 -1 2774 -1.7752999439835548e-02 + + 6.3292801380157471e-01 -4.2360001243650913e-03 + <_> + + 0 -1 2775 6.2299999408423901e-03 + + -3.3637198805809021e-01 1.2790599465370178e-01 + <_> + + 0 -1 2776 2.2770000621676445e-02 + + -3.4703999757766724e-02 3.9141800999641418e-01 + <_> + + 0 -1 2777 -2.1534999832510948e-02 + + 6.4765101671218872e-01 -2.0097799599170685e-01 + <_> + + 0 -1 2778 6.1758998781442642e-02 + + 5.4297000169754028e-02 9.0700101852416992e-01 + <_> + + 0 -1 2779 -7.8069999814033508e-02 + + 6.5523397922515869e-01 -1.9754399359226227e-01 + <_> + + 0 -1 2780 1.1315000243484974e-02 + + 1.9385300576686859e-01 -5.1707297563552856e-01 + <_> + + 0 -1 2781 -2.5590000674128532e-02 + + -9.3096500635147095e-01 -3.1546998769044876e-02 + <_> + + 0 -1 2782 -3.8058999925851822e-02 + + -6.8326902389526367e-01 1.2709100544452667e-01 + <_> + + 0 -1 2783 9.7970003262162209e-03 + + 1.5523999929428101e-02 -6.3347899913787842e-01 + <_> + + 0 -1 2784 -1.3841999694705009e-02 + + 1.0060529708862305e+00 6.2812998890876770e-02 + <_> + + 0 -1 2785 8.3459997549653053e-03 + + -2.3383200168609619e-01 3.0982699990272522e-01 + <_> + + 0 -1 2786 -7.1439996361732483e-02 + + -7.2505402565002441e-01 1.7148299515247345e-01 + <_> + + 0 -1 2787 1.0006000287830830e-02 + + -2.2071999311447144e-01 3.5266199707984924e-01 + <_> + + 0 -1 2788 1.1005300283432007e-01 + + 1.6662000119686127e-01 -7.4318999052047729e-01 + <_> + + 0 -1 2789 3.5310998558998108e-02 + + -2.3982700705528259e-01 4.1435998678207397e-01 + <_> + + 0 -1 2790 -1.1174699664115906e-01 + + 5.1045399904251099e-01 2.2319999989122152e-03 + <_> + + 0 -1 2791 -1.1367800086736679e-01 + + 9.0475201606750488e-01 -1.6615299880504608e-01 + <_> + + 0 -1 2792 1.6667999327182770e-02 + + 1.4024500548839569e-01 -5.2178502082824707e-01 + <_> + + 0 -1 2793 -8.0340001732110977e-03 + + -6.6178399324417114e-01 3.7640000227838755e-03 + <_> + + 0 -1 2794 -3.3096998929977417e-02 + + 8.0185902118682861e-01 5.9385001659393311e-02 + <_> + + 0 -1 2795 1.2547999620437622e-02 + + -3.3545500040054321e-01 1.4578600227832794e-01 + <_> + + 0 -1 2796 -4.2073998600244522e-02 + + -5.5509102344512939e-01 1.3266600668430328e-01 + <_> + + 0 -1 2797 2.5221999734640121e-02 + + -6.1631999909877777e-02 -1.3678770065307617e+00 + <_> + + 0 -1 2798 -2.4268999695777893e-02 + + 3.4185099601745605e-01 -7.4160001240670681e-03 + <_> + + 0 -1 2799 -1.2280000373721123e-02 + + 2.7745801210403442e-01 -3.1033900380134583e-01 + <_> + + 0 -1 2800 -1.1377099901437759e-01 + + 1.1719540357589722e+00 8.3681002259254456e-02 + <_> + + 0 -1 2801 -8.4771998226642609e-02 + + 8.1694799661636353e-01 -1.7837500572204590e-01 + <_> + + 0 -1 2802 -2.4552000686526299e-02 + + -1.8627299368381500e-01 1.4340099692344666e-01 + <_> + + 0 -1 2803 -9.0269995853304863e-03 + + 3.2659199833869934e-01 -2.3541299998760223e-01 + <_> + + 0 -1 2804 1.1177999898791313e-02 + + 1.9761200249195099e-01 -2.1701000630855560e-02 + <_> + + 0 -1 2805 -2.9366999864578247e-02 + + -9.3414801359176636e-01 -2.1704999729990959e-02 + <_> + + 0 -1 2806 6.3640000298619270e-03 + + 2.5573000311851501e-02 4.6412798762321472e-01 + <_> + + 0 -1 2807 1.4026000164449215e-02 + + -2.1228599548339844e-01 4.0078800916671753e-01 + <_> + + 0 -1 2808 -1.3341999612748623e-02 + + 7.4202698469161987e-01 2.9001999646425247e-02 + <_> + + 0 -1 2809 2.8422799706459045e-01 + + -1.9243599474430084e-01 4.3631199002265930e-01 + <_> + + 0 -1 2810 -2.3724000155925751e-01 + + 6.9736397266387939e-01 6.9307997822761536e-02 + <_> + + 0 -1 2811 -1.1169700324535370e-01 + + 3.9147201180458069e-01 -2.0922000706195831e-01 + <_> + + 0 -1 2812 1.2787500023841858e-01 + + -7.2555996477603912e-02 3.6088201403617859e-01 + <_> + + 0 -1 2813 -6.2900997698307037e-02 + + 9.5424997806549072e-01 -1.5402799844741821e-01 + <_> + + 0 -1 2814 1.7439000308513641e-02 + + -5.1134999841451645e-02 2.7750301361083984e-01 + <_> + + 0 -1 2815 1.2319999514147639e-03 + + 7.5627997517585754e-02 -3.6456099152565002e-01 + <_> + + 0 -1 2816 2.7495000511407852e-02 + + 5.1844000816345215e-02 4.1562598943710327e-01 + <_> + + 0 -1 2817 -4.3543998152017593e-02 + + 7.1969997882843018e-01 -1.7132200300693512e-01 + <_> + + 0 -1 2818 1.1025999672710896e-02 + + 1.4354600012302399e-01 -6.5403002500534058e-01 + <_> + + 0 -1 2819 2.0865999162197113e-02 + + 4.0089000016450882e-02 -4.5743298530578613e-01 + <_> + + 0 -1 2820 -2.2304000332951546e-02 + + 5.3855001926422119e-01 7.1662999689579010e-02 + <_> + + 0 -1 2821 3.2492000609636307e-02 + + -4.5991998165845871e-02 -1.0047069787979126e+00 + <_> + + 0 -1 2822 1.2269999831914902e-02 + + 3.4334998577833176e-02 4.2431798577308655e-01 + <_> + + 0 -1 2823 8.3820000290870667e-03 + + -2.5850600004196167e-01 2.6263499259948730e-01 + <_> + + 0 -1 2824 3.7353999912738800e-02 + + 1.5692499279975891e-01 -1.0429090261459351e+00 + <_> + + 0 -1 2825 -1.4111000113189220e-02 + + -7.3177701234817505e-01 -2.0276999101042747e-02 + <_> + + 0 -1 2826 5.7066999375820160e-02 + + 8.3360001444816589e-02 1.5661499500274658e+00 + <_> + + 0 -1 2827 4.9680001102387905e-03 + + -3.5318198800086975e-01 1.4698399603366852e-01 + <_> + + 0 -1 2828 -2.4492999538779259e-02 + + 2.8325900435447693e-01 -3.4640000667423010e-03 + <_> + + 0 -1 2829 -1.1254999786615372e-02 + + -8.4017497301101685e-01 -3.6251999437808990e-02 + <_> + + 0 -1 2830 3.4533001482486725e-02 + + 1.4998500049114227e-01 -8.7367099523544312e-01 + <_> + + 0 -1 2831 2.4303000420331955e-02 + + -1.8787500262260437e-01 5.9483999013900757e-01 + <_> + + 0 -1 2832 -7.8790001571178436e-03 + + 4.4315698742866516e-01 -5.6570999324321747e-02 + <_> + + 0 -1 2833 3.5142000764608383e-02 + + -5.6494999676942825e-02 -1.3617190122604370e+00 + <_> + + 0 -1 2834 4.6259998343884945e-03 + + -3.1161698698997498e-01 2.5447699427604675e-01 + <_> + + 0 -1 2835 -8.3131000399589539e-02 + + 1.6424349546432495e+00 -1.4429399371147156e-01 + <_> + + 0 -1 2836 -1.4015999622642994e-02 + + -7.7819502353668213e-01 1.7173300683498383e-01 + <_> + + 0 -1 2837 1.2450000504031777e-03 + + -2.3191399872303009e-01 2.8527900576591492e-01 + <_> + + 0 -1 2838 -1.6803000122308731e-02 + + -3.5965099930763245e-01 2.0412999391555786e-01 + <_> + + 0 -1 2839 -7.6747998595237732e-02 + + 7.8050500154495239e-01 -1.5612800419330597e-01 + <_> + + 0 -1 2840 -2.3671999573707581e-01 + + 1.1813700199127197e+00 7.8111998736858368e-02 + <_> + + 0 -1 2841 -1.0057400166988373e-01 + + -4.7104099392890930e-01 7.9172998666763306e-02 + <_> + + 0 -1 2842 1.3239999534562230e-03 + + 2.2262699902057648e-01 -3.7099799513816833e-01 + <_> + + 0 -1 2843 2.2152999415993690e-02 + + -3.8649000227451324e-02 -9.2274999618530273e-01 + <_> + + 0 -1 2844 -1.1246199905872345e-01 + + 4.1899600625038147e-01 8.0411002039909363e-02 + <_> + + 0 -1 2845 1.6481000930070877e-02 + + -1.6756699979305267e-01 7.1842402219772339e-01 + <_> + + 0 -1 2846 6.8113997578620911e-02 + + 1.5719899535179138e-01 -8.7681102752685547e-01 + <_> + + 0 -1 2847 1.6011999920010567e-02 + + -4.1600000113248825e-03 -5.9327799081802368e-01 + <_> + + 0 -1 2848 4.6640001237392426e-03 + + -3.0153999105095863e-02 4.8345300555229187e-01 + <_> + + 0 -1 2849 6.7579997703433037e-03 + + -2.2667400538921356e-01 3.3662301301956177e-01 + <_> + + 0 -1 2850 4.7289999201893806e-03 + + -6.0373999178409576e-02 3.1458100676536560e-01 + <_> + + 0 -1 2851 2.5869999080896378e-03 + + -2.9872599244117737e-01 1.7787499725818634e-01 + <_> + + 0 -1 2852 2.8989999555051327e-03 + + 2.1890200674533844e-01 -2.9567098617553711e-01 + <_> + + 0 -1 2853 -3.0053999274969101e-02 + + 1.2150429487228394e+00 -1.4354999363422394e-01 + <_> + + 0 -1 2854 1.4181000180542469e-02 + + 1.2451999820768833e-02 5.5490100383758545e-01 + <_> + + 0 -1 2855 -6.0527000576257706e-02 + + -1.4933999776840210e+00 -6.5227001905441284e-02 + <_> + + 0 -1 2856 -1.9882999360561371e-02 + + -3.8526400923728943e-01 1.9761200249195099e-01 + <_> + + 0 -1 2857 3.1218999996781349e-02 + + -2.1281200647354126e-01 2.9446500539779663e-01 + <_> + + 0 -1 2858 1.8271999433636665e-02 + + 9.7200000891461968e-04 6.6814202070236206e-01 + <_> + + 0 -1 2859 1.1089999461546540e-03 + + -6.2467902898788452e-01 -1.6599999507889152e-03 + <_> + + 0 -1 2860 -3.6713998764753342e-02 + + -4.2333900928497314e-01 1.2084700167179108e-01 + <_> + + 0 -1 2861 1.2044000439345837e-02 + + 2.5882000103592873e-02 -5.0732398033142090e-01 + <_> + + 0 -1 2862 7.4749000370502472e-02 + + 1.3184699416160583e-01 -2.1739600598812103e-01 + <_> + + 0 -1 2863 -2.3473200201988220e-01 + + 1.1775610446929932e+00 -1.5114699304103851e-01 + <_> + + 0 -1 2864 1.4096499979496002e-01 + + 3.3991001546382904e-02 3.9923098683357239e-01 + <_> + + 0 -1 2865 6.1789997853338718e-03 + + -3.1806701421737671e-01 1.1681699752807617e-01 + <_> + + 0 -1 2866 -5.7216998189687729e-02 + + 8.4399098157882690e-01 8.3889000117778778e-02 + <_> + + 0 -1 2867 -5.5227000266313553e-02 + + 3.6888301372528076e-01 -1.8913400173187256e-01 + <_> + + 0 -1 2868 -2.1583000198006630e-02 + + -5.2161800861358643e-01 1.5772600471973419e-01 + <_> + + 0 -1 2869 2.5747999548912048e-02 + + -5.9921998530626297e-02 -1.0674990415573120e+00 + <_> + + 0 -1 2870 -1.3098999857902527e-02 + + 7.8958398103713989e-01 5.2099999040365219e-02 + <_> + + 0 -1 2871 2.2799998987466097e-03 + + -1.1704430580139160e+00 -5.9356998652219772e-02 + <_> + + 0 -1 2872 8.8060004636645317e-03 + + 4.1717998683452606e-02 6.6352599859237671e-01 + <_> + + 0 -1 2873 -8.9699998497962952e-03 + + -3.5862699151039124e-01 6.0458000749349594e-02 + <_> + + 0 -1 2874 4.0230001322925091e-03 + + 2.0979399979114532e-01 -2.4806000292301178e-01 + <_> + + 0 -1 2875 2.5017000734806061e-02 + + -1.8795900046825409e-01 3.9547100663185120e-01 + <_> + + 0 -1 2876 -5.9009999968111515e-03 + + 2.5663900375366211e-01 -9.4919003546237946e-02 + <_> + + 0 -1 2877 4.3850000947713852e-03 + + 3.3139001578092575e-02 -4.6075400710105896e-01 + <_> + + 0 -1 2878 -3.3771999180316925e-02 + + -9.8881602287292480e-01 1.4636899530887604e-01 + <_> + + 0 -1 2879 4.4523000717163086e-02 + + -1.3286699354648590e-01 1.5796790122985840e+00 + <_> + + 0 -1 2880 -4.0929000824689865e-02 + + 3.3877098560333252e-01 7.4970997869968414e-02 + <_> + + 0 -1 2881 3.9351999759674072e-02 + + -1.8327899277210236e-01 4.6980699896812439e-01 + <_> + + 0 -1 2882 -7.0322997868061066e-02 + + -9.8322701454162598e-01 1.1808100342750549e-01 + <_> + + 0 -1 2883 3.5743001848459244e-02 + + -3.3050999045372009e-02 -8.3610898256301880e-01 + <_> + + 0 -1 2884 -4.2961999773979187e-02 + + 1.1670809984207153e+00 8.0692000687122345e-02 + <_> + + 0 -1 2885 -2.1007999777793884e-02 + + 6.3869798183441162e-01 -1.7626300454139709e-01 + <_> + + 0 -1 2886 -1.5742200613021851e-01 + + -2.3302499949932098e-01 1.2517499923706055e-01 + <_> + + 0 -1 2887 7.8659998252987862e-03 + + -2.2037999331951141e-01 2.7196800708770752e-01 + <_> + + 0 -1 2888 2.3622000589966774e-02 + + 1.6127300262451172e-01 -4.3329000473022461e-01 + <_> + + 0 -1 2889 7.4692003428936005e-02 + + -1.6991999745368958e-01 5.8884900808334351e-01 + <_> + + 0 -1 2890 -6.4799998654052615e-04 + + 2.5842899084091187e-01 -3.5911999642848969e-02 + <_> + + 0 -1 2891 -1.6290999948978424e-02 + + -7.6764398813247681e-01 -2.0472999662160873e-02 + <_> + + 0 -1 2892 -3.3133998513221741e-02 + + -2.7180099487304688e-01 1.4325700700283051e-01 + <_> + + 0 -1 2893 4.8797998577356339e-02 + + 7.6408997178077698e-02 -4.1445198655128479e-01 + <_> + + 0 -1 2894 2.2869999520480633e-03 + + -3.8628999143838882e-02 2.0753799378871918e-01 + <_> + + 0 -1 2895 4.5304000377655029e-02 + + -1.7777900397777557e-01 6.3461399078369141e-01 + <_> + + 0 -1 2896 1.0705800354480743e-01 + + 1.8972299993038177e-01 -5.1236200332641602e-01 + <_> + + 0 -1 2897 -4.0525000542402267e-02 + + 7.0614999532699585e-01 -1.7803299427032471e-01 + <_> + + 0 -1 2898 3.1968999654054642e-02 + + 6.8149998784065247e-02 6.8733102083206177e-01 + <_> + + 0 -1 2899 -5.7617001235485077e-02 + + 7.5170499086380005e-01 -1.5764999389648438e-01 + <_> + + 0 -1 2900 1.3593999668955803e-02 + + 1.9411900639533997e-01 -2.4561899900436401e-01 + <_> + + 0 -1 2901 7.1396000683307648e-02 + + -4.6881001442670822e-02 -8.8198298215866089e-01 + <_> + + 0 -1 2902 -1.4895999804139137e-02 + + -4.4532400369644165e-01 1.7679899930953979e-01 + <_> + + 0 -1 2903 -1.0026000440120697e-02 + + 6.5122699737548828e-01 -1.6709999740123749e-01 + <_> + + 0 -1 2904 3.7589999847114086e-03 + + -5.8301001787185669e-02 3.4483298659324646e-01 + <_> + + 0 -1 2905 1.6263000667095184e-02 + + -1.5581500530242920e-01 8.6432701349258423e-01 + <_> + + 0 -1 2906 -4.0176000446081161e-02 + + -6.1028599739074707e-01 1.1796399950981140e-01 + <_> + + 0 -1 2907 2.7080999687314034e-02 + + -4.9601998180150986e-02 -8.9990001916885376e-01 + <_> + + 0 -1 2908 5.2420001477003098e-02 + + 1.1297199875116348e-01 -1.0833640098571777e+00 + <_> + + 0 -1 2909 -1.9160000607371330e-02 + + -7.9880100488662720e-01 -3.4079000353813171e-02 + <_> + + 0 -1 2910 -3.7730000913143158e-03 + + -1.9124099612236023e-01 2.1535199880599976e-01 + <_> + + 0 -1 2911 7.5762003660202026e-02 + + -1.3421699404716492e-01 1.6807060241699219e+00 + <_> + + 0 -1 2912 -2.2173000499606133e-02 + + 4.8600998520851135e-01 3.6160000599920750e-03 + + <_> + + <_> + 6 4 12 9 -1. + <_> + 6 7 12 3 3. + <_> + + <_> + 6 4 12 7 -1. + <_> + 10 4 4 7 3. + <_> + + <_> + 3 9 18 9 -1. + <_> + 3 12 18 3 3. + <_> + + <_> + 8 18 9 6 -1. + <_> + 8 20 9 2 3. + <_> + + <_> + 3 5 4 19 -1. + <_> + 5 5 2 19 2. + <_> + + <_> + 6 5 12 16 -1. + <_> + 6 13 12 8 2. + <_> + + <_> + 5 8 12 6 -1. + <_> + 5 11 12 3 2. + <_> + + <_> + 11 14 4 10 -1. + <_> + 11 19 4 5 2. + <_> + + <_> + 4 0 7 6 -1. + <_> + 4 3 7 3 2. + <_> + + <_> + 6 6 12 6 -1. + <_> + 6 8 12 2 3. + <_> + + <_> + 6 4 12 7 -1. + <_> + 10 4 4 7 3. + <_> + + <_> + 1 8 19 12 -1. + <_> + 1 12 19 4 3. + <_> + + <_> + 0 2 24 3 -1. + <_> + 8 2 8 3 3. + <_> + + <_> + 9 9 6 15 -1. + <_> + 9 14 6 5 3. + <_> + + <_> + 5 6 14 10 -1. + <_> + 5 11 14 5 2. + <_> + + <_> + 5 0 14 9 -1. + <_> + 5 3 14 3 3. + <_> + + <_> + 13 11 9 6 -1. + <_> + 16 11 3 6 3. + <_> + + <_> + 7 5 6 10 -1. + <_> + 9 5 2 10 3. + <_> + + <_> + 10 8 6 10 -1. + <_> + 12 8 2 10 3. + <_> + + <_> + 2 5 4 9 -1. + <_> + 4 5 2 9 2. + <_> + + <_> + 18 0 6 11 -1. + <_> + 20 0 2 11 3. + <_> + + <_> + 0 6 24 13 -1. + <_> + 8 6 8 13 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 7 18 10 6 -1. + <_> + 7 20 10 2 3. + <_> + + <_> + 5 7 14 12 -1. + <_> + 5 13 14 6 2. + <_> + + <_> + 0 3 24 3 -1. + <_> + 8 3 8 3 3. + <_> + + <_> + 5 8 15 6 -1. + <_> + 5 11 15 3 2. + <_> + + <_> + 9 6 5 14 -1. + <_> + 9 13 5 7 2. + <_> + + <_> + 9 5 6 10 -1. + <_> + 11 5 2 10 3. + <_> + + <_> + 6 6 3 12 -1. + <_> + 6 12 3 6 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 5 6 13 6 -1. + <_> + 5 8 13 2 3. + <_> + + <_> + 18 1 6 15 -1. + <_> + 18 1 3 15 2. + <_> + + <_> + 1 1 6 15 -1. + <_> + 4 1 3 15 2. + <_> + + <_> + 0 8 24 15 -1. + <_> + 8 8 8 15 3. + <_> + + <_> + 5 6 14 12 -1. + <_> + 5 6 7 6 2. + <_> + 12 12 7 6 2. + <_> + + <_> + 2 12 21 12 -1. + <_> + 2 16 21 4 3. + <_> + + <_> + 8 1 4 10 -1. + <_> + 10 1 2 10 2. + <_> + + <_> + 2 13 20 10 -1. + <_> + 2 13 10 10 2. + <_> + + <_> + 0 1 6 13 -1. + <_> + 2 1 2 13 3. + <_> + + <_> + 20 2 4 13 -1. + <_> + 20 2 2 13 2. + <_> + + <_> + 0 5 22 19 -1. + <_> + 11 5 11 19 2. + <_> + + <_> + 18 4 6 9 -1. + <_> + 20 4 2 9 3. + <_> + + <_> + 0 3 6 11 -1. + <_> + 2 3 2 11 3. + <_> + + <_> + 12 1 4 9 -1. + <_> + 12 1 2 9 2. + <_> + + <_> + 0 6 19 3 -1. + <_> + 0 7 19 1 3. + <_> + + <_> + 12 1 4 9 -1. + <_> + 12 1 2 9 2. + <_> + + <_> + 8 1 4 9 -1. + <_> + 10 1 2 9 2. + <_> + + <_> + 5 5 14 14 -1. + <_> + 12 5 7 7 2. + <_> + 5 12 7 7 2. + <_> + + <_> + 1 10 18 2 -1. + <_> + 1 11 18 1 2. + <_> + + <_> + 17 13 4 11 -1. + <_> + 17 13 2 11 2. + <_> + + <_> + 0 4 6 9 -1. + <_> + 0 7 6 3 3. + <_> + + <_> + 6 4 12 9 -1. + <_> + 6 7 12 3 3. + <_> + + <_> + 6 5 12 6 -1. + <_> + 10 5 4 6 3. + <_> + + <_> + 0 1 24 5 -1. + <_> + 8 1 8 5 3. + <_> + + <_> + 4 10 18 6 -1. + <_> + 4 12 18 2 3. + <_> + + <_> + 2 17 12 6 -1. + <_> + 2 17 6 3 2. + <_> + 8 20 6 3 2. + <_> + + <_> + 19 3 4 13 -1. + <_> + 19 3 2 13 2. + <_> + + <_> + 1 3 4 13 -1. + <_> + 3 3 2 13 2. + <_> + + <_> + 0 1 24 23 -1. + <_> + 8 1 8 23 3. + <_> + + <_> + 1 7 8 12 -1. + <_> + 1 11 8 4 3. + <_> + + <_> + 14 7 3 14 -1. + <_> + 14 14 3 7 2. + <_> + + <_> + 3 12 16 6 -1. + <_> + 3 12 8 3 2. + <_> + 11 15 8 3 2. + <_> + + <_> + 6 6 12 6 -1. + <_> + 6 8 12 2 3. + <_> + + <_> + 8 7 6 12 -1. + <_> + 8 13 6 6 2. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 1 17 18 3 -1. + <_> + 1 18 18 1 3. + <_> + + <_> + 4 4 16 12 -1. + <_> + 4 10 16 6 2. + <_> + + <_> + 0 1 4 20 -1. + <_> + 2 1 2 20 2. + <_> + + <_> + 3 0 18 2 -1. + <_> + 3 1 18 1 2. + <_> + + <_> + 1 5 20 14 -1. + <_> + 1 5 10 7 2. + <_> + 11 12 10 7 2. + <_> + + <_> + 5 8 14 12 -1. + <_> + 5 12 14 4 3. + <_> + + <_> + 3 14 7 9 -1. + <_> + 3 17 7 3 3. + <_> + + <_> + 14 15 9 6 -1. + <_> + 14 17 9 2 3. + <_> + + <_> + 1 15 9 6 -1. + <_> + 1 17 9 2 3. + <_> + + <_> + 11 6 8 10 -1. + <_> + 15 6 4 5 2. + <_> + 11 11 4 5 2. + <_> + + <_> + 5 5 14 14 -1. + <_> + 5 5 7 7 2. + <_> + 12 12 7 7 2. + <_> + + <_> + 6 0 12 5 -1. + <_> + 10 0 4 5 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 9 3 6 3 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 3 8 18 4 -1. + <_> + 9 8 6 4 3. + <_> + + <_> + 6 0 12 9 -1. + <_> + 6 3 12 3 3. + <_> + + <_> + 0 0 24 6 -1. + <_> + 8 0 8 6 3. + <_> + + <_> + 4 7 16 12 -1. + <_> + 4 11 16 4 3. + <_> + + <_> + 11 6 6 6 -1. + <_> + 11 6 3 6 2. + <_> + + <_> + 0 20 24 3 -1. + <_> + 8 20 8 3 3. + <_> + + <_> + 11 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 4 13 15 4 -1. + <_> + 9 13 5 4 3. + <_> + + <_> + 11 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 9 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 18 6 6 2. + <_> + + <_> + 1 22 18 2 -1. + <_> + 1 23 18 1 2. + <_> + + <_> + 10 7 4 10 -1. + <_> + 10 12 4 5 2. + <_> + + <_> + 6 7 8 10 -1. + <_> + 6 12 8 5 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 0 14 10 4 -1. + <_> + 0 16 10 2 2. + <_> + + <_> + 6 18 18 2 -1. + <_> + 6 19 18 1 2. + <_> + + <_> + 1 1 22 3 -1. + <_> + 1 2 22 1 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 2 4 6 15 -1. + <_> + 5 4 3 15 2. + <_> + + <_> + 20 4 4 10 -1. + <_> + 20 4 2 10 2. + <_> + + <_> + 0 4 4 10 -1. + <_> + 2 4 2 10 2. + <_> + + <_> + 2 16 20 6 -1. + <_> + 12 16 10 3 2. + <_> + 2 19 10 3 2. + <_> + + <_> + 0 12 8 9 -1. + <_> + 4 12 4 9 2. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 5 10 6 6 -1. + <_> + 8 10 3 6 2. + <_> + + <_> + 11 8 12 6 -1. + <_> + 17 8 6 3 2. + <_> + 11 11 6 3 2. + <_> + + <_> + 0 8 12 6 -1. + <_> + 0 8 6 3 2. + <_> + 6 11 6 3 2. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 8 14 9 6 -1. + <_> + 8 16 9 2 3. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 10 8 6 10 -1. + <_> + 12 8 2 10 3. + <_> + + <_> + 3 19 12 3 -1. + <_> + 9 19 6 3 2. + <_> + + <_> + 2 10 20 2 -1. + <_> + 2 11 20 1 2. + <_> + + <_> + 2 9 18 12 -1. + <_> + 2 9 9 6 2. + <_> + 11 15 9 6 2. + <_> + + <_> + 3 0 18 24 -1. + <_> + 3 0 9 24 2. + <_> + + <_> + 5 6 14 10 -1. + <_> + 5 6 7 5 2. + <_> + 12 11 7 5 2. + <_> + + <_> + 9 5 10 12 -1. + <_> + 14 5 5 6 2. + <_> + 9 11 5 6 2. + <_> + + <_> + 4 5 12 12 -1. + <_> + 4 5 6 6 2. + <_> + 10 11 6 6 2. + <_> + + <_> + 4 14 18 3 -1. + <_> + 4 15 18 1 3. + <_> + + <_> + 6 13 8 8 -1. + <_> + 6 17 8 4 2. + <_> + + <_> + 3 16 18 6 -1. + <_> + 3 19 18 3 2. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 6 6 12 18 -1. + <_> + 10 6 4 18 3. + <_> + + <_> + 6 1 4 14 -1. + <_> + 8 1 2 14 2. + <_> + + <_> + 3 2 19 2 -1. + <_> + 3 3 19 1 2. + <_> + + <_> + 1 8 22 13 -1. + <_> + 12 8 11 13 2. + <_> + + <_> + 8 9 11 4 -1. + <_> + 8 11 11 2 2. + <_> + + <_> + 0 12 15 10 -1. + <_> + 5 12 5 10 3. + <_> + + <_> + 12 16 12 6 -1. + <_> + 16 16 4 6 3. + <_> + + <_> + 0 16 12 6 -1. + <_> + 4 16 4 6 3. + <_> + + <_> + 19 1 5 12 -1. + <_> + 19 5 5 4 3. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 6 8 12 4 -1. + <_> + 6 10 12 2 2. + <_> + + <_> + 7 5 9 6 -1. + <_> + 10 5 3 6 3. + <_> + + <_> + 9 17 6 6 -1. + <_> + 9 20 6 3 2. + <_> + + <_> + 0 7 22 15 -1. + <_> + 0 12 22 5 3. + <_> + + <_> + 4 1 17 9 -1. + <_> + 4 4 17 3 3. + <_> + + <_> + 7 5 6 10 -1. + <_> + 9 5 2 10 3. + <_> + + <_> + 18 1 6 8 -1. + <_> + 18 1 3 8 2. + <_> + + <_> + 0 1 6 7 -1. + <_> + 3 1 3 7 2. + <_> + + <_> + 18 0 6 22 -1. + <_> + 18 0 3 22 2. + <_> + + <_> + 0 0 6 22 -1. + <_> + 3 0 3 22 2. + <_> + + <_> + 16 7 8 16 -1. + <_> + 16 7 4 16 2. + <_> + + <_> + 2 10 19 6 -1. + <_> + 2 12 19 2 3. + <_> + + <_> + 9 9 6 12 -1. + <_> + 9 13 6 4 3. + <_> + + <_> + 2 15 17 6 -1. + <_> + 2 17 17 2 3. + <_> + + <_> + 14 7 3 14 -1. + <_> + 14 14 3 7 2. + <_> + + <_> + 5 6 8 10 -1. + <_> + 5 6 4 5 2. + <_> + 9 11 4 5 2. + <_> + + <_> + 15 8 9 11 -1. + <_> + 18 8 3 11 3. + <_> + + <_> + 0 8 9 11 -1. + <_> + 3 8 3 11 3. + <_> + + <_> + 8 6 10 18 -1. + <_> + 8 15 10 9 2. + <_> + + <_> + 7 7 3 14 -1. + <_> + 7 14 3 7 2. + <_> + + <_> + 0 14 24 8 -1. + <_> + 8 14 8 8 3. + <_> + + <_> + 1 10 18 14 -1. + <_> + 10 10 9 14 2. + <_> + + <_> + 14 12 6 6 -1. + <_> + 14 15 6 3 2. + <_> + + <_> + 7 0 10 16 -1. + <_> + 7 0 5 8 2. + <_> + 12 8 5 8 2. + <_> + + <_> + 10 0 9 6 -1. + <_> + 13 0 3 6 3. + <_> + + <_> + 4 3 16 4 -1. + <_> + 12 3 8 4 2. + <_> + + <_> + 10 0 9 6 -1. + <_> + 13 0 3 6 3. + <_> + + <_> + 1 1 20 4 -1. + <_> + 1 1 10 2 2. + <_> + 11 3 10 2 2. + <_> + + <_> + 10 0 9 6 -1. + <_> + 13 0 3 6 3. + <_> + + <_> + 5 0 9 6 -1. + <_> + 8 0 3 6 3. + <_> + + <_> + 8 18 10 6 -1. + <_> + 8 20 10 2 3. + <_> + + <_> + 6 3 6 9 -1. + <_> + 8 3 2 9 3. + <_> + + <_> + 7 3 12 6 -1. + <_> + 7 5 12 2 3. + <_> + + <_> + 0 10 18 3 -1. + <_> + 0 11 18 1 3. + <_> + + <_> + 1 10 22 3 -1. + <_> + 1 11 22 1 3. + <_> + + <_> + 5 11 8 8 -1. + <_> + 9 11 4 8 2. + <_> + + <_> + 12 11 6 6 -1. + <_> + 12 11 3 6 2. + <_> + + <_> + 6 11 6 6 -1. + <_> + 9 11 3 6 2. + <_> + + <_> + 7 10 11 6 -1. + <_> + 7 12 11 2 3. + <_> + + <_> + 0 13 24 4 -1. + <_> + 0 13 12 2 2. + <_> + 12 15 12 2 2. + <_> + + <_> + 2 4 22 12 -1. + <_> + 13 4 11 6 2. + <_> + 2 10 11 6 2. + <_> + + <_> + 2 0 20 17 -1. + <_> + 12 0 10 17 2. + <_> + + <_> + 14 0 2 24 -1. + <_> + 14 0 1 24 2. + <_> + + <_> + 8 0 2 24 -1. + <_> + 9 0 1 24 2. + <_> + + <_> + 14 1 2 22 -1. + <_> + 14 1 1 22 2. + <_> + + <_> + 8 1 2 22 -1. + <_> + 9 1 1 22 2. + <_> + + <_> + 17 6 3 18 -1. + <_> + 18 6 1 18 3. + <_> + + <_> + 6 14 9 6 -1. + <_> + 6 16 9 2 3. + <_> + + <_> + 13 14 9 4 -1. + <_> + 13 16 9 2 2. + <_> + + <_> + 3 18 18 3 -1. + <_> + 3 19 18 1 3. + <_> + + <_> + 9 4 8 18 -1. + <_> + 13 4 4 9 2. + <_> + 9 13 4 9 2. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 0 2 12 4 -1. + <_> + 6 2 6 4 2. + <_> + + <_> + 6 8 14 6 -1. + <_> + 6 11 14 3 2. + <_> + + <_> + 7 5 6 6 -1. + <_> + 10 5 3 6 2. + <_> + + <_> + 10 5 6 16 -1. + <_> + 10 13 6 8 2. + <_> + + <_> + 1 4 9 16 -1. + <_> + 4 4 3 16 3. + <_> + + <_> + 5 0 18 9 -1. + <_> + 5 3 18 3 3. + <_> + + <_> + 9 15 5 8 -1. + <_> + 9 19 5 4 2. + <_> + + <_> + 20 0 4 9 -1. + <_> + 20 0 2 9 2. + <_> + + <_> + 2 0 18 3 -1. + <_> + 2 1 18 1 3. + <_> + + <_> + 5 22 19 2 -1. + <_> + 5 23 19 1 2. + <_> + + <_> + 0 0 4 9 -1. + <_> + 2 0 2 9 2. + <_> + + <_> + 5 6 19 18 -1. + <_> + 5 12 19 6 3. + <_> + + <_> + 0 1 6 9 -1. + <_> + 2 1 2 9 3. + <_> + + <_> + 6 5 14 12 -1. + <_> + 13 5 7 6 2. + <_> + 6 11 7 6 2. + <_> + + <_> + 0 1 20 2 -1. + <_> + 0 2 20 1 2. + <_> + + <_> + 1 2 22 3 -1. + <_> + 1 3 22 1 3. + <_> + + <_> + 2 8 7 9 -1. + <_> + 2 11 7 3 3. + <_> + + <_> + 2 12 22 4 -1. + <_> + 13 12 11 2 2. + <_> + 2 14 11 2 2. + <_> + + <_> + 0 12 22 4 -1. + <_> + 0 12 11 2 2. + <_> + 11 14 11 2 2. + <_> + + <_> + 9 7 6 11 -1. + <_> + 11 7 2 11 3. + <_> + + <_> + 7 1 9 6 -1. + <_> + 10 1 3 6 3. + <_> + + <_> + 11 2 4 10 -1. + <_> + 11 7 4 5 2. + <_> + + <_> + 6 4 12 12 -1. + <_> + 6 10 12 6 2. + <_> + + <_> + 18 1 6 15 -1. + <_> + 18 6 6 5 3. + <_> + + <_> + 3 15 18 3 -1. + <_> + 3 16 18 1 3. + <_> + + <_> + 18 5 6 9 -1. + <_> + 18 8 6 3 3. + <_> + + <_> + 1 5 16 6 -1. + <_> + 1 5 8 3 2. + <_> + 9 8 8 3 2. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 0 4 24 14 -1. + <_> + 0 4 12 7 2. + <_> + 12 11 12 7 2. + <_> + + <_> + 13 0 4 13 -1. + <_> + 13 0 2 13 2. + <_> + + <_> + 7 0 4 13 -1. + <_> + 9 0 2 13 2. + <_> + + <_> + 11 6 6 9 -1. + <_> + 13 6 2 9 3. + <_> + + <_> + 8 7 6 9 -1. + <_> + 10 7 2 9 3. + <_> + + <_> + 13 17 9 6 -1. + <_> + 13 19 9 2 3. + <_> + + <_> + 2 18 14 6 -1. + <_> + 2 18 7 3 2. + <_> + 9 21 7 3 2. + <_> + + <_> + 3 18 18 4 -1. + <_> + 12 18 9 2 2. + <_> + 3 20 9 2 2. + <_> + + <_> + 0 20 15 4 -1. + <_> + 5 20 5 4 3. + <_> + + <_> + 9 15 15 9 -1. + <_> + 14 15 5 9 3. + <_> + + <_> + 4 4 16 4 -1. + <_> + 4 6 16 2 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 0 14 15 10 -1. + <_> + 5 14 5 10 3. + <_> + + <_> + 7 9 10 14 -1. + <_> + 12 9 5 7 2. + <_> + 7 16 5 7 2. + <_> + + <_> + 7 6 6 9 -1. + <_> + 9 6 2 9 3. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 0 10 18 3 -1. + <_> + 0 11 18 1 3. + <_> + + <_> + 3 16 18 4 -1. + <_> + 12 16 9 2 2. + <_> + 3 18 9 2 2. + <_> + + <_> + 4 6 14 6 -1. + <_> + 4 6 7 3 2. + <_> + 11 9 7 3 2. + <_> + + <_> + 13 0 2 18 -1. + <_> + 13 0 1 18 2. + <_> + + <_> + 9 0 2 18 -1. + <_> + 10 0 1 18 2. + <_> + + <_> + 5 7 15 10 -1. + <_> + 10 7 5 10 3. + <_> + + <_> + 1 20 21 4 -1. + <_> + 8 20 7 4 3. + <_> + + <_> + 10 5 5 18 -1. + <_> + 10 14 5 9 2. + <_> + + <_> + 0 2 24 6 -1. + <_> + 0 2 12 3 2. + <_> + 12 5 12 3 2. + <_> + + <_> + 1 1 22 8 -1. + <_> + 12 1 11 4 2. + <_> + 1 5 11 4 2. + <_> + + <_> + 4 0 15 9 -1. + <_> + 4 3 15 3 3. + <_> + + <_> + 0 0 24 19 -1. + <_> + 8 0 8 19 3. + <_> + + <_> + 2 21 18 3 -1. + <_> + 11 21 9 3 2. + <_> + + <_> + 9 7 10 4 -1. + <_> + 9 7 5 4 2. + <_> + + <_> + 5 7 10 4 -1. + <_> + 10 7 5 4 2. + <_> + + <_> + 17 8 6 16 -1. + <_> + 20 8 3 8 2. + <_> + 17 16 3 8 2. + <_> + + <_> + 1 15 20 4 -1. + <_> + 1 15 10 2 2. + <_> + 11 17 10 2 2. + <_> + + <_> + 14 15 10 6 -1. + <_> + 14 17 10 2 3. + <_> + + <_> + 3 0 16 9 -1. + <_> + 3 3 16 3 3. + <_> + + <_> + 15 6 7 15 -1. + <_> + 15 11 7 5 3. + <_> + + <_> + 9 1 6 13 -1. + <_> + 11 1 2 13 3. + <_> + + <_> + 17 2 6 14 -1. + <_> + 17 2 3 14 2. + <_> + + <_> + 3 14 12 10 -1. + <_> + 3 14 6 5 2. + <_> + 9 19 6 5 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 1 2 6 14 -1. + <_> + 4 2 3 14 2. + <_> + + <_> + 10 4 5 12 -1. + <_> + 10 8 5 4 3. + <_> + + <_> + 0 17 24 5 -1. + <_> + 8 17 8 5 3. + <_> + + <_> + 15 7 5 12 -1. + <_> + 15 11 5 4 3. + <_> + + <_> + 3 1 6 12 -1. + <_> + 3 1 3 6 2. + <_> + 6 7 3 6 2. + <_> + + <_> + 12 13 6 6 -1. + <_> + 12 16 6 3 2. + <_> + + <_> + 6 13 6 6 -1. + <_> + 6 16 6 3 2. + <_> + + <_> + 14 6 3 16 -1. + <_> + 14 14 3 8 2. + <_> + + <_> + 1 12 13 6 -1. + <_> + 1 14 13 2 3. + <_> + + <_> + 13 1 4 9 -1. + <_> + 13 1 2 9 2. + <_> + + <_> + 7 0 9 6 -1. + <_> + 10 0 3 6 3. + <_> + + <_> + 12 2 6 9 -1. + <_> + 12 2 3 9 2. + <_> + + <_> + 6 2 6 9 -1. + <_> + 9 2 3 9 2. + <_> + + <_> + 6 18 12 6 -1. + <_> + 6 20 12 2 3. + <_> + + <_> + 7 6 6 9 -1. + <_> + 9 6 2 9 3. + <_> + + <_> + 7 7 12 3 -1. + <_> + 7 7 6 3 2. + <_> + + <_> + 8 3 8 21 -1. + <_> + 8 10 8 7 3. + <_> + + <_> + 7 4 10 12 -1. + <_> + 7 8 10 4 3. + <_> + + <_> + 0 1 6 9 -1. + <_> + 0 4 6 3 3. + <_> + + <_> + 15 2 2 20 -1. + <_> + 15 2 1 20 2. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 15 3 2 21 -1. + <_> + 15 3 1 21 2. + <_> + + <_> + 7 0 2 23 -1. + <_> + 8 0 1 23 2. + <_> + + <_> + 15 8 9 4 -1. + <_> + 15 10 9 2 2. + <_> + + <_> + 0 8 9 4 -1. + <_> + 0 10 9 2 2. + <_> + + <_> + 8 14 9 6 -1. + <_> + 8 16 9 2 3. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 3 10 18 4 -1. + <_> + 9 10 6 4 3. + <_> + + <_> + 0 0 24 19 -1. + <_> + 8 0 8 19 3. + <_> + + <_> + 9 1 8 12 -1. + <_> + 9 7 8 6 2. + <_> + + <_> + 10 6 4 10 -1. + <_> + 12 6 2 10 2. + <_> + + <_> + 7 9 10 12 -1. + <_> + 12 9 5 6 2. + <_> + 7 15 5 6 2. + <_> + + <_> + 5 0 3 19 -1. + <_> + 6 0 1 19 3. + <_> + + <_> + 14 0 6 10 -1. + <_> + 16 0 2 10 3. + <_> + + <_> + 2 0 6 12 -1. + <_> + 2 0 3 6 2. + <_> + 5 6 3 6 2. + <_> + + <_> + 0 11 24 2 -1. + <_> + 0 12 24 1 2. + <_> + + <_> + 4 9 13 4 -1. + <_> + 4 11 13 2 2. + <_> + + <_> + 9 8 6 9 -1. + <_> + 9 11 6 3 3. + <_> + + <_> + 0 12 16 4 -1. + <_> + 0 14 16 2 2. + <_> + + <_> + 18 12 6 9 -1. + <_> + 18 15 6 3 3. + <_> + + <_> + 0 12 6 9 -1. + <_> + 0 15 6 3 3. + <_> + + <_> + 8 7 10 4 -1. + <_> + 8 7 5 4 2. + <_> + + <_> + 8 7 6 9 -1. + <_> + 10 7 2 9 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 12 3 6 15 -1. + <_> + 14 3 2 15 3. + <_> + + <_> + 6 3 6 15 -1. + <_> + 8 3 2 15 3. + <_> + + <_> + 15 2 9 4 -1. + <_> + 15 4 9 2 2. + <_> + + <_> + 5 10 6 7 -1. + <_> + 8 10 3 7 2. + <_> + + <_> + 9 14 6 10 -1. + <_> + 9 19 6 5 2. + <_> + + <_> + 7 13 5 8 -1. + <_> + 7 17 5 4 2. + <_> + + <_> + 14 5 3 16 -1. + <_> + 14 13 3 8 2. + <_> + + <_> + 2 17 18 3 -1. + <_> + 2 18 18 1 3. + <_> + + <_> + 5 18 19 3 -1. + <_> + 5 19 19 1 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 12 4 3 18 -1. + <_> + 13 4 1 18 3. + <_> + + <_> + 9 4 3 18 -1. + <_> + 10 4 1 18 3. + <_> + + <_> + 3 3 18 9 -1. + <_> + 9 3 6 9 3. + <_> + + <_> + 6 1 6 14 -1. + <_> + 8 1 2 14 3. + <_> + + <_> + 12 16 9 6 -1. + <_> + 12 19 9 3 2. + <_> + + <_> + 1 3 20 16 -1. + <_> + 1 3 10 8 2. + <_> + 11 11 10 8 2. + <_> + + <_> + 12 5 6 12 -1. + <_> + 15 5 3 6 2. + <_> + 12 11 3 6 2. + <_> + + <_> + 1 2 22 16 -1. + <_> + 1 2 11 8 2. + <_> + 12 10 11 8 2. + <_> + + <_> + 10 14 5 10 -1. + <_> + 10 19 5 5 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 3 22 18 1 3. + <_> + + <_> + 10 14 6 10 -1. + <_> + 12 14 2 10 3. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 6 4 12 9 -1. + <_> + 6 7 12 3 3. + <_> + + <_> + 6 6 12 5 -1. + <_> + 10 6 4 5 3. + <_> + + <_> + 5 8 14 12 -1. + <_> + 5 12 14 4 3. + <_> + + <_> + 4 14 8 10 -1. + <_> + 4 14 4 5 2. + <_> + 8 19 4 5 2. + <_> + + <_> + 11 6 5 14 -1. + <_> + 11 13 5 7 2. + <_> + + <_> + 7 6 3 16 -1. + <_> + 7 14 3 8 2. + <_> + + <_> + 3 7 18 8 -1. + <_> + 9 7 6 8 3. + <_> + + <_> + 2 3 20 2 -1. + <_> + 2 4 20 1 2. + <_> + + <_> + 3 12 19 6 -1. + <_> + 3 14 19 2 3. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 16 6 6 14 -1. + <_> + 16 6 3 14 2. + <_> + + <_> + 7 9 6 12 -1. + <_> + 9 9 2 12 3. + <_> + + <_> + 18 6 6 18 -1. + <_> + 21 6 3 9 2. + <_> + 18 15 3 9 2. + <_> + + <_> + 0 6 6 18 -1. + <_> + 0 6 3 9 2. + <_> + 3 15 3 9 2. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 3 18 15 6 -1. + <_> + 3 20 15 2 3. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 0 5 6 3 3. + <_> + + <_> + 5 10 18 2 -1. + <_> + 5 11 18 1 2. + <_> + + <_> + 6 0 12 6 -1. + <_> + 6 2 12 2 3. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 8 0 6 9 -1. + <_> + 10 0 2 9 3. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 3 6 13 6 -1. + <_> + 3 8 13 2 3. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 2 5 6 15 -1. + <_> + 5 5 3 15 2. + <_> + + <_> + 8 8 9 6 -1. + <_> + 11 8 3 6 3. + <_> + + <_> + 8 6 3 14 -1. + <_> + 8 13 3 7 2. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 4 12 10 4 -1. + <_> + 9 12 5 4 2. + <_> + + <_> + 13 1 4 19 -1. + <_> + 13 1 2 19 2. + <_> + + <_> + 7 1 4 19 -1. + <_> + 9 1 2 19 2. + <_> + + <_> + 18 9 6 9 -1. + <_> + 18 12 6 3 3. + <_> + + <_> + 1 21 18 3 -1. + <_> + 1 22 18 1 3. + <_> + + <_> + 14 13 10 9 -1. + <_> + 14 16 10 3 3. + <_> + + <_> + 1 13 22 4 -1. + <_> + 1 13 11 2 2. + <_> + 12 15 11 2 2. + <_> + + <_> + 4 6 16 6 -1. + <_> + 12 6 8 3 2. + <_> + 4 9 8 3 2. + <_> + + <_> + 1 0 18 22 -1. + <_> + 1 0 9 11 2. + <_> + 10 11 9 11 2. + <_> + + <_> + 10 7 8 14 -1. + <_> + 14 7 4 7 2. + <_> + 10 14 4 7 2. + <_> + + <_> + 0 4 6 20 -1. + <_> + 0 4 3 10 2. + <_> + 3 14 3 10 2. + <_> + + <_> + 15 0 6 9 -1. + <_> + 17 0 2 9 3. + <_> + + <_> + 3 0 6 9 -1. + <_> + 5 0 2 9 3. + <_> + + <_> + 15 12 6 12 -1. + <_> + 18 12 3 6 2. + <_> + 15 18 3 6 2. + <_> + + <_> + 3 12 6 12 -1. + <_> + 3 12 3 6 2. + <_> + 6 18 3 6 2. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 0 12 9 6 -1. + <_> + 0 14 9 2 3. + <_> + + <_> + 4 14 19 3 -1. + <_> + 4 15 19 1 3. + <_> + + <_> + 2 13 19 3 -1. + <_> + 2 14 19 1 3. + <_> + + <_> + 14 15 10 6 -1. + <_> + 14 17 10 2 3. + <_> + + <_> + 6 0 10 12 -1. + <_> + 6 0 5 6 2. + <_> + 11 6 5 6 2. + <_> + + <_> + 17 1 6 12 -1. + <_> + 20 1 3 6 2. + <_> + 17 7 3 6 2. + <_> + + <_> + 1 1 6 12 -1. + <_> + 1 1 3 6 2. + <_> + 4 7 3 6 2. + <_> + + <_> + 16 14 6 9 -1. + <_> + 16 17 6 3 3. + <_> + + <_> + 7 3 9 12 -1. + <_> + 7 9 9 6 2. + <_> + + <_> + 12 1 4 12 -1. + <_> + 12 7 4 6 2. + <_> + + <_> + 4 0 14 8 -1. + <_> + 4 4 14 4 2. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 2 10 18 3 -1. + <_> + 8 10 6 3 3. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 1 21 23 -1. + <_> + 7 1 7 23 3. + <_> + + <_> + 6 9 17 4 -1. + <_> + 6 11 17 2 2. + <_> + + <_> + 1 0 11 18 -1. + <_> + 1 6 11 6 3. + <_> + + <_> + 6 15 13 6 -1. + <_> + 6 17 13 2 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 8 7 15 4 -1. + <_> + 13 7 5 4 3. + <_> + + <_> + 9 12 6 9 -1. + <_> + 9 15 6 3 3. + <_> + + <_> + 6 8 18 3 -1. + <_> + 12 8 6 3 3. + <_> + + <_> + 0 14 24 4 -1. + <_> + 8 14 8 4 3. + <_> + + <_> + 16 10 3 12 -1. + <_> + 16 16 3 6 2. + <_> + + <_> + 0 3 24 3 -1. + <_> + 0 4 24 1 3. + <_> + + <_> + 14 17 10 6 -1. + <_> + 14 19 10 2 3. + <_> + + <_> + 1 13 18 3 -1. + <_> + 7 13 6 3 3. + <_> + + <_> + 5 0 18 9 -1. + <_> + 5 3 18 3 3. + <_> + + <_> + 4 3 16 9 -1. + <_> + 4 6 16 3 3. + <_> + + <_> + 16 5 3 12 -1. + <_> + 16 11 3 6 2. + <_> + + <_> + 0 7 18 4 -1. + <_> + 6 7 6 4 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 9 8 6 10 -1. + <_> + 11 8 2 10 3. + <_> + + <_> + 9 15 6 9 -1. + <_> + 11 15 2 9 3. + <_> + + <_> + 3 1 18 21 -1. + <_> + 12 1 9 21 2. + <_> + + <_> + 6 8 12 7 -1. + <_> + 6 8 6 7 2. + <_> + + <_> + 8 5 6 9 -1. + <_> + 10 5 2 9 3. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 14 7 5 12 -1. + <_> + 14 11 5 4 3. + <_> + + <_> + 5 7 5 12 -1. + <_> + 5 11 5 4 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 0 1 6 17 -1. + <_> + 3 1 3 17 2. + <_> + + <_> + 3 1 19 9 -1. + <_> + 3 4 19 3 3. + <_> + + <_> + 3 18 12 6 -1. + <_> + 3 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 20 4 4 19 -1. + <_> + 20 4 2 19 2. + <_> + + <_> + 0 16 10 7 -1. + <_> + 5 16 5 7 2. + <_> + + <_> + 8 7 10 12 -1. + <_> + 13 7 5 6 2. + <_> + 8 13 5 6 2. + <_> + + <_> + 6 7 10 12 -1. + <_> + 6 7 5 6 2. + <_> + 11 13 5 6 2. + <_> + + <_> + 9 2 9 6 -1. + <_> + 12 2 3 6 3. + <_> + + <_> + 1 20 21 4 -1. + <_> + 8 20 7 4 3. + <_> + + <_> + 9 12 9 6 -1. + <_> + 9 14 9 2 3. + <_> + + <_> + 7 2 9 6 -1. + <_> + 10 2 3 6 3. + <_> + + <_> + 13 0 4 14 -1. + <_> + 13 0 2 14 2. + <_> + + <_> + 7 0 4 14 -1. + <_> + 9 0 2 14 2. + <_> + + <_> + 14 15 9 6 -1. + <_> + 14 17 9 2 3. + <_> + + <_> + 2 8 18 5 -1. + <_> + 8 8 6 5 3. + <_> + + <_> + 18 3 6 11 -1. + <_> + 20 3 2 11 3. + <_> + + <_> + 6 5 11 14 -1. + <_> + 6 12 11 7 2. + <_> + + <_> + 18 4 6 9 -1. + <_> + 18 7 6 3 3. + <_> + + <_> + 7 6 9 6 -1. + <_> + 7 8 9 2 3. + <_> + + <_> + 18 4 6 9 -1. + <_> + 18 7 6 3 3. + <_> + + <_> + 0 4 6 9 -1. + <_> + 0 7 6 3 3. + <_> + + <_> + 9 4 9 4 -1. + <_> + 9 6 9 2 2. + <_> + + <_> + 0 22 19 2 -1. + <_> + 0 23 19 1 2. + <_> + + <_> + 17 14 6 9 -1. + <_> + 17 17 6 3 3. + <_> + + <_> + 1 14 6 9 -1. + <_> + 1 17 6 3 3. + <_> + + <_> + 14 11 4 9 -1. + <_> + 14 11 2 9 2. + <_> + + <_> + 6 11 4 9 -1. + <_> + 8 11 2 9 2. + <_> + + <_> + 3 9 18 7 -1. + <_> + 9 9 6 7 3. + <_> + + <_> + 9 12 6 10 -1. + <_> + 9 17 6 5 2. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 6 17 18 3 -1. + <_> + 6 18 18 1 3. + <_> + + <_> + 1 17 18 3 -1. + <_> + 1 18 18 1 3. + <_> + + <_> + 10 6 11 12 -1. + <_> + 10 12 11 6 2. + <_> + + <_> + 5 6 14 6 -1. + <_> + 5 6 7 3 2. + <_> + 12 9 7 3 2. + <_> + + <_> + 5 4 15 4 -1. + <_> + 5 6 15 2 2. + <_> + + <_> + 0 0 22 2 -1. + <_> + 0 1 22 1 2. + <_> + + <_> + 0 0 24 24 -1. + <_> + 8 0 8 24 3. + <_> + + <_> + 1 15 18 4 -1. + <_> + 10 15 9 4 2. + <_> + + <_> + 6 8 12 9 -1. + <_> + 6 11 12 3 3. + <_> + + <_> + 4 12 7 12 -1. + <_> + 4 16 7 4 3. + <_> + + <_> + 1 2 22 6 -1. + <_> + 12 2 11 3 2. + <_> + 1 5 11 3 2. + <_> + + <_> + 5 20 14 3 -1. + <_> + 12 20 7 3 2. + <_> + + <_> + 0 0 24 16 -1. + <_> + 12 0 12 8 2. + <_> + 0 8 12 8 2. + <_> + + <_> + 3 13 18 4 -1. + <_> + 3 13 9 2 2. + <_> + 12 15 9 2 2. + <_> + + <_> + 2 10 22 2 -1. + <_> + 2 11 22 1 2. + <_> + + <_> + 6 3 11 8 -1. + <_> + 6 7 11 4 2. + <_> + + <_> + 14 5 6 6 -1. + <_> + 14 8 6 3 2. + <_> + + <_> + 0 7 24 6 -1. + <_> + 0 9 24 2 3. + <_> + + <_> + 14 0 10 10 -1. + <_> + 19 0 5 5 2. + <_> + 14 5 5 5 2. + <_> + + <_> + 0 0 10 10 -1. + <_> + 0 0 5 5 2. + <_> + 5 5 5 5 2. + <_> + + <_> + 0 1 24 4 -1. + <_> + 12 1 12 2 2. + <_> + 0 3 12 2 2. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 5 15 16 6 -1. + <_> + 13 15 8 3 2. + <_> + 5 18 8 3 2. + <_> + + <_> + 3 15 16 6 -1. + <_> + 3 15 8 3 2. + <_> + 11 18 8 3 2. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 0 13 21 10 -1. + <_> + 0 18 21 5 2. + <_> + + <_> + 13 0 6 24 -1. + <_> + 15 0 2 24 3. + <_> + + <_> + 7 4 6 11 -1. + <_> + 9 4 2 11 3. + <_> + + <_> + 9 5 9 6 -1. + <_> + 12 5 3 6 3. + <_> + + <_> + 1 4 2 20 -1. + <_> + 1 14 2 10 2. + <_> + + <_> + 13 0 6 24 -1. + <_> + 15 0 2 24 3. + <_> + + <_> + 5 0 6 24 -1. + <_> + 7 0 2 24 3. + <_> + + <_> + 16 7 6 14 -1. + <_> + 19 7 3 7 2. + <_> + 16 14 3 7 2. + <_> + + <_> + 4 7 4 12 -1. + <_> + 6 7 2 12 2. + <_> + + <_> + 0 5 24 14 -1. + <_> + 8 5 8 14 3. + <_> + + <_> + 5 13 10 6 -1. + <_> + 5 15 10 2 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 2 7 6 14 -1. + <_> + 2 7 3 7 2. + <_> + 5 14 3 7 2. + <_> + + <_> + 15 2 9 15 -1. + <_> + 18 2 3 15 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 2 2 2 9 3. + <_> + + <_> + 12 2 10 14 -1. + <_> + 17 2 5 7 2. + <_> + 12 9 5 7 2. + <_> + + <_> + 11 6 2 18 -1. + <_> + 12 6 1 18 2. + <_> + + <_> + 9 5 15 6 -1. + <_> + 14 5 5 6 3. + <_> + + <_> + 8 6 6 10 -1. + <_> + 10 6 2 10 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 3 3 9 7 -1. + <_> + 6 3 3 7 3. + <_> + + <_> + 6 7 14 3 -1. + <_> + 6 7 7 3 2. + <_> + + <_> + 7 7 8 6 -1. + <_> + 11 7 4 6 2. + <_> + + <_> + 12 7 7 12 -1. + <_> + 12 13 7 6 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 10 6 2 9 2. + <_> + 12 15 2 9 2. + <_> + + <_> + 16 14 6 9 -1. + <_> + 16 17 6 3 3. + <_> + + <_> + 4 0 6 13 -1. + <_> + 6 0 2 13 3. + <_> + + <_> + 2 2 21 3 -1. + <_> + 9 2 7 3 3. + <_> + + <_> + 5 4 5 12 -1. + <_> + 5 8 5 4 3. + <_> + + <_> + 10 3 4 10 -1. + <_> + 10 8 4 5 2. + <_> + + <_> + 8 4 5 8 -1. + <_> + 8 8 5 4 2. + <_> + + <_> + 6 0 11 9 -1. + <_> + 6 3 11 3 3. + <_> + + <_> + 6 6 12 5 -1. + <_> + 10 6 4 5 3. + <_> + + <_> + 0 0 24 5 -1. + <_> + 8 0 8 5 3. + <_> + + <_> + 1 10 23 6 -1. + <_> + 1 12 23 2 3. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 3 6 21 6 -1. + <_> + 3 8 21 2 3. + <_> + + <_> + 0 5 6 12 -1. + <_> + 2 5 2 12 3. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 8 7 8 10 -1. + <_> + 8 12 8 5 2. + <_> + + <_> + 5 7 15 12 -1. + <_> + 10 7 5 12 3. + <_> + + <_> + 0 17 10 6 -1. + <_> + 0 19 10 2 3. + <_> + + <_> + 14 18 9 6 -1. + <_> + 14 20 9 2 3. + <_> + + <_> + 9 6 6 16 -1. + <_> + 9 14 6 8 2. + <_> + + <_> + 14 18 9 6 -1. + <_> + 14 20 9 2 3. + <_> + + <_> + 1 18 9 6 -1. + <_> + 1 20 9 2 3. + <_> + + <_> + 15 9 9 6 -1. + <_> + 15 11 9 2 3. + <_> + + <_> + 0 9 9 6 -1. + <_> + 0 11 9 2 3. + <_> + + <_> + 17 3 6 9 -1. + <_> + 19 3 2 9 3. + <_> + + <_> + 2 17 18 3 -1. + <_> + 2 18 18 1 3. + <_> + + <_> + 3 15 21 6 -1. + <_> + 3 17 21 2 3. + <_> + + <_> + 9 17 6 6 -1. + <_> + 9 20 6 3 2. + <_> + + <_> + 18 3 6 9 -1. + <_> + 18 6 6 3 3. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 4 0 16 10 -1. + <_> + 12 0 8 5 2. + <_> + 4 5 8 5 2. + <_> + + <_> + 2 0 10 16 -1. + <_> + 2 0 5 8 2. + <_> + 7 8 5 8 2. + <_> + + <_> + 14 0 10 5 -1. + <_> + 14 0 5 5 2. + <_> + + <_> + 0 0 10 5 -1. + <_> + 5 0 5 5 2. + <_> + + <_> + 18 3 6 10 -1. + <_> + 18 3 3 10 2. + <_> + + <_> + 5 11 12 6 -1. + <_> + 5 11 6 3 2. + <_> + 11 14 6 3 2. + <_> + + <_> + 21 0 3 18 -1. + <_> + 22 0 1 18 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 8 8 9 7 -1. + <_> + 11 8 3 7 3. + <_> + + <_> + 7 12 8 10 -1. + <_> + 7 12 4 5 2. + <_> + 11 17 4 5 2. + <_> + + <_> + 21 0 3 18 -1. + <_> + 22 0 1 18 3. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 15 0 9 6 -1. + <_> + 15 2 9 2 3. + <_> + + <_> + 0 2 24 3 -1. + <_> + 0 3 24 1 3. + <_> + + <_> + 11 7 6 9 -1. + <_> + 13 7 2 9 3. + <_> + + <_> + 7 6 6 10 -1. + <_> + 9 6 2 10 3. + <_> + + <_> + 12 1 6 12 -1. + <_> + 14 1 2 12 3. + <_> + + <_> + 6 4 12 12 -1. + <_> + 6 10 12 6 2. + <_> + + <_> + 14 3 2 21 -1. + <_> + 14 3 1 21 2. + <_> + + <_> + 6 1 12 8 -1. + <_> + 6 5 12 4 2. + <_> + + <_> + 3 0 18 8 -1. + <_> + 3 4 18 4 2. + <_> + + <_> + 3 0 18 3 -1. + <_> + 3 1 18 1 3. + <_> + + <_> + 0 13 24 4 -1. + <_> + 12 13 12 2 2. + <_> + 0 15 12 2 2. + <_> + + <_> + 10 5 4 9 -1. + <_> + 12 5 2 9 2. + <_> + + <_> + 11 1 6 9 -1. + <_> + 13 1 2 9 3. + <_> + + <_> + 6 2 6 22 -1. + <_> + 8 2 2 22 3. + <_> + + <_> + 16 10 8 14 -1. + <_> + 20 10 4 7 2. + <_> + 16 17 4 7 2. + <_> + + <_> + 3 4 16 15 -1. + <_> + 3 9 16 5 3. + <_> + + <_> + 16 10 8 14 -1. + <_> + 20 10 4 7 2. + <_> + 16 17 4 7 2. + <_> + + <_> + 0 10 8 14 -1. + <_> + 0 10 4 7 2. + <_> + 4 17 4 7 2. + <_> + + <_> + 10 14 11 6 -1. + <_> + 10 17 11 3 2. + <_> + + <_> + 0 7 24 9 -1. + <_> + 8 7 8 9 3. + <_> + + <_> + 13 1 4 16 -1. + <_> + 13 1 2 16 2. + <_> + + <_> + 7 1 4 16 -1. + <_> + 9 1 2 16 2. + <_> + + <_> + 5 5 16 8 -1. + <_> + 13 5 8 4 2. + <_> + 5 9 8 4 2. + <_> + + <_> + 0 9 6 9 -1. + <_> + 0 12 6 3 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 3 12 6 9 -1. + <_> + 3 15 6 3 3. + <_> + + <_> + 8 14 9 6 -1. + <_> + 8 16 9 2 3. + <_> + + <_> + 2 13 8 10 -1. + <_> + 2 13 4 5 2. + <_> + 6 18 4 5 2. + <_> + + <_> + 15 5 3 18 -1. + <_> + 15 11 3 6 3. + <_> + + <_> + 3 5 18 3 -1. + <_> + 3 6 18 1 3. + <_> + + <_> + 17 5 6 11 -1. + <_> + 19 5 2 11 3. + <_> + + <_> + 1 5 6 11 -1. + <_> + 3 5 2 11 3. + <_> + + <_> + 19 1 4 9 -1. + <_> + 19 1 2 9 2. + <_> + + <_> + 1 1 4 9 -1. + <_> + 3 1 2 9 2. + <_> + + <_> + 4 15 18 9 -1. + <_> + 4 15 9 9 2. + <_> + + <_> + 6 9 12 4 -1. + <_> + 6 11 12 2 2. + <_> + + <_> + 15 2 9 6 -1. + <_> + 15 4 9 2 3. + <_> + + <_> + 0 2 9 6 -1. + <_> + 0 4 9 2 3. + <_> + + <_> + 15 0 6 17 -1. + <_> + 17 0 2 17 3. + <_> + + <_> + 3 0 6 17 -1. + <_> + 5 0 2 17 3. + <_> + + <_> + 8 17 9 4 -1. + <_> + 8 19 9 2 2. + <_> + + <_> + 6 5 3 18 -1. + <_> + 6 11 3 6 3. + <_> + + <_> + 5 2 14 12 -1. + <_> + 5 8 14 6 2. + <_> + + <_> + 10 2 3 12 -1. + <_> + 10 8 3 6 2. + <_> + + <_> + 10 7 14 15 -1. + <_> + 10 12 14 5 3. + <_> + + <_> + 0 7 14 15 -1. + <_> + 0 12 14 5 3. + <_> + + <_> + 15 0 9 6 -1. + <_> + 15 2 9 2 3. + <_> + + <_> + 0 0 9 6 -1. + <_> + 0 2 9 2 3. + <_> + + <_> + 12 6 6 14 -1. + <_> + 14 6 2 14 3. + <_> + + <_> + 9 7 6 9 -1. + <_> + 11 7 2 9 3. + <_> + + <_> + 12 6 6 15 -1. + <_> + 14 6 2 15 3. + <_> + + <_> + 6 6 6 15 -1. + <_> + 8 6 2 15 3. + <_> + + <_> + 15 3 8 9 -1. + <_> + 15 3 4 9 2. + <_> + + <_> + 0 0 9 21 -1. + <_> + 3 0 3 21 3. + <_> + + <_> + 11 9 8 12 -1. + <_> + 11 13 8 4 3. + <_> + + <_> + 6 7 10 12 -1. + <_> + 6 7 5 6 2. + <_> + 11 13 5 6 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 0 0 6 9 -1. + <_> + 0 3 6 3 3. + <_> + + <_> + 3 14 18 3 -1. + <_> + 3 15 18 1 3. + <_> + + <_> + 3 14 8 10 -1. + <_> + 3 14 4 5 2. + <_> + 7 19 4 5 2. + <_> + + <_> + 0 12 24 4 -1. + <_> + 12 12 12 2 2. + <_> + 0 14 12 2 2. + <_> + + <_> + 0 2 3 20 -1. + <_> + 1 2 1 20 3. + <_> + + <_> + 12 16 10 8 -1. + <_> + 17 16 5 4 2. + <_> + 12 20 5 4 2. + <_> + + <_> + 2 16 10 8 -1. + <_> + 2 16 5 4 2. + <_> + 7 20 5 4 2. + <_> + + <_> + 7 0 10 9 -1. + <_> + 7 3 10 3 3. + <_> + + <_> + 0 0 24 3 -1. + <_> + 8 0 8 3 3. + <_> + + <_> + 3 8 15 4 -1. + <_> + 3 10 15 2 2. + <_> + + <_> + 6 5 12 6 -1. + <_> + 10 5 4 6 3. + <_> + + <_> + 5 13 14 6 -1. + <_> + 5 16 14 3 2. + <_> + + <_> + 11 14 4 10 -1. + <_> + 11 19 4 5 2. + <_> + + <_> + 0 6 6 7 -1. + <_> + 3 6 3 7 2. + <_> + + <_> + 18 0 6 6 -1. + <_> + 18 0 3 6 2. + <_> + + <_> + 3 1 18 3 -1. + <_> + 3 2 18 1 3. + <_> + + <_> + 9 6 14 18 -1. + <_> + 9 12 14 6 3. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 0 20 24 3 -1. + <_> + 8 20 8 3 3. + <_> + + <_> + 13 11 6 7 -1. + <_> + 13 11 3 7 2. + <_> + + <_> + 4 12 10 6 -1. + <_> + 4 14 10 2 3. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 5 11 6 7 -1. + <_> + 8 11 3 7 2. + <_> + + <_> + 7 4 11 12 -1. + <_> + 7 8 11 4 3. + <_> + + <_> + 6 15 10 4 -1. + <_> + 6 17 10 2 2. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 4 0 6 9 -1. + <_> + 6 0 2 9 3. + <_> + + <_> + 11 2 4 15 -1. + <_> + 11 7 4 5 3. + <_> + + <_> + 0 0 20 3 -1. + <_> + 0 1 20 1 3. + <_> + + <_> + 13 18 10 6 -1. + <_> + 13 20 10 2 3. + <_> + + <_> + 2 7 6 11 -1. + <_> + 5 7 3 11 2. + <_> + + <_> + 10 14 10 9 -1. + <_> + 10 17 10 3 3. + <_> + + <_> + 8 2 4 9 -1. + <_> + 10 2 2 9 2. + <_> + + <_> + 14 3 10 4 -1. + <_> + 14 3 5 4 2. + <_> + + <_> + 6 6 12 6 -1. + <_> + 6 6 6 3 2. + <_> + 12 9 6 3 2. + <_> + + <_> + 8 8 8 10 -1. + <_> + 12 8 4 5 2. + <_> + 8 13 4 5 2. + <_> + + <_> + 7 4 4 16 -1. + <_> + 7 12 4 8 2. + <_> + + <_> + 8 8 9 4 -1. + <_> + 8 10 9 2 2. + <_> + + <_> + 5 2 14 9 -1. + <_> + 5 5 14 3 3. + <_> + + <_> + 3 16 19 8 -1. + <_> + 3 20 19 4 2. + <_> + + <_> + 0 0 10 8 -1. + <_> + 5 0 5 8 2. + <_> + + <_> + 5 2 16 18 -1. + <_> + 5 2 8 18 2. + <_> + + <_> + 0 11 24 11 -1. + <_> + 8 11 8 11 3. + <_> + + <_> + 3 3 18 5 -1. + <_> + 3 3 9 5 2. + <_> + + <_> + 1 16 18 3 -1. + <_> + 1 17 18 1 3. + <_> + + <_> + 5 17 18 3 -1. + <_> + 5 18 18 1 3. + <_> + + <_> + 1 13 9 6 -1. + <_> + 1 15 9 2 3. + <_> + + <_> + 1 9 23 10 -1. + <_> + 1 14 23 5 2. + <_> + + <_> + 3 7 18 3 -1. + <_> + 3 8 18 1 3. + <_> + + <_> + 6 8 12 3 -1. + <_> + 6 8 6 3 2. + <_> + + <_> + 6 2 3 22 -1. + <_> + 7 2 1 22 3. + <_> + + <_> + 14 17 10 6 -1. + <_> + 14 19 10 2 3. + <_> + + <_> + 1 18 10 6 -1. + <_> + 1 20 10 2 3. + <_> + + <_> + 11 3 6 12 -1. + <_> + 13 3 2 12 3. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 12 10 9 6 -1. + <_> + 15 10 3 6 3. + <_> + + <_> + 2 11 6 9 -1. + <_> + 5 11 3 9 2. + <_> + + <_> + 14 5 3 19 -1. + <_> + 15 5 1 19 3. + <_> + + <_> + 6 6 9 6 -1. + <_> + 6 8 9 2 3. + <_> + + <_> + 14 5 3 19 -1. + <_> + 15 5 1 19 3. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 5 21 18 3 -1. + <_> + 5 22 18 1 3. + <_> + + <_> + 1 10 18 4 -1. + <_> + 7 10 6 4 3. + <_> + + <_> + 13 4 8 10 -1. + <_> + 17 4 4 5 2. + <_> + 13 9 4 5 2. + <_> + + <_> + 7 8 9 6 -1. + <_> + 10 8 3 6 3. + <_> + + <_> + 12 9 9 8 -1. + <_> + 15 9 3 8 3. + <_> + + <_> + 0 6 5 12 -1. + <_> + 0 10 5 4 3. + <_> + + <_> + 7 6 14 6 -1. + <_> + 14 6 7 3 2. + <_> + 7 9 7 3 2. + <_> + + <_> + 7 5 3 19 -1. + <_> + 8 5 1 19 3. + <_> + + <_> + 8 4 15 20 -1. + <_> + 13 4 5 20 3. + <_> + + <_> + 1 4 15 20 -1. + <_> + 6 4 5 20 3. + <_> + + <_> + 13 10 6 6 -1. + <_> + 13 10 3 6 2. + <_> + + <_> + 5 10 6 6 -1. + <_> + 8 10 3 6 2. + <_> + + <_> + 14 2 6 14 -1. + <_> + 17 2 3 7 2. + <_> + 14 9 3 7 2. + <_> + + <_> + 4 2 6 14 -1. + <_> + 4 2 3 7 2. + <_> + 7 9 3 7 2. + <_> + + <_> + 12 4 6 7 -1. + <_> + 12 4 3 7 2. + <_> + + <_> + 9 4 6 9 -1. + <_> + 11 4 2 9 3. + <_> + + <_> + 11 4 8 10 -1. + <_> + 11 4 4 10 2. + <_> + + <_> + 5 4 8 10 -1. + <_> + 9 4 4 10 2. + <_> + + <_> + 8 18 10 6 -1. + <_> + 8 20 10 2 3. + <_> + + <_> + 1 18 21 6 -1. + <_> + 1 20 21 2 3. + <_> + + <_> + 9 2 12 6 -1. + <_> + 9 2 6 6 2. + <_> + + <_> + 3 2 12 6 -1. + <_> + 9 2 6 6 2. + <_> + + <_> + 12 5 12 6 -1. + <_> + 18 5 6 3 2. + <_> + 12 8 6 3 2. + <_> + + <_> + 8 8 6 9 -1. + <_> + 8 11 6 3 3. + <_> + + <_> + 2 7 20 6 -1. + <_> + 2 9 20 2 3. + <_> + + <_> + 0 5 12 6 -1. + <_> + 0 5 6 3 2. + <_> + 6 8 6 3 2. + <_> + + <_> + 14 14 8 10 -1. + <_> + 18 14 4 5 2. + <_> + 14 19 4 5 2. + <_> + + <_> + 2 14 8 10 -1. + <_> + 2 14 4 5 2. + <_> + 6 19 4 5 2. + <_> + + <_> + 2 11 20 13 -1. + <_> + 2 11 10 13 2. + <_> + + <_> + 6 9 12 5 -1. + <_> + 12 9 6 5 2. + <_> + + <_> + 5 6 16 6 -1. + <_> + 13 6 8 3 2. + <_> + 5 9 8 3 2. + <_> + + <_> + 1 19 9 4 -1. + <_> + 1 21 9 2 2. + <_> + + <_> + 7 5 12 5 -1. + <_> + 11 5 4 5 3. + <_> + + <_> + 3 5 14 12 -1. + <_> + 3 5 7 6 2. + <_> + 10 11 7 6 2. + <_> + + <_> + 9 4 9 6 -1. + <_> + 12 4 3 6 3. + <_> + + <_> + 2 6 19 3 -1. + <_> + 2 7 19 1 3. + <_> + + <_> + 18 10 6 9 -1. + <_> + 18 13 6 3 3. + <_> + + <_> + 3 7 18 2 -1. + <_> + 3 8 18 1 2. + <_> + + <_> + 20 2 4 18 -1. + <_> + 22 2 2 9 2. + <_> + 20 11 2 9 2. + <_> + + <_> + 2 18 20 3 -1. + <_> + 2 19 20 1 3. + <_> + + <_> + 1 9 22 3 -1. + <_> + 1 10 22 1 3. + <_> + + <_> + 0 2 4 18 -1. + <_> + 0 2 2 9 2. + <_> + 2 11 2 9 2. + <_> + + <_> + 19 0 4 23 -1. + <_> + 19 0 2 23 2. + <_> + + <_> + 0 3 6 19 -1. + <_> + 3 3 3 19 2. + <_> + + <_> + 18 2 6 9 -1. + <_> + 20 2 2 9 3. + <_> + + <_> + 0 5 10 6 -1. + <_> + 0 7 10 2 3. + <_> + + <_> + 7 0 12 12 -1. + <_> + 13 0 6 6 2. + <_> + 7 6 6 6 2. + <_> + + <_> + 0 3 24 6 -1. + <_> + 0 3 12 3 2. + <_> + 12 6 12 3 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 8 9 4 15 -1. + <_> + 8 14 4 5 3. + <_> + + <_> + 4 11 17 6 -1. + <_> + 4 14 17 3 2. + <_> + + <_> + 2 5 18 8 -1. + <_> + 2 5 9 4 2. + <_> + 11 9 9 4 2. + <_> + + <_> + 7 6 14 6 -1. + <_> + 14 6 7 3 2. + <_> + 7 9 7 3 2. + <_> + + <_> + 3 6 14 6 -1. + <_> + 3 6 7 3 2. + <_> + 10 9 7 3 2. + <_> + + <_> + 16 5 3 18 -1. + <_> + 17 5 1 18 3. + <_> + + <_> + 5 5 3 18 -1. + <_> + 6 5 1 18 3. + <_> + + <_> + 10 10 14 4 -1. + <_> + 10 12 14 2 2. + <_> + + <_> + 4 10 9 4 -1. + <_> + 4 12 9 2 2. + <_> + + <_> + 2 0 18 9 -1. + <_> + 2 3 18 3 3. + <_> + + <_> + 6 3 12 8 -1. + <_> + 10 3 4 8 3. + <_> + + <_> + 1 1 8 5 -1. + <_> + 5 1 4 5 2. + <_> + + <_> + 12 7 7 8 -1. + <_> + 12 11 7 4 2. + <_> + + <_> + 0 12 22 4 -1. + <_> + 0 14 22 2 2. + <_> + + <_> + 15 6 4 15 -1. + <_> + 15 11 4 5 3. + <_> + + <_> + 5 7 7 8 -1. + <_> + 5 11 7 4 2. + <_> + + <_> + 8 18 9 4 -1. + <_> + 8 20 9 2 2. + <_> + + <_> + 1 2 22 4 -1. + <_> + 1 4 22 2 2. + <_> + + <_> + 17 3 6 17 -1. + <_> + 19 3 2 17 3. + <_> + + <_> + 8 2 8 18 -1. + <_> + 8 11 8 9 2. + <_> + + <_> + 17 0 6 12 -1. + <_> + 20 0 3 6 2. + <_> + 17 6 3 6 2. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 15 5 9 12 -1. + <_> + 15 11 9 6 2. + <_> + + <_> + 2 22 18 2 -1. + <_> + 2 23 18 1 2. + <_> + + <_> + 10 10 12 6 -1. + <_> + 16 10 6 3 2. + <_> + 10 13 6 3 2. + <_> + + <_> + 0 1 4 11 -1. + <_> + 2 1 2 11 2. + <_> + + <_> + 20 0 4 10 -1. + <_> + 20 0 2 10 2. + <_> + + <_> + 1 3 6 17 -1. + <_> + 3 3 2 17 3. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 13 8 9 -1. + <_> + 0 16 8 3 3. + <_> + + <_> + 16 8 6 12 -1. + <_> + 16 12 6 4 3. + <_> + + <_> + 2 8 6 12 -1. + <_> + 2 12 6 4 3. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 1 5 19 3 -1. + <_> + 1 6 19 1 3. + <_> + + <_> + 11 8 9 7 -1. + <_> + 14 8 3 7 3. + <_> + + <_> + 3 8 12 9 -1. + <_> + 3 11 12 3 3. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 10 0 4 12 -1. + <_> + 10 6 4 6 2. + <_> + + <_> + 3 9 18 14 -1. + <_> + 3 9 9 14 2. + <_> + + <_> + 0 0 4 9 -1. + <_> + 2 0 2 9 2. + <_> + + <_> + 12 5 4 18 -1. + <_> + 12 5 2 18 2. + <_> + + <_> + 8 5 4 18 -1. + <_> + 10 5 2 18 2. + <_> + + <_> + 10 5 6 10 -1. + <_> + 12 5 2 10 3. + <_> + + <_> + 9 4 4 11 -1. + <_> + 11 4 2 11 2. + <_> + + <_> + 4 16 18 3 -1. + <_> + 4 17 18 1 3. + <_> + + <_> + 0 16 20 3 -1. + <_> + 0 17 20 1 3. + <_> + + <_> + 9 9 6 12 -1. + <_> + 9 13 6 4 3. + <_> + + <_> + 8 13 8 8 -1. + <_> + 8 17 8 4 2. + <_> + + <_> + 13 10 3 12 -1. + <_> + 13 16 3 6 2. + <_> + + <_> + 5 9 14 14 -1. + <_> + 5 9 7 7 2. + <_> + 12 16 7 7 2. + <_> + + <_> + 0 0 24 10 -1. + <_> + 12 0 12 5 2. + <_> + 0 5 12 5 2. + <_> + + <_> + 1 11 18 2 -1. + <_> + 1 12 18 1 2. + <_> + + <_> + 19 5 5 12 -1. + <_> + 19 9 5 4 3. + <_> + + <_> + 0 5 5 12 -1. + <_> + 0 9 5 4 3. + <_> + + <_> + 16 6 8 18 -1. + <_> + 20 6 4 9 2. + <_> + 16 15 4 9 2. + <_> + + <_> + 0 6 8 18 -1. + <_> + 0 6 4 9 2. + <_> + 4 15 4 9 2. + <_> + + <_> + 12 5 12 12 -1. + <_> + 18 5 6 6 2. + <_> + 12 11 6 6 2. + <_> + + <_> + 7 6 6 9 -1. + <_> + 9 6 2 9 3. + <_> + + <_> + 9 13 6 11 -1. + <_> + 11 13 2 11 3. + <_> + + <_> + 0 5 12 12 -1. + <_> + 0 5 6 6 2. + <_> + 6 11 6 6 2. + <_> + + <_> + 1 2 23 3 -1. + <_> + 1 3 23 1 3. + <_> + + <_> + 1 15 19 3 -1. + <_> + 1 16 19 1 3. + <_> + + <_> + 13 17 11 4 -1. + <_> + 13 19 11 2 2. + <_> + + <_> + 0 13 8 5 -1. + <_> + 4 13 4 5 2. + <_> + + <_> + 12 10 10 4 -1. + <_> + 12 10 5 4 2. + <_> + + <_> + 4 6 9 9 -1. + <_> + 4 9 9 3 3. + <_> + + <_> + 15 14 9 6 -1. + <_> + 15 16 9 2 3. + <_> + + <_> + 1 12 9 6 -1. + <_> + 1 14 9 2 3. + <_> + + <_> + 3 10 20 8 -1. + <_> + 13 10 10 4 2. + <_> + 3 14 10 4 2. + <_> + + <_> + 2 0 9 18 -1. + <_> + 5 0 3 18 3. + <_> + + <_> + 13 11 9 10 -1. + <_> + 16 11 3 10 3. + <_> + + <_> + 1 2 8 5 -1. + <_> + 5 2 4 5 2. + <_> + + <_> + 3 4 21 6 -1. + <_> + 10 4 7 6 3. + <_> + + <_> + 7 0 10 14 -1. + <_> + 7 0 5 7 2. + <_> + 12 7 5 7 2. + <_> + + <_> + 12 17 12 4 -1. + <_> + 12 19 12 2 2. + <_> + + <_> + 0 6 23 4 -1. + <_> + 0 8 23 2 2. + <_> + + <_> + 13 10 8 10 -1. + <_> + 17 10 4 5 2. + <_> + 13 15 4 5 2. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 15 16 9 4 -1. + <_> + 15 18 9 2 2. + <_> + + <_> + 0 16 9 4 -1. + <_> + 0 18 9 2 2. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 5 11 6 6 -1. + <_> + 8 11 3 6 2. + <_> + + <_> + 0 3 24 6 -1. + <_> + 12 3 12 3 2. + <_> + 0 6 12 3 2. + <_> + + <_> + 2 4 18 3 -1. + <_> + 2 5 18 1 3. + <_> + + <_> + 0 0 24 4 -1. + <_> + 12 0 12 2 2. + <_> + 0 2 12 2 2. + <_> + + <_> + 1 16 18 3 -1. + <_> + 1 17 18 1 3. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 6 17 18 3 -1. + <_> + 6 18 18 1 3. + <_> + + <_> + 8 8 6 10 -1. + <_> + 10 8 2 10 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 8 8 5 8 -1. + <_> + 8 12 5 4 2. + <_> + + <_> + 12 8 6 8 -1. + <_> + 12 12 6 4 2. + <_> + + <_> + 6 5 6 11 -1. + <_> + 8 5 2 11 3. + <_> + + <_> + 13 6 8 9 -1. + <_> + 13 9 8 3 3. + <_> + + <_> + 1 7 21 6 -1. + <_> + 1 9 21 2 3. + <_> + + <_> + 15 5 3 12 -1. + <_> + 15 11 3 6 2. + <_> + + <_> + 6 9 11 12 -1. + <_> + 6 13 11 4 3. + <_> + + <_> + 13 8 10 8 -1. + <_> + 18 8 5 4 2. + <_> + 13 12 5 4 2. + <_> + + <_> + 5 8 12 3 -1. + <_> + 11 8 6 3 2. + <_> + + <_> + 6 11 18 4 -1. + <_> + 12 11 6 4 3. + <_> + + <_> + 0 0 22 22 -1. + <_> + 0 11 22 11 2. + <_> + + <_> + 11 2 6 8 -1. + <_> + 11 6 6 4 2. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 8 3 6 14 -1. + <_> + 8 3 3 7 2. + <_> + 11 10 3 7 2. + <_> + + <_> + 3 10 18 8 -1. + <_> + 9 10 6 8 3. + <_> + + <_> + 10 0 3 14 -1. + <_> + 10 7 3 7 2. + <_> + + <_> + 4 3 16 20 -1. + <_> + 4 13 16 10 2. + <_> + + <_> + 9 4 6 10 -1. + <_> + 11 4 2 10 3. + <_> + + <_> + 5 0 16 4 -1. + <_> + 5 2 16 2 2. + <_> + + <_> + 2 5 18 4 -1. + <_> + 8 5 6 4 3. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 8 4 8 5 -1. + <_> + 12 4 4 5 2. + <_> + + <_> + 12 10 10 4 -1. + <_> + 12 10 5 4 2. + <_> + + <_> + 2 10 10 4 -1. + <_> + 7 10 5 4 2. + <_> + + <_> + 7 11 12 5 -1. + <_> + 11 11 4 5 3. + <_> + + <_> + 3 10 8 10 -1. + <_> + 3 10 4 5 2. + <_> + 7 15 4 5 2. + <_> + + <_> + 11 12 9 8 -1. + <_> + 14 12 3 8 3. + <_> + + <_> + 0 21 24 3 -1. + <_> + 8 21 8 3 3. + <_> + + <_> + 3 20 18 4 -1. + <_> + 9 20 6 4 3. + <_> + + <_> + 1 15 9 6 -1. + <_> + 1 17 9 2 3. + <_> + + <_> + 11 17 10 4 -1. + <_> + 11 19 10 2 2. + <_> + + <_> + 9 12 4 12 -1. + <_> + 9 18 4 6 2. + <_> + + <_> + 9 6 9 6 -1. + <_> + 12 6 3 6 3. + <_> + + <_> + 1 13 6 9 -1. + <_> + 1 16 6 3 3. + <_> + + <_> + 6 16 12 4 -1. + <_> + 6 18 12 2 2. + <_> + + <_> + 1 5 20 3 -1. + <_> + 1 6 20 1 3. + <_> + + <_> + 8 1 9 9 -1. + <_> + 8 4 9 3 3. + <_> + + <_> + 2 19 9 4 -1. + <_> + 2 21 9 2 2. + <_> + + <_> + 11 1 4 18 -1. + <_> + 11 7 4 6 3. + <_> + + <_> + 7 2 8 12 -1. + <_> + 7 2 4 6 2. + <_> + 11 8 4 6 2. + <_> + + <_> + 11 10 9 8 -1. + <_> + 14 10 3 8 3. + <_> + + <_> + 5 11 12 5 -1. + <_> + 9 11 4 5 3. + <_> + + <_> + 11 9 9 6 -1. + <_> + 14 9 3 6 3. + <_> + + <_> + 5 10 6 9 -1. + <_> + 7 10 2 9 3. + <_> + + <_> + 4 7 5 12 -1. + <_> + 4 11 5 4 3. + <_> + + <_> + 2 0 21 6 -1. + <_> + 9 0 7 6 3. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 9 0 6 15 -1. + <_> + 11 0 2 15 3. + <_> + + <_> + 2 2 18 2 -1. + <_> + 2 3 18 1 2. + <_> + + <_> + 8 17 8 6 -1. + <_> + 8 20 8 3 2. + <_> + + <_> + 3 0 18 2 -1. + <_> + 3 1 18 1 2. + <_> + + <_> + 8 0 9 6 -1. + <_> + 11 0 3 6 3. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 6 7 12 5 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 0 3 6 9 -1. + <_> + 2 3 2 9 3. + <_> + + <_> + 20 2 4 9 -1. + <_> + 20 2 2 9 2. + <_> + + <_> + 0 2 4 9 -1. + <_> + 2 2 2 9 2. + <_> + + <_> + 0 1 24 4 -1. + <_> + 12 1 12 2 2. + <_> + 0 3 12 2 2. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 14 13 9 6 -1. + <_> + 14 15 9 2 3. + <_> + + <_> + 0 15 19 3 -1. + <_> + 0 16 19 1 3. + <_> + + <_> + 1 5 22 12 -1. + <_> + 12 5 11 6 2. + <_> + 1 11 11 6 2. + <_> + + <_> + 5 13 6 6 -1. + <_> + 8 13 3 6 2. + <_> + + <_> + 4 2 20 3 -1. + <_> + 4 3 20 1 3. + <_> + + <_> + 8 14 6 10 -1. + <_> + 10 14 2 10 3. + <_> + + <_> + 6 12 16 6 -1. + <_> + 14 12 8 3 2. + <_> + 6 15 8 3 2. + <_> + + <_> + 2 13 8 9 -1. + <_> + 2 16 8 3 3. + <_> + + <_> + 11 8 6 14 -1. + <_> + 14 8 3 7 2. + <_> + 11 15 3 7 2. + <_> + + <_> + 2 12 16 6 -1. + <_> + 2 12 8 3 2. + <_> + 10 15 8 3 2. + <_> + + <_> + 5 16 16 8 -1. + <_> + 5 20 16 4 2. + <_> + + <_> + 9 1 4 12 -1. + <_> + 9 7 4 6 2. + <_> + + <_> + 8 2 8 10 -1. + <_> + 12 2 4 5 2. + <_> + 8 7 4 5 2. + <_> + + <_> + 6 6 12 6 -1. + <_> + 6 6 6 3 2. + <_> + 12 9 6 3 2. + <_> + + <_> + 10 7 6 9 -1. + <_> + 12 7 2 9 3. + <_> + + <_> + 0 0 8 12 -1. + <_> + 0 0 4 6 2. + <_> + 4 6 4 6 2. + <_> + + <_> + 18 8 6 9 -1. + <_> + 18 11 6 3 3. + <_> + + <_> + 2 12 6 6 -1. + <_> + 5 12 3 6 2. + <_> + + <_> + 3 21 21 3 -1. + <_> + 10 21 7 3 3. + <_> + + <_> + 2 0 16 6 -1. + <_> + 2 3 16 3 2. + <_> + + <_> + 13 6 7 6 -1. + <_> + 13 9 7 3 2. + <_> + + <_> + 6 4 4 14 -1. + <_> + 6 11 4 7 2. + <_> + + <_> + 9 7 6 9 -1. + <_> + 11 7 2 9 3. + <_> + + <_> + 7 8 6 14 -1. + <_> + 7 8 3 7 2. + <_> + 10 15 3 7 2. + <_> + + <_> + 18 8 4 16 -1. + <_> + 18 16 4 8 2. + <_> + + <_> + 9 14 6 10 -1. + <_> + 11 14 2 10 3. + <_> + + <_> + 6 11 12 5 -1. + <_> + 10 11 4 5 3. + <_> + + <_> + 0 12 23 3 -1. + <_> + 0 13 23 1 3. + <_> + + <_> + 13 0 6 12 -1. + <_> + 15 0 2 12 3. + <_> + + <_> + 0 10 12 5 -1. + <_> + 4 10 4 5 3. + <_> + + <_> + 13 2 10 4 -1. + <_> + 13 4 10 2 2. + <_> + + <_> + 5 0 6 12 -1. + <_> + 7 0 2 12 3. + <_> + + <_> + 11 6 9 6 -1. + <_> + 14 6 3 6 3. + <_> + + <_> + 4 6 9 6 -1. + <_> + 7 6 3 6 3. + <_> + + <_> + 6 11 18 13 -1. + <_> + 12 11 6 13 3. + <_> + + <_> + 0 11 18 13 -1. + <_> + 6 11 6 13 3. + <_> + + <_> + 12 16 12 6 -1. + <_> + 16 16 4 6 3. + <_> + + <_> + 0 6 21 3 -1. + <_> + 0 7 21 1 3. + <_> + + <_> + 12 16 12 6 -1. + <_> + 16 16 4 6 3. + <_> + + <_> + 5 7 6 14 -1. + <_> + 5 14 6 7 2. + <_> + + <_> + 5 10 19 2 -1. + <_> + 5 11 19 1 2. + <_> + + <_> + 5 4 14 4 -1. + <_> + 5 6 14 2 2. + <_> + + <_> + 3 18 18 4 -1. + <_> + 9 18 6 4 3. + <_> + + <_> + 7 0 4 9 -1. + <_> + 9 0 2 9 2. + <_> + + <_> + 13 3 11 4 -1. + <_> + 13 5 11 2 2. + <_> + + <_> + 2 0 9 6 -1. + <_> + 5 0 3 6 3. + <_> + + <_> + 19 1 4 23 -1. + <_> + 19 1 2 23 2. + <_> + + <_> + 1 1 4 23 -1. + <_> + 3 1 2 23 2. + <_> + + <_> + 5 16 18 3 -1. + <_> + 5 17 18 1 3. + <_> + + <_> + 0 3 11 4 -1. + <_> + 0 5 11 2 2. + <_> + + <_> + 2 16 20 3 -1. + <_> + 2 17 20 1 3. + <_> + + <_> + 5 3 13 4 -1. + <_> + 5 5 13 2 2. + <_> + + <_> + 1 9 22 15 -1. + <_> + 1 9 11 15 2. + <_> + + <_> + 3 4 14 3 -1. + <_> + 10 4 7 3 2. + <_> + + <_> + 8 7 10 4 -1. + <_> + 8 7 5 4 2. + <_> + + <_> + 6 7 10 4 -1. + <_> + 11 7 5 4 2. + <_> + + <_> + 10 4 6 9 -1. + <_> + 12 4 2 9 3. + <_> + + <_> + 1 12 9 6 -1. + <_> + 4 12 3 6 3. + <_> + + <_> + 8 3 8 10 -1. + <_> + 12 3 4 5 2. + <_> + 8 8 4 5 2. + <_> + + <_> + 3 6 16 6 -1. + <_> + 3 6 8 3 2. + <_> + 11 9 8 3 2. + <_> + + <_> + 5 6 14 6 -1. + <_> + 5 9 14 3 2. + <_> + + <_> + 4 3 9 6 -1. + <_> + 4 5 9 2 3. + <_> + + <_> + 6 3 18 2 -1. + <_> + 6 4 18 1 2. + <_> + + <_> + 7 6 9 6 -1. + <_> + 10 6 3 6 3. + <_> + + <_> + 0 1 24 3 -1. + <_> + 0 2 24 1 3. + <_> + + <_> + 0 17 10 6 -1. + <_> + 0 19 10 2 3. + <_> + + <_> + 3 18 18 3 -1. + <_> + 3 19 18 1 3. + <_> + + <_> + 2 5 6 16 -1. + <_> + 2 5 3 8 2. + <_> + 5 13 3 8 2. + <_> + + <_> + 7 6 11 6 -1. + <_> + 7 8 11 2 3. + <_> + + <_> + 5 2 12 22 -1. + <_> + 5 13 12 11 2. + <_> + + <_> + 10 7 4 10 -1. + <_> + 10 12 4 5 2. + <_> + + <_> + 9 0 4 18 -1. + <_> + 9 6 4 6 3. + <_> + + <_> + 18 8 6 9 -1. + <_> + 18 11 6 3 3. + <_> + + <_> + 4 7 15 10 -1. + <_> + 9 7 5 10 3. + <_> + + <_> + 10 5 6 9 -1. + <_> + 12 5 2 9 3. + <_> + + <_> + 9 9 6 10 -1. + <_> + 11 9 2 10 3. + <_> + + <_> + 11 14 6 10 -1. + <_> + 13 14 2 10 3. + <_> + + <_> + 7 14 6 10 -1. + <_> + 9 14 2 10 3. + <_> + + <_> + 4 8 16 9 -1. + <_> + 4 11 16 3 3. + <_> + + <_> + 2 11 20 3 -1. + <_> + 2 12 20 1 3. + <_> + + <_> + 13 0 4 13 -1. + <_> + 13 0 2 13 2. + <_> + + <_> + 7 0 4 13 -1. + <_> + 9 0 2 13 2. + <_> + + <_> + 3 1 18 7 -1. + <_> + 9 1 6 7 3. + <_> + + <_> + 1 11 6 9 -1. + <_> + 1 14 6 3 3. + <_> + + <_> + 8 18 9 6 -1. + <_> + 8 20 9 2 3. + <_> + + <_> + 3 9 15 6 -1. + <_> + 3 11 15 2 3. + <_> + + <_> + 5 10 19 2 -1. + <_> + 5 11 19 1 2. + <_> + + <_> + 8 6 7 16 -1. + <_> + 8 14 7 8 2. + <_> + + <_> + 9 14 9 6 -1. + <_> + 9 16 9 2 3. + <_> + + <_> + 0 7 8 12 -1. + <_> + 0 11 8 4 3. + <_> + + <_> + 6 4 18 3 -1. + <_> + 6 5 18 1 3. + <_> + + <_> + 0 16 12 6 -1. + <_> + 4 16 4 6 3. + <_> + + <_> + 13 13 9 4 -1. + <_> + 13 15 9 2 2. + <_> + + <_> + 5 8 14 14 -1. + <_> + 5 8 7 7 2. + <_> + 12 15 7 7 2. + <_> + + <_> + 1 16 22 6 -1. + <_> + 12 16 11 3 2. + <_> + 1 19 11 3 2. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 9 5 10 10 -1. + <_> + 14 5 5 5 2. + <_> + 9 10 5 5 2. + <_> + + <_> + 5 5 10 10 -1. + <_> + 5 5 5 5 2. + <_> + 10 10 5 5 2. + <_> + + <_> + 4 6 16 6 -1. + <_> + 12 6 8 3 2. + <_> + 4 9 8 3 2. + <_> + + <_> + 0 7 6 9 -1. + <_> + 0 10 6 3 3. + <_> + + <_> + 16 10 8 14 -1. + <_> + 20 10 4 7 2. + <_> + 16 17 4 7 2. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 18 6 6 2. + <_> + + <_> + 8 10 8 12 -1. + <_> + 12 10 4 6 2. + <_> + 8 16 4 6 2. + <_> + + <_> + 8 0 4 9 -1. + <_> + 10 0 2 9 2. + <_> + + <_> + 10 4 8 16 -1. + <_> + 14 4 4 8 2. + <_> + 10 12 4 8 2. + <_> + + <_> + 7 10 10 6 -1. + <_> + 7 12 10 2 3. + <_> + + <_> + 5 6 14 14 -1. + <_> + 12 6 7 7 2. + <_> + 5 13 7 7 2. + <_> + + <_> + 2 11 20 2 -1. + <_> + 2 12 20 1 2. + <_> + + <_> + 18 8 4 16 -1. + <_> + 18 16 4 8 2. + <_> + + <_> + 1 11 12 10 -1. + <_> + 1 11 6 5 2. + <_> + 7 16 6 5 2. + <_> + + <_> + 6 9 12 4 -1. + <_> + 6 11 12 2 2. + <_> + + <_> + 9 12 6 7 -1. + <_> + 12 12 3 7 2. + <_> + + <_> + 10 4 8 16 -1. + <_> + 14 4 4 8 2. + <_> + 10 12 4 8 2. + <_> + + <_> + 6 4 8 16 -1. + <_> + 6 4 4 8 2. + <_> + 10 12 4 8 2. + <_> + + <_> + 8 9 9 6 -1. + <_> + 11 9 3 6 3. + <_> + + <_> + 1 5 16 12 -1. + <_> + 1 5 8 6 2. + <_> + 9 11 8 6 2. + <_> + + <_> + 9 9 6 8 -1. + <_> + 9 9 3 8 2. + <_> + + <_> + 6 0 3 18 -1. + <_> + 7 0 1 18 3. + <_> + + <_> + 17 9 5 14 -1. + <_> + 17 16 5 7 2. + <_> + + <_> + 2 9 5 14 -1. + <_> + 2 16 5 7 2. + <_> + + <_> + 7 4 10 6 -1. + <_> + 7 7 10 3 2. + <_> + + <_> + 1 3 23 18 -1. + <_> + 1 9 23 6 3. + <_> + + <_> + 1 1 21 3 -1. + <_> + 8 1 7 3 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 3 18 12 6 -1. + <_> + 3 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 16 8 8 16 -1. + <_> + 20 8 4 8 2. + <_> + 16 16 4 8 2. + <_> + + <_> + 0 19 24 4 -1. + <_> + 8 19 8 4 3. + <_> + + <_> + 16 8 8 16 -1. + <_> + 20 8 4 8 2. + <_> + 16 16 4 8 2. + <_> + + <_> + 0 8 8 16 -1. + <_> + 0 8 4 8 2. + <_> + 4 16 4 8 2. + <_> + + <_> + 8 12 8 10 -1. + <_> + 8 17 8 5 2. + <_> + + <_> + 5 7 5 8 -1. + <_> + 5 11 5 4 2. + <_> + + <_> + 4 1 19 2 -1. + <_> + 4 2 19 1 2. + <_> + + <_> + 0 12 24 9 -1. + <_> + 8 12 8 9 3. + <_> + + <_> + 6 0 13 8 -1. + <_> + 6 4 13 4 2. + <_> + + <_> + 0 0 24 3 -1. + <_> + 0 1 24 1 3. + <_> + + <_> + 20 3 4 11 -1. + <_> + 20 3 2 11 2. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 6 11 12 8 -1. + <_> + 12 11 6 4 2. + <_> + 6 15 6 4 2. + <_> + + <_> + 0 8 12 6 -1. + <_> + 0 8 6 3 2. + <_> + 6 11 6 3 2. + <_> + + <_> + 6 17 18 3 -1. + <_> + 6 18 18 1 3. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 20 3 4 9 -1. + <_> + 20 3 2 9 2. + <_> + + <_> + 0 3 4 9 -1. + <_> + 2 3 2 9 2. + <_> + + <_> + 15 0 9 19 -1. + <_> + 18 0 3 19 3. + <_> + + <_> + 0 0 9 19 -1. + <_> + 3 0 3 19 3. + <_> + + <_> + 13 11 6 8 -1. + <_> + 13 11 3 8 2. + <_> + + <_> + 5 11 6 8 -1. + <_> + 8 11 3 8 2. + <_> + + <_> + 5 11 19 3 -1. + <_> + 5 12 19 1 3. + <_> + + <_> + 3 20 18 4 -1. + <_> + 9 20 6 4 3. + <_> + + <_> + 6 6 16 6 -1. + <_> + 6 8 16 2 3. + <_> + + <_> + 6 0 9 6 -1. + <_> + 9 0 3 6 3. + <_> + + <_> + 10 3 4 14 -1. + <_> + 10 10 4 7 2. + <_> + + <_> + 1 5 15 12 -1. + <_> + 1 11 15 6 2. + <_> + + <_> + 11 12 8 5 -1. + <_> + 11 12 4 5 2. + <_> + + <_> + 5 0 6 9 -1. + <_> + 7 0 2 9 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 5 5 12 8 -1. + <_> + 5 5 6 4 2. + <_> + 11 9 6 4 2. + <_> + + <_> + 13 12 11 6 -1. + <_> + 13 14 11 2 3. + <_> + + <_> + 0 13 21 3 -1. + <_> + 0 14 21 1 3. + <_> + + <_> + 8 1 8 12 -1. + <_> + 12 1 4 6 2. + <_> + 8 7 4 6 2. + <_> + + <_> + 1 0 6 12 -1. + <_> + 1 0 3 6 2. + <_> + 4 6 3 6 2. + <_> + + <_> + 2 2 21 2 -1. + <_> + 2 3 21 1 2. + <_> + + <_> + 2 2 19 3 -1. + <_> + 2 3 19 1 3. + <_> + + <_> + 17 10 6 14 -1. + <_> + 20 10 3 7 2. + <_> + 17 17 3 7 2. + <_> + + <_> + 1 10 6 14 -1. + <_> + 1 10 3 7 2. + <_> + 4 17 3 7 2. + <_> + + <_> + 7 6 14 14 -1. + <_> + 14 6 7 7 2. + <_> + 7 13 7 7 2. + <_> + + <_> + 0 12 9 6 -1. + <_> + 0 14 9 2 3. + <_> + + <_> + 15 14 8 9 -1. + <_> + 15 17 8 3 3. + <_> + + <_> + 1 1 22 4 -1. + <_> + 1 1 11 2 2. + <_> + 12 3 11 2 2. + <_> + + <_> + 9 11 9 6 -1. + <_> + 9 13 9 2 3. + <_> + + <_> + 0 15 18 3 -1. + <_> + 0 16 18 1 3. + <_> + + <_> + 16 14 7 9 -1. + <_> + 16 17 7 3 3. + <_> + + <_> + 4 3 16 4 -1. + <_> + 12 3 8 4 2. + <_> + + <_> + 7 6 12 5 -1. + <_> + 7 6 6 5 2. + <_> + + <_> + 9 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 12 1 4 10 -1. + <_> + 12 1 2 10 2. + <_> + + <_> + 8 1 4 10 -1. + <_> + 10 1 2 10 2. + <_> + + <_> + 15 15 6 9 -1. + <_> + 15 18 6 3 3. + <_> + + <_> + 3 15 6 9 -1. + <_> + 3 18 6 3 3. + <_> + + <_> + 15 1 3 19 -1. + <_> + 16 1 1 19 3. + <_> + + <_> + 1 3 6 9 -1. + <_> + 3 3 2 9 3. + <_> + + <_> + 15 0 3 19 -1. + <_> + 16 0 1 19 3. + <_> + + <_> + 6 3 12 4 -1. + <_> + 12 3 6 4 2. + <_> + + <_> + 10 5 4 9 -1. + <_> + 10 5 2 9 2. + <_> + + <_> + 6 0 3 19 -1. + <_> + 7 0 1 19 3. + <_> + + <_> + 11 1 3 12 -1. + <_> + 11 7 3 6 2. + <_> + + <_> + 6 7 10 5 -1. + <_> + 11 7 5 5 2. + <_> + + <_> + 11 3 3 18 -1. + <_> + 12 3 1 18 3. + <_> + + <_> + 9 3 6 12 -1. + <_> + 11 3 2 12 3. + <_> + + <_> + 3 7 19 3 -1. + <_> + 3 8 19 1 3. + <_> + + <_> + 2 7 18 3 -1. + <_> + 2 8 18 1 3. + <_> + + <_> + 3 13 18 4 -1. + <_> + 12 13 9 2 2. + <_> + 3 15 9 2 2. + <_> + + <_> + 3 5 6 9 -1. + <_> + 5 5 2 9 3. + <_> + + <_> + 4 1 20 4 -1. + <_> + 14 1 10 2 2. + <_> + 4 3 10 2 2. + <_> + + <_> + 0 1 20 4 -1. + <_> + 0 1 10 2 2. + <_> + 10 3 10 2 2. + <_> + + <_> + 10 15 6 6 -1. + <_> + 10 15 3 6 2. + <_> + + <_> + 0 2 24 8 -1. + <_> + 8 2 8 8 3. + <_> + + <_> + 5 5 18 3 -1. + <_> + 5 6 18 1 3. + <_> + + <_> + 8 15 6 6 -1. + <_> + 11 15 3 6 2. + <_> + + <_> + 11 12 8 5 -1. + <_> + 11 12 4 5 2. + <_> + + <_> + 5 12 8 5 -1. + <_> + 9 12 4 5 2. + <_> + + <_> + 5 0 14 6 -1. + <_> + 5 2 14 2 3. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 10 7 5 12 -1. + <_> + 10 11 5 4 3. + <_> + + <_> + 7 9 8 14 -1. + <_> + 7 9 4 7 2. + <_> + 11 16 4 7 2. + <_> + + <_> + 1 5 22 6 -1. + <_> + 12 5 11 3 2. + <_> + 1 8 11 3 2. + <_> + + <_> + 0 5 6 6 -1. + <_> + 0 8 6 3 2. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 2 18 19 3 -1. + <_> + 2 19 19 1 3. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 1 17 18 3 -1. + <_> + 1 18 18 1 3. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 0 0 24 3 -1. + <_> + 0 1 24 1 3. + <_> + + <_> + 5 0 14 4 -1. + <_> + 5 2 14 2 2. + <_> + + <_> + 6 14 9 6 -1. + <_> + 6 16 9 2 3. + <_> + + <_> + 14 13 6 9 -1. + <_> + 14 16 6 3 3. + <_> + + <_> + 5 20 13 4 -1. + <_> + 5 22 13 2 2. + <_> + + <_> + 9 9 6 12 -1. + <_> + 9 13 6 4 3. + <_> + + <_> + 1 10 21 3 -1. + <_> + 8 10 7 3 3. + <_> + + <_> + 8 8 9 6 -1. + <_> + 11 8 3 6 3. + <_> + + <_> + 3 10 9 7 -1. + <_> + 6 10 3 7 3. + <_> + + <_> + 12 10 10 8 -1. + <_> + 17 10 5 4 2. + <_> + 12 14 5 4 2. + <_> + + <_> + 0 15 24 3 -1. + <_> + 8 15 8 3 3. + <_> + + <_> + 8 5 9 6 -1. + <_> + 8 7 9 2 3. + <_> + + <_> + 4 13 6 9 -1. + <_> + 4 16 6 3 3. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 9 12 6 6 -1. + <_> + 9 15 6 3 2. + <_> + + <_> + 9 9 14 10 -1. + <_> + 16 9 7 5 2. + <_> + 9 14 7 5 2. + <_> + + <_> + 1 9 14 10 -1. + <_> + 1 9 7 5 2. + <_> + 8 14 7 5 2. + <_> + + <_> + 8 7 9 17 -1. + <_> + 11 7 3 17 3. + <_> + + <_> + 3 4 6 20 -1. + <_> + 3 4 3 10 2. + <_> + 6 14 3 10 2. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 8 5 4 2. + <_> + + <_> + 10 7 4 9 -1. + <_> + 12 7 2 9 2. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 3 8 6 16 -1. + <_> + 3 8 3 8 2. + <_> + 6 16 3 8 2. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 3 17 9 4 -1. + <_> + 3 19 9 2 2. + <_> + + <_> + 10 1 9 6 -1. + <_> + 13 1 3 6 3. + <_> + + <_> + 5 7 4 10 -1. + <_> + 5 12 4 5 2. + <_> + + <_> + 7 5 12 6 -1. + <_> + 11 5 4 6 3. + <_> + + <_> + 6 4 9 8 -1. + <_> + 9 4 3 8 3. + <_> + + <_> + 12 16 10 8 -1. + <_> + 17 16 5 4 2. + <_> + 12 20 5 4 2. + <_> + + <_> + 2 16 10 8 -1. + <_> + 2 16 5 4 2. + <_> + 7 20 5 4 2. + <_> + + <_> + 0 0 24 4 -1. + <_> + 12 0 12 2 2. + <_> + 0 2 12 2 2. + <_> + + <_> + 0 6 9 6 -1. + <_> + 0 8 9 2 3. + <_> + + <_> + 0 4 24 6 -1. + <_> + 12 4 12 3 2. + <_> + 0 7 12 3 2. + <_> + + <_> + 5 0 11 4 -1. + <_> + 5 2 11 2 2. + <_> + + <_> + 1 1 22 4 -1. + <_> + 12 1 11 2 2. + <_> + 1 3 11 2 2. + <_> + + <_> + 9 6 6 18 -1. + <_> + 9 15 6 9 2. + <_> + + <_> + 2 9 20 4 -1. + <_> + 2 11 20 2 2. + <_> + + <_> + 5 2 14 14 -1. + <_> + 5 9 14 7 2. + <_> + + <_> + 4 2 16 6 -1. + <_> + 4 5 16 3 2. + <_> + + <_> + 2 3 19 3 -1. + <_> + 2 4 19 1 3. + <_> + + <_> + 7 1 10 4 -1. + <_> + 7 3 10 2 2. + <_> + + <_> + 0 9 4 15 -1. + <_> + 0 14 4 5 3. + <_> + + <_> + 2 10 21 3 -1. + <_> + 2 11 21 1 3. + <_> + + <_> + 3 0 6 6 -1. + <_> + 6 0 3 6 2. + <_> + + <_> + 6 4 14 9 -1. + <_> + 6 7 14 3 3. + <_> + + <_> + 9 1 6 9 -1. + <_> + 11 1 2 9 3. + <_> + + <_> + 15 8 9 9 -1. + <_> + 15 11 9 3 3. + <_> + + <_> + 8 0 4 21 -1. + <_> + 8 7 4 7 3. + <_> + + <_> + 3 22 19 2 -1. + <_> + 3 23 19 1 2. + <_> + + <_> + 2 15 20 3 -1. + <_> + 2 16 20 1 3. + <_> + + <_> + 19 0 4 13 -1. + <_> + 19 0 2 13 2. + <_> + + <_> + 1 7 8 8 -1. + <_> + 1 11 8 4 2. + <_> + + <_> + 14 14 6 9 -1. + <_> + 14 17 6 3 3. + <_> + + <_> + 4 14 6 9 -1. + <_> + 4 17 6 3 3. + <_> + + <_> + 14 5 4 10 -1. + <_> + 14 5 2 10 2. + <_> + + <_> + 6 5 4 10 -1. + <_> + 8 5 2 10 2. + <_> + + <_> + 14 5 6 6 -1. + <_> + 14 8 6 3 2. + <_> + + <_> + 4 5 6 6 -1. + <_> + 4 8 6 3 2. + <_> + + <_> + 0 2 24 21 -1. + <_> + 8 2 8 21 3. + <_> + + <_> + 1 2 6 13 -1. + <_> + 3 2 2 13 3. + <_> + + <_> + 20 0 4 21 -1. + <_> + 20 0 2 21 2. + <_> + + <_> + 0 4 4 20 -1. + <_> + 2 4 2 20 2. + <_> + + <_> + 8 16 9 6 -1. + <_> + 8 18 9 2 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 16 12 7 9 -1. + <_> + 16 15 7 3 3. + <_> + + <_> + 5 21 14 3 -1. + <_> + 12 21 7 3 2. + <_> + + <_> + 11 5 6 9 -1. + <_> + 11 5 3 9 2. + <_> + + <_> + 10 5 4 10 -1. + <_> + 12 5 2 10 2. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 7 5 6 9 -1. + <_> + 10 5 3 9 2. + <_> + + <_> + 14 14 10 4 -1. + <_> + 14 16 10 2 2. + <_> + + <_> + 5 5 14 14 -1. + <_> + 5 5 7 7 2. + <_> + 12 12 7 7 2. + <_> + + <_> + 12 8 12 6 -1. + <_> + 18 8 6 3 2. + <_> + 12 11 6 3 2. + <_> + + <_> + 6 6 12 12 -1. + <_> + 6 6 6 6 2. + <_> + 12 12 6 6 2. + <_> + + <_> + 11 13 6 10 -1. + <_> + 13 13 2 10 3. + <_> + + <_> + 1 10 20 8 -1. + <_> + 1 10 10 4 2. + <_> + 11 14 10 4 2. + <_> + + <_> + 15 13 9 6 -1. + <_> + 15 15 9 2 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 9 3 6 3 3. + <_> + + <_> + 10 1 5 14 -1. + <_> + 10 8 5 7 2. + <_> + + <_> + 3 4 16 6 -1. + <_> + 3 6 16 2 3. + <_> + + <_> + 16 3 8 9 -1. + <_> + 16 6 8 3 3. + <_> + + <_> + 7 13 6 10 -1. + <_> + 9 13 2 10 3. + <_> + + <_> + 15 13 9 6 -1. + <_> + 15 15 9 2 3. + <_> + + <_> + 0 13 9 6 -1. + <_> + 0 15 9 2 3. + <_> + + <_> + 13 16 9 6 -1. + <_> + 13 18 9 2 3. + <_> + + <_> + 2 16 9 6 -1. + <_> + 2 18 9 2 3. + <_> + + <_> + 5 16 18 3 -1. + <_> + 5 17 18 1 3. + <_> + + <_> + 1 16 18 3 -1. + <_> + 1 17 18 1 3. + <_> + + <_> + 5 0 18 3 -1. + <_> + 5 1 18 1 3. + <_> + + <_> + 1 1 19 2 -1. + <_> + 1 2 19 1 2. + <_> + + <_> + 14 2 6 11 -1. + <_> + 16 2 2 11 3. + <_> + + <_> + 4 15 15 6 -1. + <_> + 9 15 5 6 3. + <_> + + <_> + 14 2 6 11 -1. + <_> + 16 2 2 11 3. + <_> + + <_> + 4 2 6 11 -1. + <_> + 6 2 2 11 3. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 1 2 22 4 -1. + <_> + 1 2 11 2 2. + <_> + 12 4 11 2 2. + <_> + + <_> + 2 0 21 12 -1. + <_> + 9 0 7 12 3. + <_> + + <_> + 0 12 18 3 -1. + <_> + 0 13 18 1 3. + <_> + + <_> + 12 2 6 9 -1. + <_> + 14 2 2 9 3. + <_> + + <_> + 3 10 18 3 -1. + <_> + 3 11 18 1 3. + <_> + + <_> + 16 3 8 9 -1. + <_> + 16 6 8 3 3. + <_> + + <_> + 3 7 18 3 -1. + <_> + 3 8 18 1 3. + <_> + + <_> + 9 11 6 9 -1. + <_> + 11 11 2 9 3. + <_> + + <_> + 9 8 6 9 -1. + <_> + 11 8 2 9 3. + <_> + + <_> + 15 0 2 18 -1. + <_> + 15 0 1 18 2. + <_> + + <_> + 7 0 2 18 -1. + <_> + 8 0 1 18 2. + <_> + + <_> + 17 3 7 9 -1. + <_> + 17 6 7 3 3. + <_> + + <_> + 3 18 9 6 -1. + <_> + 3 20 9 2 3. + <_> + + <_> + 3 18 21 3 -1. + <_> + 3 19 21 1 3. + <_> + + <_> + 0 3 7 9 -1. + <_> + 0 6 7 3 3. + <_> + + <_> + 2 7 22 3 -1. + <_> + 2 8 22 1 3. + <_> + + <_> + 0 3 24 16 -1. + <_> + 0 3 12 8 2. + <_> + 12 11 12 8 2. + <_> + + <_> + 13 17 9 4 -1. + <_> + 13 19 9 2 2. + <_> + + <_> + 5 5 12 8 -1. + <_> + 5 5 6 4 2. + <_> + 11 9 6 4 2. + <_> + + <_> + 5 6 14 6 -1. + <_> + 12 6 7 3 2. + <_> + 5 9 7 3 2. + <_> + + <_> + 5 16 14 6 -1. + <_> + 5 16 7 3 2. + <_> + 12 19 7 3 2. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 0 5 6 3 3. + <_> + + <_> + 3 4 20 10 -1. + <_> + 13 4 10 5 2. + <_> + 3 9 10 5 2. + <_> + + <_> + 2 13 9 8 -1. + <_> + 5 13 3 8 3. + <_> + + <_> + 2 1 21 15 -1. + <_> + 9 1 7 15 3. + <_> + + <_> + 5 12 14 8 -1. + <_> + 12 12 7 8 2. + <_> + + <_> + 6 7 12 4 -1. + <_> + 6 7 6 4 2. + <_> + + <_> + 6 5 9 6 -1. + <_> + 9 5 3 6 3. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 5 11 6 6 -1. + <_> + 8 11 3 6 2. + <_> + + <_> + 6 4 18 2 -1. + <_> + 6 5 18 1 2. + <_> + + <_> + 0 2 6 11 -1. + <_> + 2 2 2 11 3. + <_> + + <_> + 18 0 6 15 -1. + <_> + 20 0 2 15 3. + <_> + + <_> + 0 0 6 13 -1. + <_> + 2 0 2 13 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 3 13 18 4 -1. + <_> + 12 13 9 4 2. + <_> + + <_> + 9 7 10 4 -1. + <_> + 9 7 5 4 2. + <_> + + <_> + 5 8 12 3 -1. + <_> + 11 8 6 3 2. + <_> + + <_> + 4 14 19 3 -1. + <_> + 4 15 19 1 3. + <_> + + <_> + 10 0 4 20 -1. + <_> + 10 10 4 10 2. + <_> + + <_> + 8 15 9 6 -1. + <_> + 8 17 9 2 3. + <_> + + <_> + 2 9 15 4 -1. + <_> + 7 9 5 4 3. + <_> + + <_> + 8 4 12 7 -1. + <_> + 12 4 4 7 3. + <_> + + <_> + 0 10 6 9 -1. + <_> + 0 13 6 3 3. + <_> + + <_> + 18 5 6 9 -1. + <_> + 18 8 6 3 3. + <_> + + <_> + 0 18 16 6 -1. + <_> + 0 18 8 3 2. + <_> + 8 21 8 3 2. + <_> + + <_> + 9 18 14 6 -1. + <_> + 16 18 7 3 2. + <_> + 9 21 7 3 2. + <_> + + <_> + 1 20 20 4 -1. + <_> + 1 20 10 2 2. + <_> + 11 22 10 2 2. + <_> + + <_> + 2 8 20 6 -1. + <_> + 12 8 10 3 2. + <_> + 2 11 10 3 2. + <_> + + <_> + 7 8 6 9 -1. + <_> + 9 8 2 9 3. + <_> + + <_> + 8 5 12 8 -1. + <_> + 12 5 4 8 3. + <_> + + <_> + 4 5 12 8 -1. + <_> + 8 5 4 8 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 2 0 6 16 -1. + <_> + 4 0 2 16 3. + <_> + + <_> + 15 4 6 12 -1. + <_> + 15 8 6 4 3. + <_> + + <_> + 3 4 6 12 -1. + <_> + 3 8 6 4 3. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 4 0 15 22 -1. + <_> + 4 11 15 11 2. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 0 12 9 6 -1. + <_> + 0 14 9 2 3. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 10 0 8 10 -1. + <_> + 14 0 4 5 2. + <_> + 10 5 4 5 2. + <_> + + <_> + 1 0 4 16 -1. + <_> + 3 0 2 16 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 10 12 4 10 -1. + <_> + 10 17 4 5 2. + <_> + + <_> + 8 4 10 6 -1. + <_> + 8 6 10 2 3. + <_> + + <_> + 3 22 18 2 -1. + <_> + 12 22 9 2 2. + <_> + + <_> + 7 7 11 6 -1. + <_> + 7 9 11 2 3. + <_> + + <_> + 0 0 12 10 -1. + <_> + 0 0 6 5 2. + <_> + 6 5 6 5 2. + <_> + + <_> + 10 1 12 6 -1. + <_> + 16 1 6 3 2. + <_> + 10 4 6 3 2. + <_> + + <_> + 7 16 9 4 -1. + <_> + 7 18 9 2 2. + <_> + + <_> + 5 7 15 16 -1. + <_> + 10 7 5 16 3. + <_> + + <_> + 5 10 12 13 -1. + <_> + 11 10 6 13 2. + <_> + + <_> + 6 2 12 6 -1. + <_> + 12 2 6 3 2. + <_> + 6 5 6 3 2. + <_> + + <_> + 3 9 12 9 -1. + <_> + 3 12 12 3 3. + <_> + + <_> + 16 2 8 6 -1. + <_> + 16 5 8 3 2. + <_> + + <_> + 0 2 8 6 -1. + <_> + 0 5 8 3 2. + <_> + + <_> + 0 3 24 11 -1. + <_> + 0 3 12 11 2. + <_> + + <_> + 0 13 8 10 -1. + <_> + 0 13 4 5 2. + <_> + 4 18 4 5 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 10 2 4 21 -1. + <_> + 10 9 4 7 3. + <_> + + <_> + 4 4 15 9 -1. + <_> + 4 7 15 3 3. + <_> + + <_> + 0 1 24 6 -1. + <_> + 8 1 8 6 3. + <_> + + <_> + 9 6 5 16 -1. + <_> + 9 14 5 8 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 6 5 3 12 -1. + <_> + 6 11 3 6 2. + <_> + + <_> + 11 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 5 6 9 8 -1. + <_> + 8 6 3 8 3. + <_> + + <_> + 4 3 20 2 -1. + <_> + 4 4 20 1 2. + <_> + + <_> + 2 10 18 3 -1. + <_> + 8 10 6 3 3. + <_> + + <_> + 7 15 10 6 -1. + <_> + 7 17 10 2 3. + <_> + + <_> + 1 4 4 18 -1. + <_> + 1 4 2 9 2. + <_> + 3 13 2 9 2. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 5 0 6 9 -1. + <_> + 7 0 2 9 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 6 7 9 6 -1. + <_> + 9 7 3 6 3. + <_> + + <_> + 3 0 18 2 -1. + <_> + 3 1 18 1 2. + <_> + + <_> + 0 10 20 4 -1. + <_> + 0 10 10 2 2. + <_> + 10 12 10 2 2. + <_> + + <_> + 10 2 4 12 -1. + <_> + 10 8 4 6 2. + <_> + + <_> + 6 5 6 12 -1. + <_> + 6 5 3 6 2. + <_> + 9 11 3 6 2. + <_> + + <_> + 6 0 18 22 -1. + <_> + 15 0 9 11 2. + <_> + 6 11 9 11 2. + <_> + + <_> + 0 0 18 22 -1. + <_> + 0 0 9 11 2. + <_> + 9 11 9 11 2. + <_> + + <_> + 18 2 6 11 -1. + <_> + 20 2 2 11 3. + <_> + + <_> + 0 2 6 11 -1. + <_> + 2 2 2 11 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 0 0 20 3 -1. + <_> + 0 1 20 1 3. + <_> + + <_> + 2 2 20 2 -1. + <_> + 2 3 20 1 2. + <_> + + <_> + 1 10 18 2 -1. + <_> + 1 11 18 1 2. + <_> + + <_> + 18 7 6 9 -1. + <_> + 18 10 6 3 3. + <_> + + <_> + 0 0 22 9 -1. + <_> + 0 3 22 3 3. + <_> + + <_> + 17 3 6 9 -1. + <_> + 17 6 6 3 3. + <_> + + <_> + 0 7 6 9 -1. + <_> + 0 10 6 3 3. + <_> + + <_> + 0 6 24 6 -1. + <_> + 0 8 24 2 3. + <_> + + <_> + 0 2 6 10 -1. + <_> + 2 2 2 10 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 15 0 6 9 -1. + <_> + 17 0 2 9 3. + <_> + + <_> + 3 0 6 9 -1. + <_> + 5 0 2 9 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 15 14 9 6 -1. + <_> + 15 16 9 2 3. + <_> + + <_> + 0 15 23 6 -1. + <_> + 0 17 23 2 3. + <_> + + <_> + 5 15 18 3 -1. + <_> + 5 16 18 1 3. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 3 7 15 6 -1. + <_> + 8 7 5 6 3. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 5 0 6 12 -1. + <_> + 8 0 3 12 2. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 8 5 6 9 -1. + <_> + 10 5 2 9 3. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 5 7 12 4 -1. + <_> + 11 7 6 4 2. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 7 8 8 10 -1. + <_> + 7 8 4 5 2. + <_> + 11 13 4 5 2. + <_> + + <_> + 11 10 6 14 -1. + <_> + 14 10 3 7 2. + <_> + 11 17 3 7 2. + <_> + + <_> + 9 5 6 19 -1. + <_> + 12 5 3 19 2. + <_> + + <_> + 6 12 12 6 -1. + <_> + 12 12 6 3 2. + <_> + 6 15 6 3 2. + <_> + + <_> + 1 9 18 6 -1. + <_> + 1 9 9 3 2. + <_> + 10 12 9 3 2. + <_> + + <_> + 16 14 8 10 -1. + <_> + 20 14 4 5 2. + <_> + 16 19 4 5 2. + <_> + + <_> + 0 9 22 8 -1. + <_> + 0 9 11 4 2. + <_> + 11 13 11 4 2. + <_> + + <_> + 8 18 12 6 -1. + <_> + 14 18 6 3 2. + <_> + 8 21 6 3 2. + <_> + + <_> + 0 6 20 18 -1. + <_> + 0 6 10 9 2. + <_> + 10 15 10 9 2. + <_> + + <_> + 3 6 20 12 -1. + <_> + 13 6 10 6 2. + <_> + 3 12 10 6 2. + <_> + + <_> + 0 16 10 8 -1. + <_> + 0 16 5 4 2. + <_> + 5 20 5 4 2. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 0 11 19 3 -1. + <_> + 0 12 19 1 3. + <_> + + <_> + 14 6 6 9 -1. + <_> + 14 9 6 3 3. + <_> + + <_> + 1 7 22 4 -1. + <_> + 1 7 11 2 2. + <_> + 12 9 11 2 2. + <_> + + <_> + 13 6 7 12 -1. + <_> + 13 10 7 4 3. + <_> + + <_> + 4 7 11 9 -1. + <_> + 4 10 11 3 3. + <_> + + <_> + 12 10 10 8 -1. + <_> + 17 10 5 4 2. + <_> + 12 14 5 4 2. + <_> + + <_> + 2 12 9 7 -1. + <_> + 5 12 3 7 3. + <_> + + <_> + 16 14 6 9 -1. + <_> + 16 17 6 3 3. + <_> + + <_> + 3 12 6 12 -1. + <_> + 3 16 6 4 3. + <_> + + <_> + 14 13 6 6 -1. + <_> + 14 16 6 3 2. + <_> + + <_> + 8 0 6 9 -1. + <_> + 10 0 2 9 3. + <_> + + <_> + 9 1 6 23 -1. + <_> + 11 1 2 23 3. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 4 17 18 3 -1. + <_> + 4 18 18 1 3. + <_> + + <_> + 5 2 13 14 -1. + <_> + 5 9 13 7 2. + <_> + + <_> + 15 0 8 12 -1. + <_> + 19 0 4 6 2. + <_> + 15 6 4 6 2. + <_> + + <_> + 0 0 8 12 -1. + <_> + 0 0 4 6 2. + <_> + 4 6 4 6 2. + <_> + + <_> + 8 2 8 7 -1. + <_> + 8 2 4 7 2. + <_> + + <_> + 1 1 6 9 -1. + <_> + 3 1 2 9 3. + <_> + + <_> + 14 8 6 12 -1. + <_> + 17 8 3 6 2. + <_> + 14 14 3 6 2. + <_> + + <_> + 4 8 6 12 -1. + <_> + 4 8 3 6 2. + <_> + 7 14 3 6 2. + <_> + + <_> + 16 5 5 15 -1. + <_> + 16 10 5 5 3. + <_> + + <_> + 3 5 5 15 -1. + <_> + 3 10 5 5 3. + <_> + + <_> + 18 4 6 9 -1. + <_> + 18 7 6 3 3. + <_> + + <_> + 1 7 6 15 -1. + <_> + 1 12 6 5 3. + <_> + + <_> + 11 15 12 8 -1. + <_> + 17 15 6 4 2. + <_> + 11 19 6 4 2. + <_> + + <_> + 0 2 24 4 -1. + <_> + 0 2 12 2 2. + <_> + 12 4 12 2 2. + <_> + + <_> + 15 1 2 19 -1. + <_> + 15 1 1 19 2. + <_> + + <_> + 7 1 2 19 -1. + <_> + 8 1 1 19 2. + <_> + + <_> + 22 1 2 20 -1. + <_> + 22 1 1 20 2. + <_> + + <_> + 0 1 2 20 -1. + <_> + 1 1 1 20 2. + <_> + + <_> + 18 11 6 12 -1. + <_> + 20 11 2 12 3. + <_> + + <_> + 0 11 6 12 -1. + <_> + 2 11 2 12 3. + <_> + + <_> + 3 6 18 14 -1. + <_> + 3 13 18 7 2. + <_> + + <_> + 6 10 7 8 -1. + <_> + 6 14 7 4 2. + <_> + + <_> + 7 9 12 12 -1. + <_> + 7 13 12 4 3. + <_> + + <_> + 2 18 18 5 -1. + <_> + 11 18 9 5 2. + <_> + + <_> + 4 21 20 3 -1. + <_> + 4 22 20 1 3. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 12 3 6 2. + <_> + 12 18 3 6 2. + <_> + + <_> + 4 6 18 3 -1. + <_> + 4 7 18 1 3. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 18 4 6 9 -1. + <_> + 18 7 6 3 3. + <_> + + <_> + 2 12 9 6 -1. + <_> + 2 14 9 2 3. + <_> + + <_> + 4 14 18 4 -1. + <_> + 13 14 9 2 2. + <_> + 4 16 9 2 2. + <_> + + <_> + 7 7 6 14 -1. + <_> + 7 7 3 7 2. + <_> + 10 14 3 7 2. + <_> + + <_> + 7 13 12 6 -1. + <_> + 13 13 6 3 2. + <_> + 7 16 6 3 2. + <_> + + <_> + 6 7 12 9 -1. + <_> + 10 7 4 9 3. + <_> + + <_> + 12 12 6 6 -1. + <_> + 12 12 3 6 2. + <_> + + <_> + 0 2 4 10 -1. + <_> + 0 7 4 5 2. + <_> + + <_> + 8 0 9 6 -1. + <_> + 11 0 3 6 3. + <_> + + <_> + 2 9 12 6 -1. + <_> + 2 12 12 3 2. + <_> + + <_> + 13 10 6 9 -1. + <_> + 13 13 6 3 3. + <_> + + <_> + 5 10 6 9 -1. + <_> + 5 13 6 3 3. + <_> + + <_> + 9 15 9 6 -1. + <_> + 9 17 9 2 3. + <_> + + <_> + 5 16 12 6 -1. + <_> + 5 19 12 3 2. + <_> + + <_> + 3 2 20 3 -1. + <_> + 3 3 20 1 3. + <_> + + <_> + 2 5 12 6 -1. + <_> + 6 5 4 6 3. + <_> + + <_> + 11 0 3 24 -1. + <_> + 12 0 1 24 3. + <_> + + <_> + 3 16 15 4 -1. + <_> + 8 16 5 4 3. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 18 6 6 2. + <_> + + <_> + 1 15 12 8 -1. + <_> + 1 15 6 4 2. + <_> + 7 19 6 4 2. + <_> + + <_> + 15 10 8 14 -1. + <_> + 19 10 4 7 2. + <_> + 15 17 4 7 2. + <_> + + <_> + 1 9 8 14 -1. + <_> + 1 9 4 7 2. + <_> + 5 16 4 7 2. + <_> + + <_> + 9 11 9 10 -1. + <_> + 9 16 9 5 2. + <_> + + <_> + 6 7 12 6 -1. + <_> + 6 9 12 2 3. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 7 8 9 7 -1. + <_> + 10 8 3 7 3. + <_> + + <_> + 10 4 8 10 -1. + <_> + 14 4 4 5 2. + <_> + 10 9 4 5 2. + <_> + + <_> + 4 6 6 9 -1. + <_> + 4 9 6 3 3. + <_> + + <_> + 0 6 24 12 -1. + <_> + 8 6 8 12 3. + <_> + + <_> + 3 7 6 14 -1. + <_> + 6 7 3 14 2. + <_> + + <_> + 19 8 5 8 -1. + <_> + 19 12 5 4 2. + <_> + + <_> + 0 8 5 8 -1. + <_> + 0 12 5 4 2. + <_> + + <_> + 17 3 6 6 -1. + <_> + 17 6 6 3 2. + <_> + + <_> + 1 3 6 6 -1. + <_> + 1 6 6 3 2. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 0 5 6 3 3. + <_> + + <_> + 3 3 18 6 -1. + <_> + 3 5 18 2 3. + <_> + + <_> + 2 3 9 6 -1. + <_> + 2 5 9 2 3. + <_> + + <_> + 9 3 10 8 -1. + <_> + 14 3 5 4 2. + <_> + 9 7 5 4 2. + <_> + + <_> + 5 3 10 8 -1. + <_> + 5 3 5 4 2. + <_> + 10 7 5 4 2. + <_> + + <_> + 10 11 6 12 -1. + <_> + 10 11 3 12 2. + <_> + + <_> + 8 11 6 11 -1. + <_> + 11 11 3 11 2. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 8 5 4 2. + <_> + + <_> + 9 6 6 7 -1. + <_> + 12 6 3 7 2. + <_> + + <_> + 5 18 18 3 -1. + <_> + 5 19 18 1 3. + <_> + + <_> + 8 4 6 9 -1. + <_> + 10 4 2 9 3. + <_> + + <_> + 8 1 9 7 -1. + <_> + 11 1 3 7 3. + <_> + + <_> + 6 11 6 6 -1. + <_> + 9 11 3 6 2. + <_> + + <_> + 14 12 4 11 -1. + <_> + 14 12 2 11 2. + <_> + + <_> + 6 12 4 11 -1. + <_> + 8 12 2 11 2. + <_> + + <_> + 8 0 12 18 -1. + <_> + 12 0 4 18 3. + <_> + + <_> + 2 12 10 5 -1. + <_> + 7 12 5 5 2. + <_> + + <_> + 2 20 22 3 -1. + <_> + 2 21 22 1 3. + <_> + + <_> + 0 4 2 20 -1. + <_> + 1 4 1 20 2. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 10 10 2 2. + <_> + + <_> + 6 7 8 10 -1. + <_> + 6 7 4 5 2. + <_> + 10 12 4 5 2. + <_> + + <_> + 14 0 6 14 -1. + <_> + 17 0 3 7 2. + <_> + 14 7 3 7 2. + <_> + + <_> + 4 11 5 8 -1. + <_> + 4 15 5 4 2. + <_> + + <_> + 2 0 20 9 -1. + <_> + 2 3 20 3 3. + <_> + + <_> + 6 7 12 8 -1. + <_> + 6 7 6 4 2. + <_> + 12 11 6 4 2. + <_> + + <_> + 9 17 6 6 -1. + <_> + 9 20 6 3 2. + <_> + + <_> + 7 10 10 4 -1. + <_> + 7 12 10 2 2. + <_> + + <_> + 6 5 12 9 -1. + <_> + 10 5 4 9 3. + <_> + + <_> + 5 11 6 8 -1. + <_> + 8 11 3 8 2. + <_> + + <_> + 18 4 4 17 -1. + <_> + 18 4 2 17 2. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 18 4 4 17 -1. + <_> + 18 4 2 17 2. + <_> + + <_> + 2 4 4 17 -1. + <_> + 4 4 2 17 2. + <_> + + <_> + 5 18 19 3 -1. + <_> + 5 19 19 1 3. + <_> + + <_> + 11 0 2 18 -1. + <_> + 11 9 2 9 2. + <_> + + <_> + 15 4 2 18 -1. + <_> + 15 13 2 9 2. + <_> + + <_> + 7 4 2 18 -1. + <_> + 7 13 2 9 2. + <_> + + <_> + 7 11 10 8 -1. + <_> + 12 11 5 4 2. + <_> + 7 15 5 4 2. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 2 9 16 8 -1. + <_> + 2 9 8 4 2. + <_> + 10 13 8 4 2. + <_> + + <_> + 14 15 6 9 -1. + <_> + 14 18 6 3 3. + <_> + + <_> + 8 7 6 9 -1. + <_> + 10 7 2 9 3. + <_> + + <_> + 14 15 6 9 -1. + <_> + 14 18 6 3 3. + <_> + + <_> + 3 12 12 6 -1. + <_> + 3 14 12 2 3. + <_> + + <_> + 14 12 9 6 -1. + <_> + 14 14 9 2 3. + <_> + + <_> + 1 12 9 6 -1. + <_> + 1 14 9 2 3. + <_> + + <_> + 3 7 18 3 -1. + <_> + 3 8 18 1 3. + <_> + + <_> + 1 7 22 6 -1. + <_> + 1 9 22 2 3. + <_> + + <_> + 18 4 6 6 -1. + <_> + 18 7 6 3 2. + <_> + + <_> + 0 4 6 6 -1. + <_> + 0 7 6 3 2. + <_> + + <_> + 5 11 16 6 -1. + <_> + 5 14 16 3 2. + <_> + + <_> + 6 16 9 4 -1. + <_> + 6 18 9 2 2. + <_> + + <_> + 14 15 6 9 -1. + <_> + 14 18 6 3 3. + <_> + + <_> + 4 15 6 9 -1. + <_> + 4 18 6 3 3. + <_> + + <_> + 15 1 6 23 -1. + <_> + 17 1 2 23 3. + <_> + + <_> + 0 21 24 3 -1. + <_> + 8 21 8 3 3. + <_> + + <_> + 0 20 24 4 -1. + <_> + 8 20 8 4 3. + <_> + + <_> + 3 1 6 23 -1. + <_> + 5 1 2 23 3. + <_> + + <_> + 3 17 18 3 -1. + <_> + 3 18 18 1 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 1 16 22 4 -1. + <_> + 12 16 11 2 2. + <_> + 1 18 11 2 2. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 2 10 21 3 -1. + <_> + 9 10 7 3 3. + <_> + + <_> + 2 18 12 6 -1. + <_> + 2 18 6 3 2. + <_> + 8 21 6 3 2. + <_> + + <_> + 0 5 24 4 -1. + <_> + 0 7 24 2 2. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 10 7 6 12 -1. + <_> + 10 13 6 6 2. + <_> + + <_> + 6 6 6 9 -1. + <_> + 8 6 2 9 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 9 7 6 9 -1. + <_> + 11 7 2 9 3. + <_> + + <_> + 2 1 20 3 -1. + <_> + 2 2 20 1 3. + <_> + + <_> + 1 18 12 6 -1. + <_> + 1 18 6 3 2. + <_> + 7 21 6 3 2. + <_> + + <_> + 13 2 4 13 -1. + <_> + 13 2 2 13 2. + <_> + + <_> + 6 7 12 4 -1. + <_> + 12 7 6 4 2. + <_> + + <_> + 10 1 4 13 -1. + <_> + 10 1 2 13 2. + <_> + + <_> + 6 0 3 18 -1. + <_> + 7 0 1 18 3. + <_> + + <_> + 14 3 10 5 -1. + <_> + 14 3 5 5 2. + <_> + + <_> + 6 15 12 8 -1. + <_> + 10 15 4 8 3. + <_> + + <_> + 9 10 6 9 -1. + <_> + 11 10 2 9 3. + <_> + + <_> + 8 3 4 9 -1. + <_> + 10 3 2 9 2. + <_> + + <_> + 17 0 6 14 -1. + <_> + 20 0 3 7 2. + <_> + 17 7 3 7 2. + <_> + + <_> + 1 0 6 14 -1. + <_> + 1 0 3 7 2. + <_> + 4 7 3 7 2. + <_> + + <_> + 14 0 6 16 -1. + <_> + 17 0 3 8 2. + <_> + 14 8 3 8 2. + <_> + + <_> + 7 4 4 10 -1. + <_> + 9 4 2 10 2. + <_> + + <_> + 3 17 18 6 -1. + <_> + 12 17 9 3 2. + <_> + 3 20 9 3 2. + <_> + + <_> + 1 20 22 4 -1. + <_> + 12 20 11 4 2. + <_> + + <_> + 14 3 10 5 -1. + <_> + 14 3 5 5 2. + <_> + + <_> + 0 3 10 5 -1. + <_> + 5 3 5 5 2. + <_> + + <_> + 12 6 12 16 -1. + <_> + 16 6 4 16 3. + <_> + + <_> + 0 6 12 16 -1. + <_> + 4 6 4 16 3. + <_> + + <_> + 10 9 5 15 -1. + <_> + 10 14 5 5 3. + <_> + + <_> + 1 18 21 2 -1. + <_> + 1 19 21 1 2. + <_> + + <_> + 15 0 9 6 -1. + <_> + 15 2 9 2 3. + <_> + + <_> + 6 1 12 4 -1. + <_> + 12 1 6 4 2. + <_> + + <_> + 6 0 12 12 -1. + <_> + 12 0 6 6 2. + <_> + 6 6 6 6 2. + <_> + + <_> + 8 10 8 12 -1. + <_> + 8 10 4 6 2. + <_> + 12 16 4 6 2. + <_> + + <_> + 14 16 10 8 -1. + <_> + 19 16 5 4 2. + <_> + 14 20 5 4 2. + <_> + + <_> + 0 16 10 8 -1. + <_> + 0 16 5 4 2. + <_> + 5 20 5 4 2. + <_> + + <_> + 10 12 12 5 -1. + <_> + 14 12 4 5 3. + <_> + + <_> + 6 16 10 8 -1. + <_> + 6 16 5 4 2. + <_> + 11 20 5 4 2. + <_> + + <_> + 7 6 12 6 -1. + <_> + 13 6 6 3 2. + <_> + 7 9 6 3 2. + <_> + + <_> + 9 6 4 18 -1. + <_> + 9 6 2 9 2. + <_> + 11 15 2 9 2. + <_> + + <_> + 10 9 6 14 -1. + <_> + 13 9 3 7 2. + <_> + 10 16 3 7 2. + <_> + + <_> + 8 9 6 14 -1. + <_> + 8 9 3 7 2. + <_> + 11 16 3 7 2. + <_> + + <_> + 7 4 11 12 -1. + <_> + 7 10 11 6 2. + <_> + + <_> + 4 8 6 16 -1. + <_> + 4 8 3 8 2. + <_> + 7 16 3 8 2. + <_> + + <_> + 17 3 4 21 -1. + <_> + 17 10 4 7 3. + <_> + + <_> + 3 3 4 21 -1. + <_> + 3 10 4 7 3. + <_> + + <_> + 10 1 8 18 -1. + <_> + 14 1 4 9 2. + <_> + 10 10 4 9 2. + <_> + + <_> + 2 5 16 8 -1. + <_> + 2 5 8 4 2. + <_> + 10 9 8 4 2. + <_> + + <_> + 3 6 18 12 -1. + <_> + 3 10 18 4 3. + <_> + + <_> + 4 10 16 12 -1. + <_> + 4 14 16 4 3. + <_> + + <_> + 15 4 8 20 -1. + <_> + 19 4 4 10 2. + <_> + 15 14 4 10 2. + <_> + + <_> + 7 2 9 6 -1. + <_> + 10 2 3 6 3. + <_> + + <_> + 15 4 8 20 -1. + <_> + 19 4 4 10 2. + <_> + 15 14 4 10 2. + <_> + + <_> + 1 4 8 20 -1. + <_> + 1 4 4 10 2. + <_> + 5 14 4 10 2. + <_> + + <_> + 11 8 8 14 -1. + <_> + 15 8 4 7 2. + <_> + 11 15 4 7 2. + <_> + + <_> + 5 8 8 14 -1. + <_> + 5 8 4 7 2. + <_> + 9 15 4 7 2. + <_> + + <_> + 10 13 5 8 -1. + <_> + 10 17 5 4 2. + <_> + + <_> + 4 13 7 9 -1. + <_> + 4 16 7 3 3. + <_> + + <_> + 0 13 24 10 -1. + <_> + 0 18 24 5 2. + <_> + + <_> + 4 2 8 11 -1. + <_> + 8 2 4 11 2. + <_> + + <_> + 10 2 8 16 -1. + <_> + 14 2 4 8 2. + <_> + 10 10 4 8 2. + <_> + + <_> + 0 2 24 6 -1. + <_> + 0 2 12 3 2. + <_> + 12 5 12 3 2. + <_> + + <_> + 6 0 12 9 -1. + <_> + 6 3 12 3 3. + <_> + + <_> + 1 2 12 12 -1. + <_> + 1 2 6 6 2. + <_> + 7 8 6 6 2. + <_> + + <_> + 18 5 6 9 -1. + <_> + 18 8 6 3 3. + <_> + + <_> + 4 3 8 10 -1. + <_> + 4 3 4 5 2. + <_> + 8 8 4 5 2. + <_> + + <_> + 6 21 18 3 -1. + <_> + 6 22 18 1 3. + <_> + + <_> + 1 10 18 2 -1. + <_> + 1 11 18 1 2. + <_> + + <_> + 1 10 22 3 -1. + <_> + 1 11 22 1 3. + <_> + + <_> + 2 8 12 9 -1. + <_> + 2 11 12 3 3. + <_> + + <_> + 12 8 12 6 -1. + <_> + 18 8 6 3 2. + <_> + 12 11 6 3 2. + <_> + + <_> + 0 8 12 6 -1. + <_> + 0 8 6 3 2. + <_> + 6 11 6 3 2. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 7 13 9 6 -1. + <_> + 7 15 9 2 3. + <_> + + <_> + 9 8 7 12 -1. + <_> + 9 14 7 6 2. + <_> + + <_> + 4 13 9 6 -1. + <_> + 7 13 3 6 3. + <_> + + <_> + 6 15 18 4 -1. + <_> + 12 15 6 4 3. + <_> + + <_> + 5 4 4 16 -1. + <_> + 7 4 2 16 2. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 8 15 6 9 -1. + <_> + 10 15 2 9 3. + <_> + + <_> + 9 11 12 10 -1. + <_> + 15 11 6 5 2. + <_> + 9 16 6 5 2. + <_> + + <_> + 3 6 14 6 -1. + <_> + 3 8 14 2 3. + <_> + + <_> + 4 2 17 8 -1. + <_> + 4 6 17 4 2. + <_> + + <_> + 6 2 12 21 -1. + <_> + 6 9 12 7 3. + <_> + + <_> + 8 1 9 9 -1. + <_> + 8 4 9 3 3. + <_> + + <_> + 0 7 24 3 -1. + <_> + 12 7 12 3 2. + <_> + + <_> + 11 6 9 10 -1. + <_> + 11 11 9 5 2. + <_> + + <_> + 2 11 18 3 -1. + <_> + 2 12 18 1 3. + <_> + + <_> + 8 16 9 4 -1. + <_> + 8 18 9 2 2. + <_> + + <_> + 0 0 9 6 -1. + <_> + 0 2 9 2 3. + <_> + + <_> + 0 11 24 6 -1. + <_> + 0 13 24 2 3. + <_> + + <_> + 2 9 20 6 -1. + <_> + 2 12 20 3 2. + <_> + + <_> + 4 5 16 12 -1. + <_> + 12 5 8 6 2. + <_> + 4 11 8 6 2. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 7 3 10 4 -1. + <_> + 7 5 10 2 2. + <_> + + <_> + 9 15 6 8 -1. + <_> + 9 19 6 4 2. + <_> + + <_> + 17 0 7 10 -1. + <_> + 17 5 7 5 2. + <_> + + <_> + 0 0 7 10 -1. + <_> + 0 5 7 5 2. + <_> + + <_> + 16 1 6 12 -1. + <_> + 19 1 3 6 2. + <_> + 16 7 3 6 2. + <_> + + <_> + 1 0 19 8 -1. + <_> + 1 4 19 4 2. + <_> + + <_> + 12 2 9 4 -1. + <_> + 12 4 9 2 2. + <_> + + <_> + 3 2 9 4 -1. + <_> + 3 4 9 2 2. + <_> + + <_> + 12 2 10 6 -1. + <_> + 12 4 10 2 3. + <_> + + <_> + 3 4 18 2 -1. + <_> + 12 4 9 2 2. + <_> + + <_> + 12 1 4 9 -1. + <_> + 12 1 2 9 2. + <_> + + <_> + 8 1 4 9 -1. + <_> + 10 1 2 9 2. + <_> + + <_> + 10 5 8 10 -1. + <_> + 14 5 4 5 2. + <_> + 10 10 4 5 2. + <_> + + <_> + 6 4 12 13 -1. + <_> + 10 4 4 13 3. + <_> + + <_> + 13 5 6 6 -1. + <_> + 13 5 3 6 2. + <_> + + <_> + 1 5 12 3 -1. + <_> + 7 5 6 3 2. + <_> + + <_> + 7 5 10 6 -1. + <_> + 7 7 10 2 3. + <_> + + <_> + 2 0 21 5 -1. + <_> + 9 0 7 5 3. + <_> + + <_> + 0 8 9 9 -1. + <_> + 0 11 9 3 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 0 3 6 7 -1. + <_> + 3 3 3 7 2. + <_> + + <_> + 9 18 12 6 -1. + <_> + 15 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 2 8 20 6 -1. + <_> + 2 8 10 3 2. + <_> + 12 11 10 3 2. + <_> + + <_> + 13 2 10 4 -1. + <_> + 13 4 10 2 2. + <_> + + <_> + 4 5 5 18 -1. + <_> + 4 11 5 6 3. + <_> + + <_> + 20 4 4 9 -1. + <_> + 20 4 2 9 2. + <_> + + <_> + 8 6 8 14 -1. + <_> + 8 13 8 7 2. + <_> + + <_> + 0 1 24 6 -1. + <_> + 12 1 12 3 2. + <_> + 0 4 12 3 2. + <_> + + <_> + 0 4 4 9 -1. + <_> + 2 4 2 9 2. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 3 17 16 6 -1. + <_> + 3 19 16 2 3. + <_> + + <_> + 13 6 6 9 -1. + <_> + 13 9 6 3 3. + <_> + + <_> + 5 6 14 6 -1. + <_> + 5 6 7 3 2. + <_> + 12 9 7 3 2. + <_> + + <_> + 13 5 8 10 -1. + <_> + 17 5 4 5 2. + <_> + 13 10 4 5 2. + <_> + + <_> + 2 2 20 3 -1. + <_> + 2 3 20 1 3. + <_> + + <_> + 9 2 9 6 -1. + <_> + 12 2 3 6 3. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 12 3 4 11 -1. + <_> + 12 3 2 11 2. + <_> + + <_> + 8 3 4 11 -1. + <_> + 10 3 2 11 2. + <_> + + <_> + 8 3 8 10 -1. + <_> + 12 3 4 5 2. + <_> + 8 8 4 5 2. + <_> + + <_> + 11 1 2 18 -1. + <_> + 12 1 1 18 2. + <_> + + <_> + 9 2 9 6 -1. + <_> + 12 2 3 6 3. + <_> + + <_> + 0 2 19 3 -1. + <_> + 0 3 19 1 3. + <_> + + <_> + 9 14 9 6 -1. + <_> + 9 16 9 2 3. + <_> + + <_> + 1 8 18 5 -1. + <_> + 7 8 6 5 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 13 6 4 15 -1. + <_> + 13 11 4 5 3. + <_> + + <_> + 1 5 18 3 -1. + <_> + 1 6 18 1 3. + <_> + + <_> + 9 7 14 6 -1. + <_> + 9 9 14 2 3. + <_> + + <_> + 2 16 18 3 -1. + <_> + 2 17 18 1 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 8 12 6 -1. + <_> + 0 8 6 3 2. + <_> + 6 11 6 3 2. + <_> + + <_> + 9 13 7 8 -1. + <_> + 9 17 7 4 2. + <_> + + <_> + 2 17 20 3 -1. + <_> + 2 18 20 1 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 4 0 15 4 -1. + <_> + 4 2 15 2 2. + <_> + + <_> + 17 2 6 6 -1. + <_> + 17 5 6 3 2. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 17 9 6 -1. + <_> + 0 19 9 2 3. + <_> + + <_> + 9 18 12 6 -1. + <_> + 15 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 3 15 6 9 -1. + <_> + 3 18 6 3 3. + <_> + + <_> + 16 13 8 10 -1. + <_> + 20 13 4 5 2. + <_> + 16 18 4 5 2. + <_> + + <_> + 0 14 24 4 -1. + <_> + 8 14 8 4 3. + <_> + + <_> + 13 18 6 6 -1. + <_> + 13 18 3 6 2. + <_> + + <_> + 0 13 8 10 -1. + <_> + 0 13 4 5 2. + <_> + 4 18 4 5 2. + <_> + + <_> + 0 14 24 6 -1. + <_> + 0 17 24 3 2. + <_> + + <_> + 5 2 12 8 -1. + <_> + 5 2 6 4 2. + <_> + 11 6 6 4 2. + <_> + + <_> + 8 9 9 6 -1. + <_> + 11 9 3 6 3. + <_> + + <_> + 4 3 16 4 -1. + <_> + 4 5 16 2 2. + <_> + + <_> + 10 2 4 10 -1. + <_> + 10 7 4 5 2. + <_> + + <_> + 8 4 5 8 -1. + <_> + 8 8 5 4 2. + <_> + + <_> + 11 5 9 12 -1. + <_> + 11 9 9 4 3. + <_> + + <_> + 4 5 9 12 -1. + <_> + 4 9 9 4 3. + <_> + + <_> + 14 6 6 9 -1. + <_> + 14 9 6 3 3. + <_> + + <_> + 2 4 20 12 -1. + <_> + 2 8 20 4 3. + <_> + + <_> + 4 4 17 16 -1. + <_> + 4 12 17 8 2. + <_> + + <_> + 8 7 7 6 -1. + <_> + 8 10 7 3 2. + <_> + + <_> + 1 9 23 2 -1. + <_> + 1 10 23 1 2. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 13 3 4 9 -1. + <_> + 13 3 2 9 2. + <_> + + <_> + 8 1 6 13 -1. + <_> + 10 1 2 13 3. + <_> + + <_> + 4 22 18 2 -1. + <_> + 4 23 18 1 2. + <_> + + <_> + 3 10 9 6 -1. + <_> + 6 10 3 6 3. + <_> + + <_> + 14 0 2 24 -1. + <_> + 14 0 1 24 2. + <_> + + <_> + 8 0 2 24 -1. + <_> + 9 0 1 24 2. + <_> + + <_> + 3 2 18 10 -1. + <_> + 9 2 6 10 3. + <_> + + <_> + 4 13 15 6 -1. + <_> + 9 13 5 6 3. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 9 1 4 11 -1. + <_> + 11 1 2 11 2. + <_> + + <_> + 9 7 10 4 -1. + <_> + 9 7 5 4 2. + <_> + + <_> + 7 0 10 18 -1. + <_> + 12 0 5 18 2. + <_> + + <_> + 12 1 6 16 -1. + <_> + 14 1 2 16 3. + <_> + + <_> + 6 1 6 16 -1. + <_> + 8 1 2 16 3. + <_> + + <_> + 18 2 6 6 -1. + <_> + 18 5 6 3 2. + <_> + + <_> + 3 5 18 2 -1. + <_> + 3 6 18 1 2. + <_> + + <_> + 18 2 6 6 -1. + <_> + 18 5 6 3 2. + <_> + + <_> + 0 2 6 6 -1. + <_> + 0 5 6 3 2. + <_> + + <_> + 13 11 11 6 -1. + <_> + 13 13 11 2 3. + <_> + + <_> + 5 7 10 4 -1. + <_> + 10 7 5 4 2. + <_> + + <_> + 11 9 10 7 -1. + <_> + 11 9 5 7 2. + <_> + + <_> + 3 9 10 7 -1. + <_> + 8 9 5 7 2. + <_> + + <_> + 16 4 6 6 -1. + <_> + 16 4 3 6 2. + <_> + + <_> + 5 6 10 8 -1. + <_> + 5 6 5 4 2. + <_> + 10 10 5 4 2. + <_> + + <_> + 7 21 16 3 -1. + <_> + 7 21 8 3 2. + <_> + + <_> + 1 21 16 3 -1. + <_> + 9 21 8 3 2. + <_> + + <_> + 2 5 22 14 -1. + <_> + 13 5 11 7 2. + <_> + 2 12 11 7 2. + <_> + + <_> + 3 10 8 10 -1. + <_> + 3 10 4 5 2. + <_> + 7 15 4 5 2. + <_> + + <_> + 17 0 6 12 -1. + <_> + 20 0 3 6 2. + <_> + 17 6 3 6 2. + <_> + + <_> + 5 2 6 18 -1. + <_> + 7 2 2 18 3. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 0 12 7 9 -1. + <_> + 0 15 7 3 3. + <_> + + <_> + 15 13 8 10 -1. + <_> + 19 13 4 5 2. + <_> + 15 18 4 5 2. + <_> + + <_> + 1 0 6 12 -1. + <_> + 1 0 3 6 2. + <_> + 4 6 3 6 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 1 13 8 10 -1. + <_> + 1 13 4 5 2. + <_> + 5 18 4 5 2. + <_> + + <_> + 3 21 19 2 -1. + <_> + 3 22 19 1 2. + <_> + + <_> + 6 3 4 13 -1. + <_> + 8 3 2 13 2. + <_> + + <_> + 5 10 18 3 -1. + <_> + 5 11 18 1 3. + <_> + + <_> + 9 3 5 12 -1. + <_> + 9 7 5 4 3. + <_> + + <_> + 11 2 4 15 -1. + <_> + 11 7 4 5 3. + <_> + + <_> + 4 1 16 4 -1. + <_> + 4 3 16 2 2. + <_> + + <_> + 6 0 18 3 -1. + <_> + 6 1 18 1 3. + <_> + + <_> + 5 1 10 8 -1. + <_> + 5 1 5 4 2. + <_> + 10 5 5 4 2. + <_> + + <_> + 11 18 12 6 -1. + <_> + 17 18 6 3 2. + <_> + 11 21 6 3 2. + <_> + + <_> + 5 15 12 3 -1. + <_> + 11 15 6 3 2. + <_> + + <_> + 1 10 22 4 -1. + <_> + 1 10 11 4 2. + <_> + + <_> + 7 9 9 6 -1. + <_> + 10 9 3 6 3. + <_> + + <_> + 6 11 12 5 -1. + <_> + 10 11 4 5 3. + <_> + + <_> + 6 7 10 7 -1. + <_> + 11 7 5 7 2. + <_> + + <_> + 11 2 8 10 -1. + <_> + 11 2 4 10 2. + <_> + + <_> + 5 2 8 10 -1. + <_> + 9 2 4 10 2. + <_> + + <_> + 6 4 18 6 -1. + <_> + 15 4 9 3 2. + <_> + 6 7 9 3 2. + <_> + + <_> + 0 5 10 9 -1. + <_> + 0 8 10 3 3. + <_> + + <_> + 2 7 21 6 -1. + <_> + 2 9 21 2 3. + <_> + + <_> + 0 4 22 16 -1. + <_> + 0 4 11 8 2. + <_> + 11 12 11 8 2. + <_> + + <_> + 9 0 6 22 -1. + <_> + 9 11 6 11 2. + <_> + + <_> + 9 1 3 12 -1. + <_> + 9 7 3 6 2. + <_> + + <_> + 12 0 12 18 -1. + <_> + 18 0 6 9 2. + <_> + 12 9 6 9 2. + <_> + + <_> + 0 0 12 18 -1. + <_> + 0 0 6 9 2. + <_> + 6 9 6 9 2. + <_> + + <_> + 1 1 22 4 -1. + <_> + 12 1 11 2 2. + <_> + 1 3 11 2 2. + <_> + + <_> + 3 0 18 4 -1. + <_> + 3 2 18 2 2. + <_> + + <_> + 2 5 22 6 -1. + <_> + 2 7 22 2 3. + <_> + + <_> + 5 0 6 9 -1. + <_> + 5 3 6 3 3. + <_> + + <_> + 10 14 6 9 -1. + <_> + 12 14 2 9 3. + <_> + + <_> + 8 14 6 9 -1. + <_> + 10 14 2 9 3. + <_> + + <_> + 5 18 18 3 -1. + <_> + 5 19 18 1 3. + <_> + + <_> + 6 0 6 13 -1. + <_> + 9 0 3 13 2. + <_> + + <_> + 7 4 12 4 -1. + <_> + 7 4 6 4 2. + <_> + + <_> + 5 2 12 6 -1. + <_> + 9 2 4 6 3. + <_> + + <_> + 4 1 18 3 -1. + <_> + 4 2 18 1 3. + <_> + + <_> + 0 8 6 12 -1. + <_> + 0 12 6 4 3. + <_> + + <_> + 9 15 6 9 -1. + <_> + 11 15 2 9 3. + <_> + + <_> + 9 10 6 13 -1. + <_> + 11 10 2 13 3. + <_> + + <_> + 6 17 18 2 -1. + <_> + 6 18 18 1 2. + <_> + + <_> + 9 4 6 9 -1. + <_> + 11 4 2 9 3. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 5 6 10 8 -1. + <_> + 5 6 5 4 2. + <_> + 10 10 5 4 2. + <_> + + <_> + 14 9 5 8 -1. + <_> + 14 13 5 4 2. + <_> + + <_> + 5 9 5 8 -1. + <_> + 5 13 5 4 2. + <_> + + <_> + 14 11 9 6 -1. + <_> + 14 13 9 2 3. + <_> + + <_> + 0 2 23 15 -1. + <_> + 0 7 23 5 3. + <_> + + <_> + 16 0 8 12 -1. + <_> + 16 6 8 6 2. + <_> + + <_> + 4 15 6 9 -1. + <_> + 4 18 6 3 3. + <_> + + <_> + 8 18 9 4 -1. + <_> + 8 20 9 2 2. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 13 11 11 6 -1. + <_> + 13 13 11 2 3. + <_> + + <_> + 0 11 11 6 -1. + <_> + 0 13 11 2 3. + <_> + + <_> + 0 9 24 6 -1. + <_> + 12 9 12 3 2. + <_> + 0 12 12 3 2. + <_> + + <_> + 6 16 8 8 -1. + <_> + 6 20 8 4 2. + <_> + + <_> + 10 16 14 6 -1. + <_> + 10 18 14 2 3. + <_> + + <_> + 1 1 21 3 -1. + <_> + 1 2 21 1 3. + <_> + + <_> + 0 2 24 3 -1. + <_> + 0 2 12 3 2. + <_> + + <_> + 2 15 8 5 -1. + <_> + 6 15 4 5 2. + <_> + + <_> + 2 11 21 3 -1. + <_> + 9 11 7 3 3. + <_> + + <_> + 1 18 12 6 -1. + <_> + 1 18 6 3 2. + <_> + 7 21 6 3 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 7 7 4 10 -1. + <_> + 7 12 4 5 2. + <_> + + <_> + 9 8 6 12 -1. + <_> + 9 12 6 4 3. + <_> + + <_> + 7 1 9 6 -1. + <_> + 10 1 3 6 3. + <_> + + <_> + 3 14 19 2 -1. + <_> + 3 15 19 1 2. + <_> + + <_> + 7 7 10 10 -1. + <_> + 7 7 5 5 2. + <_> + 12 12 5 5 2. + <_> + + <_> + 3 12 18 12 -1. + <_> + 3 12 9 12 2. + <_> + + <_> + 8 0 6 12 -1. + <_> + 10 0 2 12 3. + <_> + + <_> + 3 0 17 9 -1. + <_> + 3 3 17 3 3. + <_> + + <_> + 6 0 12 11 -1. + <_> + 10 0 4 11 3. + <_> + + <_> + 1 0 6 13 -1. + <_> + 4 0 3 13 2. + <_> + + <_> + 5 8 16 6 -1. + <_> + 5 11 16 3 2. + <_> + + <_> + 8 8 5 12 -1. + <_> + 8 14 5 6 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 2 0 20 3 -1. + <_> + 2 1 20 1 3. + <_> + + <_> + 4 6 15 10 -1. + <_> + 9 6 5 10 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 7 16 9 6 -1. + <_> + 7 18 9 2 3. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 4 0 6 9 -1. + <_> + 6 0 2 9 3. + <_> + + <_> + 17 1 6 16 -1. + <_> + 19 1 2 16 3. + <_> + + <_> + 1 1 6 16 -1. + <_> + 3 1 2 16 3. + <_> + + <_> + 14 13 6 9 -1. + <_> + 14 16 6 3 3. + <_> + + <_> + 0 0 6 9 -1. + <_> + 0 3 6 3 3. + <_> + + <_> + 9 5 6 6 -1. + <_> + 9 5 3 6 2. + <_> + + <_> + 3 10 9 6 -1. + <_> + 6 10 3 6 3. + <_> + + <_> + 14 7 3 16 -1. + <_> + 14 15 3 8 2. + <_> + + <_> + 4 10 14 12 -1. + <_> + 4 10 7 6 2. + <_> + 11 16 7 6 2. + <_> + + <_> + 7 6 12 6 -1. + <_> + 7 8 12 2 3. + <_> + + <_> + 7 2 4 20 -1. + <_> + 9 2 2 20 2. + <_> + + <_> + 14 13 6 9 -1. + <_> + 14 16 6 3 3. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 14 13 6 9 -1. + <_> + 14 16 6 3 3. + <_> + + <_> + 5 20 14 4 -1. + <_> + 5 22 14 2 2. + <_> + + <_> + 4 4 16 12 -1. + <_> + 4 10 16 6 2. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 3 0 21 4 -1. + <_> + 3 2 21 2 2. + <_> + + <_> + 4 13 6 9 -1. + <_> + 4 16 6 3 3. + <_> + + <_> + 16 16 5 8 -1. + <_> + 16 20 5 4 2. + <_> + + <_> + 4 0 16 16 -1. + <_> + 4 0 8 8 2. + <_> + 12 8 8 8 2. + <_> + + <_> + 6 6 14 6 -1. + <_> + 13 6 7 3 2. + <_> + 6 9 7 3 2. + <_> + + <_> + 10 5 4 15 -1. + <_> + 10 10 4 5 3. + <_> + + <_> + 9 15 12 8 -1. + <_> + 15 15 6 4 2. + <_> + 9 19 6 4 2. + <_> + + <_> + 6 7 12 4 -1. + <_> + 12 7 6 4 2. + <_> + + <_> + 5 6 14 6 -1. + <_> + 12 6 7 3 2. + <_> + 5 9 7 3 2. + <_> + + <_> + 3 6 18 10 -1. + <_> + 3 6 9 5 2. + <_> + 12 11 9 5 2. + <_> + + <_> + 6 0 18 21 -1. + <_> + 12 0 6 21 3. + <_> + + <_> + 0 0 24 21 -1. + <_> + 8 0 8 21 3. + <_> + + <_> + 6 18 18 3 -1. + <_> + 6 19 18 1 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 4 3 19 2 -1. + <_> + 4 4 19 1 2. + <_> + + <_> + 0 3 24 2 -1. + <_> + 0 4 24 1 2. + <_> + + <_> + 15 14 9 4 -1. + <_> + 15 16 9 2 2. + <_> + + <_> + 0 14 9 4 -1. + <_> + 0 16 9 2 2. + <_> + + <_> + 6 15 18 2 -1. + <_> + 6 16 18 1 2. + <_> + + <_> + 3 17 18 3 -1. + <_> + 3 18 18 1 3. + <_> + + <_> + 12 0 3 23 -1. + <_> + 13 0 1 23 3. + <_> + + <_> + 6 0 8 6 -1. + <_> + 6 3 8 3 2. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 9 0 3 23 -1. + <_> + 10 0 1 23 3. + <_> + + <_> + 10 7 4 10 -1. + <_> + 10 12 4 5 2. + <_> + + <_> + 7 8 10 12 -1. + <_> + 7 12 10 4 3. + <_> + + <_> + 14 9 6 14 -1. + <_> + 17 9 3 7 2. + <_> + 14 16 3 7 2. + <_> + + <_> + 2 0 10 9 -1. + <_> + 2 3 10 3 3. + <_> + + <_> + 11 1 5 12 -1. + <_> + 11 7 5 6 2. + <_> + + <_> + 1 4 12 10 -1. + <_> + 1 4 6 5 2. + <_> + 7 9 6 5 2. + <_> + + <_> + 15 1 9 4 -1. + <_> + 15 3 9 2 2. + <_> + + <_> + 1 2 8 10 -1. + <_> + 1 2 4 5 2. + <_> + 5 7 4 5 2. + <_> + + <_> + 10 1 5 12 -1. + <_> + 10 5 5 4 3. + <_> + + <_> + 4 0 14 24 -1. + <_> + 11 0 7 24 2. + <_> + + <_> + 7 17 10 4 -1. + <_> + 7 19 10 2 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 13 15 6 9 -1. + <_> + 15 15 2 9 3. + <_> + + <_> + 3 21 18 3 -1. + <_> + 3 22 18 1 3. + <_> + + <_> + 13 15 6 9 -1. + <_> + 15 15 2 9 3. + <_> + + <_> + 5 15 6 9 -1. + <_> + 7 15 2 9 3. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 7 3 6 11 -1. + <_> + 9 3 2 11 3. + <_> + + <_> + 15 1 9 4 -1. + <_> + 15 3 9 2 2. + <_> + + <_> + 5 4 14 8 -1. + <_> + 5 8 14 4 2. + <_> + + <_> + 8 1 15 9 -1. + <_> + 8 4 15 3 3. + <_> + + <_> + 7 2 8 10 -1. + <_> + 7 2 4 5 2. + <_> + 11 7 4 5 2. + <_> + + <_> + 12 2 6 12 -1. + <_> + 12 2 3 12 2. + <_> + + <_> + 6 2 6 12 -1. + <_> + 9 2 3 12 2. + <_> + + <_> + 7 7 12 4 -1. + <_> + 7 7 6 4 2. + <_> + + <_> + 6 3 12 10 -1. + <_> + 10 3 4 10 3. + <_> + + <_> + 5 6 16 6 -1. + <_> + 13 6 8 3 2. + <_> + 5 9 8 3 2. + <_> + + <_> + 3 1 18 9 -1. + <_> + 9 1 6 9 3. + <_> + + <_> + 3 8 18 5 -1. + <_> + 9 8 6 5 3. + <_> + + <_> + 0 0 24 22 -1. + <_> + 0 0 12 11 2. + <_> + 12 11 12 11 2. + <_> + + <_> + 14 16 9 6 -1. + <_> + 14 18 9 2 3. + <_> + + <_> + 0 16 24 8 -1. + <_> + 0 20 24 4 2. + <_> + + <_> + 1 19 22 4 -1. + <_> + 12 19 11 2 2. + <_> + 1 21 11 2 2. + <_> + + <_> + 1 16 9 6 -1. + <_> + 1 18 9 2 3. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 8 5 4 2. + <_> + + <_> + 9 15 6 9 -1. + <_> + 11 15 2 9 3. + <_> + + <_> + 10 18 12 6 -1. + <_> + 16 18 6 3 2. + <_> + 10 21 6 3 2. + <_> + + <_> + 2 18 12 6 -1. + <_> + 2 18 6 3 2. + <_> + 8 21 6 3 2. + <_> + + <_> + 8 3 16 9 -1. + <_> + 8 6 16 3 3. + <_> + + <_> + 0 5 10 6 -1. + <_> + 0 7 10 2 3. + <_> + + <_> + 5 5 18 3 -1. + <_> + 5 6 18 1 3. + <_> + + <_> + 2 6 9 6 -1. + <_> + 2 9 9 3 2. + <_> + + <_> + 14 2 10 9 -1. + <_> + 14 5 10 3 3. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 9 2 15 6 -1. + <_> + 9 4 15 2 3. + <_> + + <_> + 4 8 15 6 -1. + <_> + 4 10 15 2 3. + <_> + + <_> + 0 5 24 4 -1. + <_> + 12 5 12 2 2. + <_> + 0 7 12 2 2. + <_> + + <_> + 7 8 6 12 -1. + <_> + 9 8 2 12 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 0 12 6 12 -1. + <_> + 0 12 3 6 2. + <_> + 3 18 3 6 2. + <_> + + <_> + 14 12 10 6 -1. + <_> + 14 14 10 2 3. + <_> + + <_> + 2 7 18 9 -1. + <_> + 2 10 18 3 3. + <_> + + <_> + 11 14 10 9 -1. + <_> + 11 17 10 3 3. + <_> + + <_> + 7 6 10 8 -1. + <_> + 7 6 5 4 2. + <_> + 12 10 5 4 2. + <_> + + <_> + 6 6 14 6 -1. + <_> + 13 6 7 3 2. + <_> + 6 9 7 3 2. + <_> + + <_> + 4 13 9 7 -1. + <_> + 7 13 3 7 3. + <_> + + <_> + 14 10 6 12 -1. + <_> + 17 10 3 6 2. + <_> + 14 16 3 6 2. + <_> + + <_> + 4 10 6 12 -1. + <_> + 4 10 3 6 2. + <_> + 7 16 3 6 2. + <_> + + <_> + 13 9 8 6 -1. + <_> + 13 9 4 6 2. + <_> + + <_> + 8 3 4 14 -1. + <_> + 10 3 2 14 2. + <_> + + <_> + 17 0 3 18 -1. + <_> + 18 0 1 18 3. + <_> + + <_> + 4 12 16 12 -1. + <_> + 12 12 8 12 2. + <_> + + <_> + 15 0 6 14 -1. + <_> + 17 0 2 14 3. + <_> + + <_> + 3 0 6 14 -1. + <_> + 5 0 2 14 3. + <_> + + <_> + 12 2 12 20 -1. + <_> + 16 2 4 20 3. + <_> + + <_> + 0 2 12 20 -1. + <_> + 4 2 4 20 3. + <_> + + <_> + 16 0 6 17 -1. + <_> + 18 0 2 17 3. + <_> + + <_> + 2 0 6 17 -1. + <_> + 4 0 2 17 3. + <_> + + <_> + 15 6 9 6 -1. + <_> + 15 8 9 2 3. + <_> + + <_> + 0 6 9 6 -1. + <_> + 0 8 9 2 3. + <_> + + <_> + 18 1 6 13 -1. + <_> + 20 1 2 13 3. + <_> + + <_> + 0 1 6 13 -1. + <_> + 2 1 2 13 3. + <_> + + <_> + 16 0 4 9 -1. + <_> + 16 0 2 9 2. + <_> + + <_> + 5 10 12 7 -1. + <_> + 9 10 4 7 3. + <_> + + <_> + 12 9 12 6 -1. + <_> + 12 11 12 2 3. + <_> + + <_> + 0 9 12 6 -1. + <_> + 0 11 12 2 3. + <_> + + <_> + 5 7 14 9 -1. + <_> + 5 10 14 3 3. + <_> + + <_> + 0 15 20 3 -1. + <_> + 0 16 20 1 3. + <_> + + <_> + 8 10 8 10 -1. + <_> + 12 10 4 5 2. + <_> + 8 15 4 5 2. + <_> + + <_> + 5 4 13 9 -1. + <_> + 5 7 13 3 3. + <_> + + <_> + 10 2 6 18 -1. + <_> + 10 8 6 6 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 6 9 12 4 -1. + <_> + 6 11 12 2 2. + <_> + + <_> + 3 2 15 12 -1. + <_> + 3 6 15 4 3. + <_> + + <_> + 12 0 12 5 -1. + <_> + 16 0 4 5 3. + <_> + + <_> + 0 15 18 3 -1. + <_> + 6 15 6 3 3. + <_> + + <_> + 0 14 24 5 -1. + <_> + 8 14 8 5 3. + <_> + + <_> + 5 1 3 18 -1. + <_> + 6 1 1 18 3. + <_> + + <_> + 10 0 4 14 -1. + <_> + 10 0 2 14 2. + <_> + + <_> + 9 3 4 9 -1. + <_> + 11 3 2 9 2. + <_> + + <_> + 8 2 12 6 -1. + <_> + 14 2 6 3 2. + <_> + 8 5 6 3 2. + <_> + + <_> + 0 4 17 4 -1. + <_> + 0 6 17 2 2. + <_> + + <_> + 16 16 5 8 -1. + <_> + 16 20 5 4 2. + <_> + + <_> + 3 16 5 8 -1. + <_> + 3 20 5 4 2. + <_> + + <_> + 6 18 18 2 -1. + <_> + 6 19 18 1 2. + <_> + + <_> + 0 0 12 5 -1. + <_> + 4 0 4 5 3. + <_> + + <_> + 14 3 6 12 -1. + <_> + 17 3 3 6 2. + <_> + 14 9 3 6 2. + <_> + + <_> + 0 12 6 12 -1. + <_> + 2 12 2 12 3. + <_> + + <_> + 2 3 21 3 -1. + <_> + 2 4 21 1 3. + <_> + + <_> + 4 3 6 12 -1. + <_> + 4 3 3 6 2. + <_> + 7 9 3 6 2. + <_> + + <_> + 12 8 12 6 -1. + <_> + 18 8 6 3 2. + <_> + 12 11 6 3 2. + <_> + + <_> + 0 15 16 9 -1. + <_> + 8 15 8 9 2. + <_> + + <_> + 6 13 18 5 -1. + <_> + 6 13 9 5 2. + <_> + + <_> + 1 6 15 6 -1. + <_> + 6 6 5 6 3. + <_> + + <_> + 11 9 9 6 -1. + <_> + 14 9 3 6 3. + <_> + + <_> + 3 0 15 11 -1. + <_> + 8 0 5 11 3. + <_> + + <_> + 15 3 3 18 -1. + <_> + 15 9 3 6 3. + <_> + + <_> + 6 3 3 18 -1. + <_> + 6 9 3 6 3. + <_> + + <_> + 9 5 10 8 -1. + <_> + 14 5 5 4 2. + <_> + 9 9 5 4 2. + <_> + + <_> + 4 4 16 8 -1. + <_> + 4 4 8 4 2. + <_> + 12 8 8 4 2. + <_> + + <_> + 7 7 12 3 -1. + <_> + 7 7 6 3 2. + <_> + + <_> + 5 0 9 13 -1. + <_> + 8 0 3 13 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 8 1 10 9 -1. + <_> + 8 4 10 3 3. + <_> + + <_> + 0 2 18 2 -1. + <_> + 0 3 18 1 2. + <_> + + <_> + 10 13 14 6 -1. + <_> + 17 13 7 3 2. + <_> + 10 16 7 3 2. + <_> + + <_> + 0 13 14 6 -1. + <_> + 0 13 7 3 2. + <_> + 7 16 7 3 2. + <_> + + <_> + 20 2 3 21 -1. + <_> + 21 2 1 21 3. + <_> + + <_> + 0 9 5 12 -1. + <_> + 0 13 5 4 3. + <_> + + <_> + 12 6 12 6 -1. + <_> + 12 8 12 2 3. + <_> + + <_> + 1 8 20 3 -1. + <_> + 1 9 20 1 3. + <_> + + <_> + 5 7 19 3 -1. + <_> + 5 8 19 1 3. + <_> + + <_> + 1 12 9 6 -1. + <_> + 1 14 9 2 3. + <_> + + <_> + 6 10 14 12 -1. + <_> + 6 14 14 4 3. + <_> + + <_> + 5 6 14 18 -1. + <_> + 5 12 14 6 3. + <_> + + <_> + 11 12 9 7 -1. + <_> + 14 12 3 7 3. + <_> + + <_> + 1 15 18 4 -1. + <_> + 1 17 18 2 2. + <_> + + <_> + 11 14 6 9 -1. + <_> + 11 17 6 3 3. + <_> + + <_> + 0 8 18 4 -1. + <_> + 0 8 9 2 2. + <_> + 9 10 9 2 2. + <_> + + <_> + 3 10 20 6 -1. + <_> + 13 10 10 3 2. + <_> + 3 13 10 3 2. + <_> + + <_> + 1 10 20 6 -1. + <_> + 1 10 10 3 2. + <_> + 11 13 10 3 2. + <_> + + <_> + 0 9 24 2 -1. + <_> + 0 9 12 2 2. + <_> + + <_> + 1 12 20 8 -1. + <_> + 1 12 10 4 2. + <_> + 11 16 10 4 2. + <_> + + <_> + 11 12 9 7 -1. + <_> + 14 12 3 7 3. + <_> + + <_> + 4 12 9 7 -1. + <_> + 7 12 3 7 3. + <_> + + <_> + 12 12 8 5 -1. + <_> + 12 12 4 5 2. + <_> + + <_> + 4 12 8 5 -1. + <_> + 8 12 4 5 2. + <_> + + <_> + 13 10 4 10 -1. + <_> + 13 10 2 10 2. + <_> + + <_> + 1 15 20 2 -1. + <_> + 11 15 10 2 2. + <_> + + <_> + 9 10 6 6 -1. + <_> + 9 10 3 6 2. + <_> + + <_> + 0 1 21 3 -1. + <_> + 7 1 7 3 3. + <_> + + <_> + 6 4 13 9 -1. + <_> + 6 7 13 3 3. + <_> + + <_> + 6 5 12 5 -1. + <_> + 10 5 4 5 3. + <_> + + <_> + 10 10 10 6 -1. + <_> + 10 12 10 2 3. + <_> + + <_> + 6 12 5 8 -1. + <_> + 6 16 5 4 2. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 2 10 18 6 -1. + <_> + 8 10 6 6 3. + <_> + + <_> + 11 2 9 4 -1. + <_> + 11 4 9 2 2. + <_> + + <_> + 1 20 21 3 -1. + <_> + 8 20 7 3 3. + <_> + + <_> + 1 10 22 2 -1. + <_> + 1 11 22 1 2. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 5 0 6 9 -1. + <_> + 7 0 2 9 3. + <_> + + <_> + 18 2 6 20 -1. + <_> + 20 2 2 20 3. + <_> + + <_> + 0 2 6 20 -1. + <_> + 2 2 2 20 3. + <_> + + <_> + 11 7 6 14 -1. + <_> + 14 7 3 7 2. + <_> + 11 14 3 7 2. + <_> + + <_> + 0 1 4 9 -1. + <_> + 2 1 2 9 2. + <_> + + <_> + 12 14 9 4 -1. + <_> + 12 16 9 2 2. + <_> + + <_> + 1 13 9 4 -1. + <_> + 1 15 9 2 2. + <_> + + <_> + 7 6 15 6 -1. + <_> + 7 8 15 2 3. + <_> + + <_> + 8 2 3 18 -1. + <_> + 8 8 3 6 3. + <_> + + <_> + 6 6 12 6 -1. + <_> + 12 6 6 3 2. + <_> + 6 9 6 3 2. + <_> + + <_> + 2 19 20 4 -1. + <_> + 2 19 10 2 2. + <_> + 12 21 10 2 2. + <_> + + <_> + 14 15 6 9 -1. + <_> + 14 18 6 3 3. + <_> + + <_> + 3 5 18 14 -1. + <_> + 3 5 9 7 2. + <_> + 12 12 9 7 2. + <_> + + <_> + 15 6 4 18 -1. + <_> + 17 6 2 9 2. + <_> + 15 15 2 9 2. + <_> + + <_> + 5 6 4 18 -1. + <_> + 5 6 2 9 2. + <_> + 7 15 2 9 2. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 11 5 6 9 -1. + <_> + 13 5 2 9 3. + <_> + + <_> + 9 5 6 6 -1. + <_> + 12 5 3 6 2. + <_> + + <_> + 4 1 16 6 -1. + <_> + 12 1 8 3 2. + <_> + 4 4 8 3 2. + <_> + + <_> + 9 13 6 11 -1. + <_> + 11 13 2 11 3. + <_> + + <_> + 17 1 6 12 -1. + <_> + 20 1 3 6 2. + <_> + 17 7 3 6 2. + <_> + + <_> + 1 17 18 3 -1. + <_> + 1 18 18 1 3. + <_> + + <_> + 7 13 10 8 -1. + <_> + 7 17 10 4 2. + <_> + + <_> + 6 18 10 6 -1. + <_> + 6 20 10 2 3. + <_> + + <_> + 9 14 9 4 -1. + <_> + 9 16 9 2 2. + <_> + + <_> + 1 1 6 12 -1. + <_> + 1 1 3 6 2. + <_> + 4 7 3 6 2. + <_> + + <_> + 19 4 5 12 -1. + <_> + 19 8 5 4 3. + <_> + + <_> + 0 0 8 8 -1. + <_> + 4 0 4 8 2. + <_> + + <_> + 3 5 19 3 -1. + <_> + 3 6 19 1 3. + <_> + + <_> + 1 5 12 6 -1. + <_> + 1 5 6 3 2. + <_> + 7 8 6 3 2. + <_> + + <_> + 2 1 21 8 -1. + <_> + 9 1 7 8 3. + <_> + + <_> + 4 1 16 8 -1. + <_> + 4 5 16 4 2. + <_> + + <_> + 6 0 18 3 -1. + <_> + 6 1 18 1 3. + <_> + + <_> + 4 4 10 14 -1. + <_> + 4 11 10 7 2. + <_> + + <_> + 15 6 4 10 -1. + <_> + 15 11 4 5 2. + <_> + + <_> + 3 18 18 3 -1. + <_> + 9 18 6 3 3. + <_> + + <_> + 8 18 12 6 -1. + <_> + 12 18 4 6 3. + <_> + + <_> + 3 15 6 9 -1. + <_> + 6 15 3 9 2. + <_> + + <_> + 15 7 6 8 -1. + <_> + 15 11 6 4 2. + <_> + + <_> + 3 7 6 8 -1. + <_> + 3 11 6 4 2. + <_> + + <_> + 5 9 18 6 -1. + <_> + 14 9 9 3 2. + <_> + 5 12 9 3 2. + <_> + + <_> + 1 13 12 6 -1. + <_> + 1 15 12 2 3. + <_> + + <_> + 14 15 10 6 -1. + <_> + 14 17 10 2 3. + <_> + + <_> + 0 15 10 6 -1. + <_> + 0 17 10 2 3. + <_> + + <_> + 15 13 6 9 -1. + <_> + 15 16 6 3 3. + <_> + + <_> + 3 13 6 9 -1. + <_> + 3 16 6 3 3. + <_> + + <_> + 9 5 8 8 -1. + <_> + 9 5 4 8 2. + <_> + + <_> + 1 18 12 6 -1. + <_> + 1 18 6 3 2. + <_> + 7 21 6 3 2. + <_> + + <_> + 13 19 10 4 -1. + <_> + 13 21 10 2 2. + <_> + + <_> + 1 19 10 4 -1. + <_> + 1 21 10 2 2. + <_> + + <_> + 6 19 18 3 -1. + <_> + 6 20 18 1 3. + <_> + + <_> + 8 14 4 10 -1. + <_> + 8 19 4 5 2. + <_> + + <_> + 0 0 24 6 -1. + <_> + 0 2 24 2 3. + <_> + + <_> + 0 1 6 9 -1. + <_> + 0 4 6 3 3. + <_> + + <_> + 4 9 20 6 -1. + <_> + 14 9 10 3 2. + <_> + 4 12 10 3 2. + <_> + + <_> + 1 15 19 8 -1. + <_> + 1 19 19 4 2. + <_> + + <_> + 14 0 10 6 -1. + <_> + 14 2 10 2 3. + <_> + + <_> + 1 10 21 14 -1. + <_> + 8 10 7 14 3. + <_> + + <_> + 10 10 8 8 -1. + <_> + 10 10 4 8 2. + <_> + + <_> + 6 8 10 4 -1. + <_> + 11 8 5 4 2. + <_> + + <_> + 10 5 4 9 -1. + <_> + 10 5 2 9 2. + <_> + + <_> + 7 5 6 10 -1. + <_> + 9 5 2 10 3. + <_> + + <_> + 14 4 4 13 -1. + <_> + 14 4 2 13 2. + <_> + + <_> + 6 4 4 13 -1. + <_> + 8 4 2 13 2. + <_> + + <_> + 8 7 9 6 -1. + <_> + 11 7 3 6 3. + <_> + + <_> + 3 6 16 6 -1. + <_> + 3 6 8 3 2. + <_> + 11 9 8 3 2. + <_> + + <_> + 5 4 16 14 -1. + <_> + 13 4 8 7 2. + <_> + 5 11 8 7 2. + <_> + + <_> + 0 0 24 4 -1. + <_> + 0 0 12 2 2. + <_> + 12 2 12 2 2. + <_> + + <_> + 9 1 9 6 -1. + <_> + 12 1 3 6 3. + <_> + + <_> + 4 1 14 4 -1. + <_> + 11 1 7 4 2. + <_> + + <_> + 10 14 7 9 -1. + <_> + 10 17 7 3 3. + <_> + + <_> + 8 3 8 10 -1. + <_> + 8 3 4 5 2. + <_> + 12 8 4 5 2. + <_> + + <_> + 7 3 12 5 -1. + <_> + 11 3 4 5 3. + <_> + + <_> + 8 2 4 13 -1. + <_> + 10 2 2 13 2. + <_> + + <_> + 11 2 3 19 -1. + <_> + 12 2 1 19 3. + <_> + + <_> + 7 7 9 6 -1. + <_> + 10 7 3 6 3. + <_> + + <_> + 4 22 20 2 -1. + <_> + 4 22 10 2 2. + <_> + + <_> + 0 16 24 4 -1. + <_> + 0 16 12 2 2. + <_> + 12 18 12 2 2. + <_> + + <_> + 7 3 12 5 -1. + <_> + 11 3 4 5 3. + <_> + + <_> + 1 10 8 14 -1. + <_> + 1 10 4 7 2. + <_> + 5 17 4 7 2. + <_> + + <_> + 11 16 6 6 -1. + <_> + 11 19 6 3 2. + <_> + + <_> + 6 0 10 24 -1. + <_> + 6 0 5 12 2. + <_> + 11 12 5 12 2. + <_> + + <_> + 7 5 14 14 -1. + <_> + 14 5 7 7 2. + <_> + 7 12 7 7 2. + <_> + + <_> + 7 8 10 8 -1. + <_> + 7 8 5 4 2. + <_> + 12 12 5 4 2. + <_> + + <_> + 9 1 9 6 -1. + <_> + 12 1 3 6 3. + <_> + + <_> + 0 6 24 3 -1. + <_> + 12 6 12 3 2. + <_> + + <_> + 7 3 12 5 -1. + <_> + 11 3 4 5 3. + <_> + + <_> + 1 13 22 4 -1. + <_> + 1 13 11 2 2. + <_> + 12 15 11 2 2. + <_> + + <_> + 9 12 12 6 -1. + <_> + 9 14 12 2 3. + <_> + + <_> + 0 5 9 6 -1. + <_> + 0 7 9 2 3. + <_> + + <_> + 1 5 23 6 -1. + <_> + 1 7 23 2 3. + <_> + + <_> + 1 6 19 12 -1. + <_> + 1 10 19 4 3. + <_> + + <_> + 9 1 6 21 -1. + <_> + 9 8 6 7 3. + <_> + + <_> + 3 19 18 3 -1. + <_> + 9 19 6 3 3. + <_> + + <_> + 9 14 6 9 -1. + <_> + 11 14 2 9 3. + <_> + + <_> + 9 6 4 12 -1. + <_> + 11 6 2 12 2. + <_> + + <_> + 16 0 6 9 -1. + <_> + 18 0 2 9 3. + <_> + + <_> + 2 0 6 9 -1. + <_> + 4 0 2 9 3. + <_> + + <_> + 13 1 4 22 -1. + <_> + 15 1 2 11 2. + <_> + 13 12 2 11 2. + <_> + + <_> + 1 8 8 12 -1. + <_> + 1 14 8 6 2. + <_> + + <_> + 14 7 7 9 -1. + <_> + 14 10 7 3 3. + <_> + + <_> + 3 12 18 4 -1. + <_> + 3 12 9 2 2. + <_> + 12 14 9 2 2. + <_> + + <_> + 13 1 4 22 -1. + <_> + 15 1 2 11 2. + <_> + 13 12 2 11 2. + <_> + + <_> + 7 1 4 22 -1. + <_> + 7 1 2 11 2. + <_> + 9 12 2 11 2. + <_> + + <_> + 4 7 20 4 -1. + <_> + 14 7 10 2 2. + <_> + 4 9 10 2 2. + <_> + + <_> + 9 10 6 7 -1. + <_> + 12 10 3 7 2. + <_> + + <_> + 7 7 10 4 -1. + <_> + 7 7 5 4 2. + <_> + + <_> + 0 3 4 15 -1. + <_> + 0 8 4 5 3. + <_> + + <_> + 15 0 8 12 -1. + <_> + 19 0 4 6 2. + <_> + 15 6 4 6 2. + <_> + + <_> + 1 0 8 12 -1. + <_> + 1 0 4 6 2. + <_> + 5 6 4 6 2. + <_> + + <_> + 14 5 6 16 -1. + <_> + 16 5 2 16 3. + <_> + + <_> + 4 5 6 16 -1. + <_> + 6 5 2 16 3. + <_> + + <_> + 15 0 6 16 -1. + <_> + 17 0 2 16 3. + <_> + + <_> + 3 0 6 16 -1. + <_> + 5 0 2 16 3. + <_> + + <_> + 0 2 24 3 -1. + <_> + 0 3 24 1 3. + <_> + + <_> + 7 1 10 4 -1. + <_> + 7 3 10 2 2. + <_> + + <_> + 1 0 23 8 -1. + <_> + 1 4 23 4 2. + <_> + + <_> + 1 17 19 3 -1. + <_> + 1 18 19 1 3. + <_> + + <_> + 6 18 18 2 -1. + <_> + 6 19 18 1 2. + <_> + + <_> + 1 17 9 6 -1. + <_> + 1 19 9 2 3. + <_> + + <_> + 15 15 6 9 -1. + <_> + 15 18 6 3 3. + <_> + + <_> + 3 15 6 9 -1. + <_> + 3 18 6 3 3. + <_> + + <_> + 4 14 20 6 -1. + <_> + 4 17 20 3 2. + <_> + + <_> + 0 10 6 14 -1. + <_> + 0 10 3 7 2. + <_> + 3 17 3 7 2. + <_> + + <_> + 6 18 18 3 -1. + <_> + 6 19 18 1 3. + <_> + + <_> + 4 12 9 7 -1. + <_> + 7 12 3 7 3. + <_> + + <_> + 6 10 18 5 -1. + <_> + 12 10 6 5 3. + <_> + + <_> + 0 10 18 5 -1. + <_> + 6 10 6 5 3. + <_> + + <_> + 3 2 18 9 -1. + <_> + 9 2 6 9 3. + <_> + + <_> + 4 6 10 10 -1. + <_> + 4 6 5 5 2. + <_> + 9 11 5 5 2. + <_> + + <_> + 20 14 4 9 -1. + <_> + 20 14 2 9 2. + <_> + + <_> + 0 14 4 9 -1. + <_> + 2 14 2 9 2. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 6 21 12 3 -1. + <_> + 12 21 6 3 2. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 1 16 10 8 -1. + <_> + 1 16 5 4 2. + <_> + 6 20 5 4 2. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 1 0 3 19 -1. + <_> + 2 0 1 19 3. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 0 1 6 9 -1. + <_> + 2 1 2 9 3. + <_> + + <_> + 3 7 19 4 -1. + <_> + 3 9 19 2 2. + <_> + + <_> + 7 14 9 6 -1. + <_> + 7 16 9 2 3. + <_> + + <_> + 17 1 7 6 -1. + <_> + 17 4 7 3 2. + <_> + + <_> + 5 0 14 8 -1. + <_> + 5 4 14 4 2. + <_> + + <_> + 16 1 8 6 -1. + <_> + 16 4 8 3 2. + <_> + + <_> + 0 1 8 6 -1. + <_> + 0 4 8 3 2. + <_> + + <_> + 6 0 18 4 -1. + <_> + 15 0 9 2 2. + <_> + 6 2 9 2 2. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 3 7 18 8 -1. + <_> + 9 7 6 8 3. + <_> + + <_> + 2 11 6 9 -1. + <_> + 4 11 2 9 3. + <_> + + <_> + 10 5 6 9 -1. + <_> + 12 5 2 9 3. + <_> + + <_> + 10 6 4 18 -1. + <_> + 10 6 2 9 2. + <_> + 12 15 2 9 2. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 9 1 4 20 -1. + <_> + 9 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 5 9 18 6 -1. + <_> + 14 9 9 3 2. + <_> + 5 12 9 3 2. + <_> + + <_> + 6 4 6 9 -1. + <_> + 8 4 2 9 3. + <_> + + <_> + 10 16 8 6 -1. + <_> + 10 16 4 6 2. + <_> + + <_> + 0 0 18 8 -1. + <_> + 0 0 9 4 2. + <_> + 9 4 9 4 2. + <_> + + <_> + 6 5 14 12 -1. + <_> + 13 5 7 6 2. + <_> + 6 11 7 6 2. + <_> + + <_> + 4 3 15 7 -1. + <_> + 9 3 5 7 3. + <_> + + <_> + 14 12 10 6 -1. + <_> + 14 14 10 2 3. + <_> + + <_> + 0 11 4 10 -1. + <_> + 0 16 4 5 2. + <_> + + <_> + 1 10 22 3 -1. + <_> + 1 11 22 1 3. + <_> + + <_> + 8 9 6 10 -1. + <_> + 10 9 2 10 3. + <_> + + <_> + 13 2 6 12 -1. + <_> + 16 2 3 6 2. + <_> + 13 8 3 6 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 10 6 2 9 2. + <_> + 12 15 2 9 2. + <_> + + <_> + 7 8 10 16 -1. + <_> + 12 8 5 8 2. + <_> + 7 16 5 8 2. + <_> + + <_> + 8 1 8 12 -1. + <_> + 8 1 4 6 2. + <_> + 12 7 4 6 2. + <_> + + <_> + 7 1 12 14 -1. + <_> + 13 1 6 7 2. + <_> + 7 8 6 7 2. + <_> + + <_> + 2 14 12 6 -1. + <_> + 2 16 12 2 3. + <_> + + <_> + 11 16 6 6 -1. + <_> + 11 19 6 3 2. + <_> + + <_> + 7 16 6 6 -1. + <_> + 7 19 6 3 2. + <_> + + <_> + 13 4 4 10 -1. + <_> + 13 4 2 10 2. + <_> + + <_> + 0 19 19 3 -1. + <_> + 0 20 19 1 3. + <_> + + <_> + 12 8 6 8 -1. + <_> + 12 12 6 4 2. + <_> + + <_> + 8 1 8 22 -1. + <_> + 8 12 8 11 2. + <_> + + <_> + 12 8 6 8 -1. + <_> + 12 12 6 4 2. + <_> + + <_> + 6 8 6 8 -1. + <_> + 6 12 6 4 2. + <_> + + <_> + 14 5 6 9 -1. + <_> + 14 8 6 3 3. + <_> + + <_> + 0 6 24 4 -1. + <_> + 0 8 24 2 2. + <_> + + <_> + 14 12 10 6 -1. + <_> + 14 14 10 2 3. + <_> + + <_> + 0 12 10 6 -1. + <_> + 0 14 10 2 3. + <_> + + <_> + 4 6 19 3 -1. + <_> + 4 7 19 1 3. + <_> + + <_> + 1 6 19 3 -1. + <_> + 1 7 19 1 3. + <_> + + <_> + 4 0 16 9 -1. + <_> + 4 3 16 3 3. + <_> + + <_> + 0 1 24 5 -1. + <_> + 8 1 8 5 3. + <_> + + <_> + 3 6 6 15 -1. + <_> + 3 11 6 5 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 6 22 18 2 -1. + <_> + 6 23 18 1 2. + <_> + + <_> + 2 12 6 9 -1. + <_> + 2 15 6 3 3. + <_> + + <_> + 18 12 6 9 -1. + <_> + 18 15 6 3 3. + <_> + + <_> + 0 12 6 9 -1. + <_> + 0 15 6 3 3. + <_> + + <_> + 11 14 4 10 -1. + <_> + 11 19 4 5 2. + <_> + + <_> + 9 6 6 16 -1. + <_> + 9 14 6 8 2. + <_> + + <_> + 7 7 10 10 -1. + <_> + 7 12 10 5 2. + <_> + + <_> + 1 3 6 13 -1. + <_> + 3 3 2 13 3. + <_> + + <_> + 18 1 6 13 -1. + <_> + 18 1 3 13 2. + <_> + + <_> + 5 1 6 9 -1. + <_> + 7 1 2 9 3. + <_> + + <_> + 18 2 6 11 -1. + <_> + 18 2 3 11 2. + <_> + + <_> + 0 2 6 11 -1. + <_> + 3 2 3 11 2. + <_> + + <_> + 9 12 15 6 -1. + <_> + 9 14 15 2 3. + <_> + + <_> + 2 2 20 3 -1. + <_> + 2 3 20 1 3. + <_> + + <_> + 10 6 4 9 -1. + <_> + 10 6 2 9 2. + <_> + + <_> + 5 6 12 14 -1. + <_> + 5 6 6 7 2. + <_> + 11 13 6 7 2. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 7 0 9 6 -1. + <_> + 10 0 3 6 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 4 1 12 20 -1. + <_> + 4 1 6 10 2. + <_> + 10 11 6 10 2. + <_> + + <_> + 6 7 18 3 -1. + <_> + 6 7 9 3 2. + <_> + + <_> + 0 7 18 3 -1. + <_> + 9 7 9 3 2. + <_> + + <_> + 3 20 18 3 -1. + <_> + 9 20 6 3 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 6 2 12 15 -1. + <_> + 10 2 4 15 3. + <_> + + <_> + 2 3 18 3 -1. + <_> + 2 4 18 1 3. + <_> + + <_> + 19 4 4 18 -1. + <_> + 21 4 2 9 2. + <_> + 19 13 2 9 2. + <_> + + <_> + 0 1 19 3 -1. + <_> + 0 2 19 1 3. + <_> + + <_> + 5 0 15 4 -1. + <_> + 5 2 15 2 2. + <_> + + <_> + 5 2 14 5 -1. + <_> + 12 2 7 5 2. + <_> + + <_> + 1 2 22 14 -1. + <_> + 1 2 11 14 2. + <_> + + <_> + 8 15 6 9 -1. + <_> + 10 15 2 9 3. + <_> + + <_> + 6 17 18 3 -1. + <_> + 6 18 18 1 3. + <_> + + <_> + 9 6 3 18 -1. + <_> + 9 12 3 6 3. + <_> + + <_> + 2 0 20 3 -1. + <_> + 2 1 20 1 3. + <_> + + <_> + 5 4 5 12 -1. + <_> + 5 8 5 4 3. + <_> + + <_> + 8 6 12 5 -1. + <_> + 12 6 4 5 3. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 12 3 6 2. + <_> + 12 18 3 6 2. + <_> + + <_> + 14 14 8 10 -1. + <_> + 18 14 4 5 2. + <_> + 14 19 4 5 2. + <_> + + <_> + 2 14 8 10 -1. + <_> + 2 14 4 5 2. + <_> + 6 19 4 5 2. + <_> + + <_> + 10 18 12 6 -1. + <_> + 16 18 6 3 2. + <_> + 10 21 6 3 2. + <_> + + <_> + 1 3 6 9 -1. + <_> + 1 6 6 3 3. + <_> + + <_> + 11 3 3 20 -1. + <_> + 12 3 1 20 3. + <_> + + <_> + 4 6 14 6 -1. + <_> + 4 6 7 3 2. + <_> + 11 9 7 3 2. + <_> + + <_> + 6 5 12 13 -1. + <_> + 10 5 4 13 3. + <_> + + <_> + 5 4 4 15 -1. + <_> + 5 9 4 5 3. + <_> + + <_> + 9 16 15 4 -1. + <_> + 14 16 5 4 3. + <_> + + <_> + 7 8 6 14 -1. + <_> + 7 8 3 7 2. + <_> + 10 15 3 7 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 2 5 18 3 -1. + <_> + 2 6 18 1 3. + <_> + + <_> + 5 1 15 8 -1. + <_> + 5 5 15 4 2. + <_> + + <_> + 7 1 8 18 -1. + <_> + 7 10 8 9 2. + <_> + + <_> + 0 10 24 3 -1. + <_> + 0 11 24 1 3. + <_> + + <_> + 0 2 6 13 -1. + <_> + 2 2 2 13 3. + <_> + + <_> + 16 0 8 10 -1. + <_> + 20 0 4 5 2. + <_> + 16 5 4 5 2. + <_> + + <_> + 5 1 10 9 -1. + <_> + 5 4 10 3 3. + <_> + + <_> + 5 6 18 3 -1. + <_> + 5 7 18 1 3. + <_> + + <_> + 0 1 24 3 -1. + <_> + 0 2 24 1 3. + <_> + + <_> + 11 4 6 11 -1. + <_> + 13 4 2 11 3. + <_> + + <_> + 0 0 8 10 -1. + <_> + 0 0 4 5 2. + <_> + 4 5 4 5 2. + <_> + + <_> + 4 16 18 3 -1. + <_> + 4 17 18 1 3. + <_> + + <_> + 2 16 18 3 -1. + <_> + 2 17 18 1 3. + <_> + + <_> + 3 0 18 10 -1. + <_> + 12 0 9 5 2. + <_> + 3 5 9 5 2. + <_> + + <_> + 2 3 20 21 -1. + <_> + 12 3 10 21 2. + <_> + + <_> + 6 7 14 3 -1. + <_> + 6 7 7 3 2. + <_> + + <_> + 0 9 12 6 -1. + <_> + 0 9 6 3 2. + <_> + 6 12 6 3 2. + <_> + + <_> + 3 14 21 4 -1. + <_> + 10 14 7 4 3. + <_> + + <_> + 0 14 21 4 -1. + <_> + 7 14 7 4 3. + <_> + + <_> + 5 21 18 3 -1. + <_> + 11 21 6 3 3. + <_> + + <_> + 1 21 18 3 -1. + <_> + 7 21 6 3 3. + <_> + + <_> + 19 4 4 18 -1. + <_> + 21 4 2 9 2. + <_> + 19 13 2 9 2. + <_> + + <_> + 3 7 18 3 -1. + <_> + 3 8 18 1 3. + <_> + + <_> + 19 4 4 18 -1. + <_> + 21 4 2 9 2. + <_> + 19 13 2 9 2. + <_> + + <_> + 7 15 10 6 -1. + <_> + 7 17 10 2 3. + <_> + + <_> + 9 13 11 9 -1. + <_> + 9 16 11 3 3. + <_> + + <_> + 0 6 4 10 -1. + <_> + 0 11 4 5 2. + <_> + + <_> + 15 16 9 6 -1. + <_> + 15 18 9 2 3. + <_> + + <_> + 1 5 4 18 -1. + <_> + 1 5 2 9 2. + <_> + 3 14 2 9 2. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 7 8 8 10 -1. + <_> + 7 8 4 5 2. + <_> + 11 13 4 5 2. + <_> + + <_> + 9 8 12 5 -1. + <_> + 13 8 4 5 3. + <_> + + <_> + 7 8 9 7 -1. + <_> + 10 8 3 7 3. + <_> + + <_> + 9 8 12 5 -1. + <_> + 13 8 4 5 3. + <_> + + <_> + 7 6 9 7 -1. + <_> + 10 6 3 7 3. + <_> + + <_> + 9 8 12 5 -1. + <_> + 13 8 4 5 3. + <_> + + <_> + 10 5 4 18 -1. + <_> + 10 11 4 6 3. + <_> + + <_> + 5 5 14 12 -1. + <_> + 5 11 14 6 2. + <_> + + <_> + 0 1 11 4 -1. + <_> + 0 3 11 2 2. + <_> + + <_> + 9 10 6 10 -1. + <_> + 11 10 2 10 3. + <_> + + <_> + 2 17 11 6 -1. + <_> + 2 19 11 2 3. + <_> + + <_> + 15 16 9 6 -1. + <_> + 15 18 9 2 3. + <_> + + <_> + 1 10 18 2 -1. + <_> + 1 11 18 1 2. + <_> + + <_> + 6 4 12 13 -1. + <_> + 10 4 4 13 3. + <_> + + <_> + 0 18 18 3 -1. + <_> + 0 19 18 1 3. + <_> + + <_> + 6 18 18 3 -1. + <_> + 6 19 18 1 3. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 13 15 9 6 -1. + <_> + 13 17 9 2 3. + <_> + + <_> + 2 15 9 6 -1. + <_> + 2 17 9 2 3. + <_> + + <_> + 13 1 6 16 -1. + <_> + 13 1 3 16 2. + <_> + + <_> + 5 1 6 16 -1. + <_> + 8 1 3 16 2. + <_> + + <_> + 11 5 6 10 -1. + <_> + 13 5 2 10 3. + <_> + + <_> + 7 5 6 10 -1. + <_> + 9 5 2 10 3. + <_> + + <_> + 10 0 6 24 -1. + <_> + 12 0 2 24 3. + <_> + + <_> + 3 4 4 20 -1. + <_> + 3 4 2 10 2. + <_> + 5 14 2 10 2. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 4 0 6 9 -1. + <_> + 6 0 2 9 3. + <_> + + <_> + 4 5 18 5 -1. + <_> + 10 5 6 5 3. + <_> + + <_> + 5 6 6 9 -1. + <_> + 7 6 2 9 3. + <_> + + <_> + 7 2 15 8 -1. + <_> + 12 2 5 8 3. + <_> + + <_> + 2 2 15 8 -1. + <_> + 7 2 5 8 3. + <_> + + <_> + 10 0 4 9 -1. + <_> + 10 0 2 9 2. + <_> + + <_> + 3 4 6 12 -1. + <_> + 3 4 3 6 2. + <_> + 6 10 3 6 2. + <_> + + <_> + 16 0 8 18 -1. + <_> + 16 0 4 18 2. + <_> + + <_> + 0 0 8 18 -1. + <_> + 4 0 4 18 2. + <_> + + <_> + 0 7 24 6 -1. + <_> + 0 9 24 2 3. + <_> + + <_> + 4 7 14 3 -1. + <_> + 11 7 7 3 2. + <_> + + <_> + 10 8 8 15 -1. + <_> + 10 8 4 15 2. + <_> + + <_> + 7 0 10 14 -1. + <_> + 12 0 5 14 2. + <_> + + <_> + 13 10 8 10 -1. + <_> + 17 10 4 5 2. + <_> + 13 15 4 5 2. + <_> + + <_> + 3 0 4 9 -1. + <_> + 5 0 2 9 2. + <_> + + <_> + 16 1 6 8 -1. + <_> + 16 1 3 8 2. + <_> + + <_> + 2 1 6 8 -1. + <_> + 5 1 3 8 2. + <_> + + <_> + 3 6 18 12 -1. + <_> + 3 10 18 4 3. + <_> + + <_> + 4 12 16 4 -1. + <_> + 4 14 16 2 2. + <_> + + <_> + 4 9 16 15 -1. + <_> + 4 14 16 5 3. + <_> + + <_> + 3 10 8 10 -1. + <_> + 3 10 4 5 2. + <_> + 7 15 4 5 2. + <_> + + <_> + 8 18 16 6 -1. + <_> + 16 18 8 3 2. + <_> + 8 21 8 3 2. + <_> + + <_> + 2 16 12 5 -1. + <_> + 6 16 4 5 3. + <_> + + <_> + 14 14 9 4 -1. + <_> + 14 16 9 2 2. + <_> + + <_> + 7 14 9 6 -1. + <_> + 7 16 9 2 3. + <_> + + <_> + 4 10 16 12 -1. + <_> + 4 14 16 4 3. + <_> + + <_> + 0 13 19 6 -1. + <_> + 0 15 19 2 3. + <_> + + <_> + 10 13 9 6 -1. + <_> + 10 15 9 2 3. + <_> + + <_> + 5 0 3 23 -1. + <_> + 6 0 1 23 3. + <_> + + <_> + 0 8 24 6 -1. + <_> + 0 10 24 2 3. + <_> + + <_> + 0 5 5 12 -1. + <_> + 0 9 5 4 3. + <_> + + <_> + 3 0 19 18 -1. + <_> + 3 9 19 9 2. + <_> + + <_> + 9 11 6 12 -1. + <_> + 9 11 3 6 2. + <_> + 12 17 3 6 2. + <_> + + <_> + 0 5 24 8 -1. + <_> + 12 5 12 4 2. + <_> + 0 9 12 4 2. + <_> + + <_> + 6 18 9 4 -1. + <_> + 6 20 9 2 2. + <_> + + <_> + 8 8 10 6 -1. + <_> + 8 10 10 2 3. + <_> + + <_> + 2 7 20 3 -1. + <_> + 2 8 20 1 3. + <_> + + <_> + 12 0 7 20 -1. + <_> + 12 10 7 10 2. + <_> + + <_> + 5 0 7 20 -1. + <_> + 5 10 7 10 2. + <_> + + <_> + 14 2 2 18 -1. + <_> + 14 11 2 9 2. + <_> + + <_> + 5 8 10 12 -1. + <_> + 10 8 5 12 2. + <_> + + <_> + 6 9 12 8 -1. + <_> + 12 9 6 4 2. + <_> + 6 13 6 4 2. + <_> + + <_> + 7 7 3 14 -1. + <_> + 7 14 3 7 2. + <_> + + <_> + 11 2 12 16 -1. + <_> + 17 2 6 8 2. + <_> + 11 10 6 8 2. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 13 14 9 4 -1. + <_> + 13 16 9 2 2. + <_> + + <_> + 0 12 22 4 -1. + <_> + 0 12 11 2 2. + <_> + 11 14 11 2 2. + <_> + + <_> + 1 12 22 6 -1. + <_> + 12 12 11 3 2. + <_> + 1 15 11 3 2. + <_> + + <_> + 6 6 9 6 -1. + <_> + 9 6 3 6 3. + <_> + + <_> + 10 0 4 9 -1. + <_> + 10 0 2 9 2. + <_> + + <_> + 3 8 18 7 -1. + <_> + 9 8 6 7 3. + <_> + + <_> + 0 6 24 6 -1. + <_> + 0 8 24 2 3. + <_> + + <_> + 0 11 24 10 -1. + <_> + 8 11 8 10 3. + <_> + + <_> + 3 3 18 21 -1. + <_> + 9 3 6 21 3. + <_> + + <_> + 7 12 4 10 -1. + <_> + 9 12 2 10 2. + <_> + + <_> + 10 16 10 8 -1. + <_> + 15 16 5 4 2. + <_> + 10 20 5 4 2. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 12 10 6 12 -1. + <_> + 15 10 3 6 2. + <_> + 12 16 3 6 2. + <_> + + <_> + 6 10 6 12 -1. + <_> + 6 10 3 6 2. + <_> + 9 16 3 6 2. + <_> + + <_> + 16 12 6 12 -1. + <_> + 19 12 3 6 2. + <_> + 16 18 3 6 2. + <_> + + <_> + 2 12 6 12 -1. + <_> + 2 12 3 6 2. + <_> + 5 18 3 6 2. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 8 15 6 9 -1. + <_> + 10 15 2 9 3. + <_> + + <_> + 14 20 10 4 -1. + <_> + 14 20 5 4 2. + <_> + + <_> + 0 20 10 4 -1. + <_> + 5 20 5 4 2. + <_> + + <_> + 11 17 9 6 -1. + <_> + 11 19 9 2 3. + <_> + + <_> + 3 2 14 4 -1. + <_> + 3 4 14 2 2. + <_> + + <_> + 10 1 10 4 -1. + <_> + 10 3 10 2 2. + <_> + + <_> + 0 15 10 4 -1. + <_> + 5 15 5 4 2. + <_> + + <_> + 19 2 3 19 -1. + <_> + 20 2 1 19 3. + <_> + + <_> + 4 12 9 8 -1. + <_> + 7 12 3 8 3. + <_> + + <_> + 4 7 5 12 -1. + <_> + 4 11 5 4 3. + <_> + + <_> + 0 1 24 3 -1. + <_> + 8 1 8 3 3. + <_> + + <_> + 6 8 12 4 -1. + <_> + 6 10 12 2 2. + <_> + + <_> + 19 3 4 10 -1. + <_> + 19 3 2 10 2. + <_> + + <_> + 0 6 9 6 -1. + <_> + 3 6 3 6 3. + <_> + + <_> + 18 0 6 22 -1. + <_> + 20 0 2 22 3. + <_> + + <_> + 0 0 6 22 -1. + <_> + 2 0 2 22 3. + <_> + + <_> + 5 15 19 3 -1. + <_> + 5 16 19 1 3. + <_> + + <_> + 10 7 4 15 -1. + <_> + 10 12 4 5 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 0 21 18 3 -1. + <_> + 0 22 18 1 3. + <_> + + <_> + 7 3 10 15 -1. + <_> + 7 8 10 5 3. + <_> + + <_> + 1 7 18 3 -1. + <_> + 1 8 18 1 3. + <_> + + <_> + 8 2 9 6 -1. + <_> + 11 2 3 6 3. + <_> + + <_> + 0 10 24 14 -1. + <_> + 0 17 24 7 2. + <_> + + <_> + 13 9 8 10 -1. + <_> + 17 9 4 5 2. + <_> + 13 14 4 5 2. + <_> + + <_> + 10 5 4 9 -1. + <_> + 12 5 2 9 2. + <_> + + <_> + 13 9 8 10 -1. + <_> + 17 9 4 5 2. + <_> + 13 14 4 5 2. + <_> + + <_> + 7 11 10 10 -1. + <_> + 7 11 5 5 2. + <_> + 12 16 5 5 2. + <_> + + <_> + 4 13 18 4 -1. + <_> + 13 13 9 2 2. + <_> + 4 15 9 2 2. + <_> + + <_> + 0 0 19 2 -1. + <_> + 0 1 19 1 2. + <_> + + <_> + 0 18 24 6 -1. + <_> + 8 18 8 6 3. + <_> + + <_> + 6 4 8 16 -1. + <_> + 6 12 8 8 2. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 10 10 2 2. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 13 15 7 9 -1. + <_> + 13 18 7 3 3. + <_> + + <_> + 3 18 12 6 -1. + <_> + 3 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 12 14 6 9 -1. + <_> + 12 17 6 3 3. + <_> + + <_> + 2 15 15 8 -1. + <_> + 2 19 15 4 2. + <_> + + <_> + 9 6 6 16 -1. + <_> + 9 14 6 8 2. + <_> + + <_> + 6 6 7 12 -1. + <_> + 6 10 7 4 3. + <_> + + <_> + 14 6 6 9 -1. + <_> + 14 9 6 3 3. + <_> + + <_> + 5 14 6 9 -1. + <_> + 5 17 6 3 3. + <_> + + <_> + 10 8 6 9 -1. + <_> + 12 8 2 9 3. + <_> + + <_> + 6 6 4 18 -1. + <_> + 6 6 2 9 2. + <_> + 8 15 2 9 2. + <_> + + <_> + 14 9 6 12 -1. + <_> + 17 9 3 6 2. + <_> + 14 15 3 6 2. + <_> + + <_> + 4 9 6 12 -1. + <_> + 4 9 3 6 2. + <_> + 7 15 3 6 2. + <_> + + <_> + 14 15 9 6 -1. + <_> + 14 17 9 2 3. + <_> + + <_> + 0 20 18 4 -1. + <_> + 0 20 9 2 2. + <_> + 9 22 9 2 2. + <_> + + <_> + 13 18 9 6 -1. + <_> + 13 20 9 2 3. + <_> + + <_> + 2 18 9 6 -1. + <_> + 2 20 9 2 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 19 2 4 22 -1. + <_> + 21 2 2 11 2. + <_> + 19 13 2 11 2. + <_> + + <_> + 1 2 4 22 -1. + <_> + 1 2 2 11 2. + <_> + 3 13 2 11 2. + <_> + + <_> + 15 0 2 24 -1. + <_> + 15 0 1 24 2. + <_> + + <_> + 3 20 16 4 -1. + <_> + 11 20 8 4 2. + <_> + + <_> + 11 6 4 18 -1. + <_> + 13 6 2 9 2. + <_> + 11 15 2 9 2. + <_> + + <_> + 7 9 10 14 -1. + <_> + 7 9 5 7 2. + <_> + 12 16 5 7 2. + <_> + + <_> + 14 6 6 9 -1. + <_> + 14 9 6 3 3. + <_> + + <_> + 3 6 7 9 -1. + <_> + 3 9 7 3 3. + <_> + + <_> + 20 4 4 20 -1. + <_> + 22 4 2 10 2. + <_> + 20 14 2 10 2. + <_> + + <_> + 7 6 6 9 -1. + <_> + 7 9 6 3 3. + <_> + + <_> + 7 0 10 14 -1. + <_> + 12 0 5 7 2. + <_> + 7 7 5 7 2. + <_> + + <_> + 2 1 18 6 -1. + <_> + 11 1 9 6 2. + <_> + + <_> + 15 0 2 24 -1. + <_> + 15 0 1 24 2. + <_> + + <_> + 7 0 2 24 -1. + <_> + 8 0 1 24 2. + <_> + + <_> + 13 12 6 7 -1. + <_> + 13 12 3 7 2. + <_> + + <_> + 5 12 6 7 -1. + <_> + 8 12 3 7 2. + <_> + + <_> + 3 5 18 19 -1. + <_> + 9 5 6 19 3. + <_> + + <_> + 5 6 9 6 -1. + <_> + 8 6 3 6 3. + <_> + + <_> + 9 5 9 6 -1. + <_> + 12 5 3 6 3. + <_> + + <_> + 3 16 10 8 -1. + <_> + 3 16 5 4 2. + <_> + 8 20 5 4 2. + <_> + + <_> + 19 8 5 15 -1. + <_> + 19 13 5 5 3. + <_> + + <_> + 0 8 5 15 -1. + <_> + 0 13 5 5 3. + <_> + + <_> + 20 4 4 20 -1. + <_> + 22 4 2 10 2. + <_> + 20 14 2 10 2. + <_> + + <_> + 0 4 4 20 -1. + <_> + 0 4 2 10 2. + <_> + 2 14 2 10 2. + <_> + + <_> + 7 7 10 4 -1. + <_> + 7 7 5 4 2. + <_> + + <_> + 4 19 14 4 -1. + <_> + 11 19 7 4 2. + <_> + + <_> + 10 11 12 3 -1. + <_> + 10 11 6 3 2. + <_> + + <_> + 0 1 24 3 -1. + <_> + 0 2 24 1 3. + <_> + + <_> + 7 2 14 20 -1. + <_> + 14 2 7 10 2. + <_> + 7 12 7 10 2. + <_> + + <_> + 0 13 6 9 -1. + <_> + 2 13 2 9 3. + <_> + + <_> + 13 0 4 19 -1. + <_> + 13 0 2 19 2. + <_> + + <_> + 1 11 14 3 -1. + <_> + 8 11 7 3 2. + <_> + + <_> + 7 1 16 20 -1. + <_> + 15 1 8 10 2. + <_> + 7 11 8 10 2. + <_> + + <_> + 0 10 21 9 -1. + <_> + 7 10 7 9 3. + <_> + + <_> + 6 19 15 5 -1. + <_> + 11 19 5 5 3. + <_> + + <_> + 8 10 6 6 -1. + <_> + 11 10 3 6 2. + <_> + + <_> + 7 1 16 20 -1. + <_> + 15 1 8 10 2. + <_> + 7 11 8 10 2. + <_> + + <_> + 1 1 16 20 -1. + <_> + 1 1 8 10 2. + <_> + 9 11 8 10 2. + <_> + + <_> + 16 4 3 12 -1. + <_> + 16 10 3 6 2. + <_> + + <_> + 5 4 3 12 -1. + <_> + 5 10 3 6 2. + <_> + + <_> + 7 6 10 8 -1. + <_> + 12 6 5 4 2. + <_> + 7 10 5 4 2. + <_> + + <_> + 4 9 6 6 -1. + <_> + 4 12 6 3 2. + <_> + + <_> + 6 5 12 4 -1. + <_> + 6 7 12 2 2. + <_> + + <_> + 9 2 5 15 -1. + <_> + 9 7 5 5 3. + <_> + + <_> + 15 0 9 6 -1. + <_> + 15 2 9 2 3. + <_> + + <_> + 6 0 11 10 -1. + <_> + 6 5 11 5 2. + <_> + + <_> + 12 7 4 12 -1. + <_> + 12 13 4 6 2. + <_> + + <_> + 7 2 9 4 -1. + <_> + 7 4 9 2 2. + <_> + + <_> + 6 0 13 6 -1. + <_> + 6 2 13 2 3. + <_> + + <_> + 10 6 4 18 -1. + <_> + 10 6 2 9 2. + <_> + 12 15 2 9 2. + <_> + + <_> + 10 8 6 9 -1. + <_> + 12 8 2 9 3. + <_> + + <_> + 3 18 10 6 -1. + <_> + 3 20 10 2 3. + <_> + + <_> + 4 14 20 3 -1. + <_> + 4 15 20 1 3. + <_> + + <_> + 2 15 9 6 -1. + <_> + 2 17 9 2 3. + <_> + + <_> + 13 0 4 19 -1. + <_> + 13 0 2 19 2. + <_> + + <_> + 7 0 4 19 -1. + <_> + 9 0 2 19 2. + <_> + + <_> + 1 4 22 2 -1. + <_> + 1 5 22 1 2. + <_> + + <_> + 0 0 9 6 -1. + <_> + 0 2 9 2 3. + <_> + + <_> + 0 0 24 18 -1. + <_> + 0 9 24 9 2. + <_> + + <_> + 3 2 16 8 -1. + <_> + 3 6 16 4 2. + <_> + + <_> + 3 6 18 6 -1. + <_> + 3 8 18 2 3. + <_> + + <_> + 3 1 6 10 -1. + <_> + 5 1 2 10 3. + <_> + + <_> + 13 0 9 6 -1. + <_> + 16 0 3 6 3. + <_> + + <_> + 2 0 9 6 -1. + <_> + 5 0 3 6 3. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 6 0 7 10 -1. + <_> + 6 5 7 5 2. + <_> + + <_> + 2 2 20 4 -1. + <_> + 12 2 10 2 2. + <_> + 2 4 10 2 2. + <_> + + <_> + 2 11 19 3 -1. + <_> + 2 12 19 1 3. + <_> + + <_> + 10 8 6 9 -1. + <_> + 12 8 2 9 3. + <_> + + <_> + 8 8 6 9 -1. + <_> + 10 8 2 9 3. + <_> + + <_> + 13 8 4 9 -1. + <_> + 13 8 2 9 2. + <_> + + <_> + 3 11 9 9 -1. + <_> + 6 11 3 9 3. + <_> + + <_> + 3 9 18 5 -1. + <_> + 9 9 6 5 3. + <_> + + <_> + 2 4 2 20 -1. + <_> + 2 14 2 10 2. + <_> + + <_> + 14 17 8 6 -1. + <_> + 14 20 8 3 2. + <_> + + <_> + 3 21 18 2 -1. + <_> + 3 22 18 1 2. + <_> + + <_> + 5 4 15 6 -1. + <_> + 10 4 5 6 3. + <_> + + <_> + 2 15 12 6 -1. + <_> + 2 17 12 2 3. + <_> + + <_> + 17 8 6 9 -1. + <_> + 17 11 6 3 3. + <_> + + <_> + 2 12 20 4 -1. + <_> + 2 12 10 2 2. + <_> + 12 14 10 2 2. + <_> + + <_> + 0 17 24 6 -1. + <_> + 0 19 24 2 3. + <_> + + <_> + 7 16 9 4 -1. + <_> + 7 18 9 2 2. + <_> + + <_> + 15 1 4 22 -1. + <_> + 17 1 2 11 2. + <_> + 15 12 2 11 2. + <_> + + <_> + 5 1 4 22 -1. + <_> + 5 1 2 11 2. + <_> + 7 12 2 11 2. + <_> + + <_> + 11 13 8 9 -1. + <_> + 11 16 8 3 3. + <_> + + <_> + 6 1 6 9 -1. + <_> + 8 1 2 9 3. + <_> + + <_> + 11 4 3 18 -1. + <_> + 11 10 3 6 3. + <_> + + <_> + 5 8 12 6 -1. + <_> + 5 8 6 3 2. + <_> + 11 11 6 3 2. + <_> + + <_> + 15 7 5 8 -1. + <_> + 15 11 5 4 2. + <_> + + <_> + 4 7 5 8 -1. + <_> + 4 11 5 4 2. + <_> + + <_> + 12 6 6 12 -1. + <_> + 15 6 3 6 2. + <_> + 12 12 3 6 2. + <_> + + <_> + 6 6 6 12 -1. + <_> + 6 6 3 6 2. + <_> + 9 12 3 6 2. + <_> + + <_> + 5 9 14 8 -1. + <_> + 12 9 7 4 2. + <_> + 5 13 7 4 2. + <_> + + <_> + 9 1 3 14 -1. + <_> + 9 8 3 7 2. + <_> + + <_> + 12 6 6 12 -1. + <_> + 12 10 6 4 3. + <_> + + <_> + 4 5 4 18 -1. + <_> + 4 5 2 9 2. + <_> + 6 14 2 9 2. + <_> + + <_> + 4 6 16 18 -1. + <_> + 4 12 16 6 3. + <_> + + <_> + 5 4 7 20 -1. + <_> + 5 14 7 10 2. + <_> + + <_> + 14 8 8 12 -1. + <_> + 14 14 8 6 2. + <_> + + <_> + 9 10 6 14 -1. + <_> + 9 10 3 7 2. + <_> + 12 17 3 7 2. + <_> + + <_> + 9 5 9 6 -1. + <_> + 12 5 3 6 3. + <_> + + <_> + 9 4 3 18 -1. + <_> + 10 4 1 18 3. + <_> + + <_> + 1 4 22 14 -1. + <_> + 12 4 11 7 2. + <_> + 1 11 11 7 2. + <_> + + <_> + 2 7 18 2 -1. + <_> + 2 8 18 1 2. + <_> + + <_> + 12 6 6 12 -1. + <_> + 12 10 6 4 3. + <_> + + <_> + 6 5 9 7 -1. + <_> + 9 5 3 7 3. + <_> + + <_> + 12 7 4 12 -1. + <_> + 12 13 4 6 2. + <_> + + <_> + 8 7 4 12 -1. + <_> + 8 13 4 6 2. + <_> + + <_> + 7 2 10 22 -1. + <_> + 7 13 10 11 2. + <_> + + <_> + 0 1 3 20 -1. + <_> + 1 1 1 20 3. + <_> + + <_> + 4 13 18 4 -1. + <_> + 13 13 9 2 2. + <_> + 4 15 9 2 2. + <_> + + <_> + 2 13 18 4 -1. + <_> + 2 13 9 2 2. + <_> + 11 15 9 2 2. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 6 0 18 24 -1. + <_> + 15 0 9 12 2. + <_> + 6 12 9 12 2. + <_> + + <_> + 6 6 6 12 -1. + <_> + 6 10 6 4 3. + <_> + + <_> + 8 7 10 4 -1. + <_> + 8 9 10 2 2. + <_> + + <_> + 1 9 18 6 -1. + <_> + 1 9 9 3 2. + <_> + 10 12 9 3 2. + <_> + + <_> + 6 6 18 3 -1. + <_> + 6 7 18 1 3. + <_> + + <_> + 7 7 9 8 -1. + <_> + 10 7 3 8 3. + <_> + + <_> + 10 12 6 12 -1. + <_> + 12 12 2 12 3. + <_> + + <_> + 3 14 18 3 -1. + <_> + 3 15 18 1 3. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 1 12 10 6 -1. + <_> + 1 14 10 2 3. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 10 3 3 19 -1. + <_> + 11 3 1 19 3. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 6 1 11 9 -1. + <_> + 6 4 11 3 3. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 6 5 11 6 -1. + <_> + 6 8 11 3 2. + <_> + + <_> + 16 7 8 5 -1. + <_> + 16 7 4 5 2. + <_> + + <_> + 2 4 20 19 -1. + <_> + 12 4 10 19 2. + <_> + + <_> + 2 1 21 6 -1. + <_> + 9 1 7 6 3. + <_> + + <_> + 6 5 12 14 -1. + <_> + 6 5 6 7 2. + <_> + 12 12 6 7 2. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 2 11 8 5 -1. + <_> + 6 11 4 5 2. + <_> + + <_> + 16 7 8 5 -1. + <_> + 16 7 4 5 2. + <_> + + <_> + 0 7 8 5 -1. + <_> + 4 7 4 5 2. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 8 6 8 10 -1. + <_> + 8 6 4 5 2. + <_> + 12 11 4 5 2. + <_> + + <_> + 15 15 9 9 -1. + <_> + 18 15 3 9 3. + <_> + + <_> + 0 15 9 9 -1. + <_> + 3 15 3 9 3. + <_> + + <_> + 12 10 9 7 -1. + <_> + 15 10 3 7 3. + <_> + + <_> + 3 10 9 7 -1. + <_> + 6 10 3 7 3. + <_> + + <_> + 13 15 10 8 -1. + <_> + 18 15 5 4 2. + <_> + 13 19 5 4 2. + <_> + + <_> + 0 1 6 12 -1. + <_> + 0 1 3 6 2. + <_> + 3 7 3 6 2. + <_> + + <_> + 10 0 6 12 -1. + <_> + 13 0 3 6 2. + <_> + 10 6 3 6 2. + <_> + + <_> + 7 0 10 12 -1. + <_> + 7 0 5 6 2. + <_> + 12 6 5 6 2. + <_> + + <_> + 4 1 16 8 -1. + <_> + 4 1 8 8 2. + <_> + + <_> + 0 21 19 3 -1. + <_> + 0 22 19 1 3. + <_> + + <_> + 6 9 18 4 -1. + <_> + 15 9 9 2 2. + <_> + 6 11 9 2 2. + <_> + + <_> + 3 4 9 6 -1. + <_> + 3 6 9 2 3. + <_> + + <_> + 9 1 6 15 -1. + <_> + 9 6 6 5 3. + <_> + + <_> + 5 9 6 6 -1. + <_> + 8 9 3 6 2. + <_> + + <_> + 5 1 14 9 -1. + <_> + 5 4 14 3 3. + <_> + + <_> + 3 0 8 20 -1. + <_> + 3 0 4 10 2. + <_> + 7 10 4 10 2. + <_> + + <_> + 5 0 7 9 -1. + <_> + 5 3 7 3 3. + <_> + + <_> + 6 6 12 5 -1. + <_> + 10 6 4 5 3. + <_> + + <_> + 0 1 8 14 -1. + <_> + 4 1 4 14 2. + <_> + + <_> + 2 12 22 4 -1. + <_> + 2 14 22 2 2. + <_> + + <_> + 8 17 6 6 -1. + <_> + 8 20 6 3 2. + <_> + + <_> + 18 1 6 7 -1. + <_> + 18 1 3 7 2. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 4 6 17 18 -1. + <_> + 4 12 17 6 3. + <_> + + <_> + 6 0 12 6 -1. + <_> + 6 0 6 3 2. + <_> + 12 3 6 3 2. + <_> + + <_> + 4 7 18 4 -1. + <_> + 13 7 9 2 2. + <_> + 4 9 9 2 2. + <_> + + <_> + 4 12 10 6 -1. + <_> + 4 14 10 2 3. + <_> + + <_> + 7 9 10 12 -1. + <_> + 12 9 5 6 2. + <_> + 7 15 5 6 2. + <_> + + <_> + 0 1 24 3 -1. + <_> + 8 1 8 3 3. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 5 11 6 6 -1. + <_> + 8 11 3 6 2. + <_> + + <_> + 3 10 19 3 -1. + <_> + 3 11 19 1 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 0 5 6 3 3. + <_> + + <_> + 14 16 10 6 -1. + <_> + 14 18 10 2 3. + <_> + + <_> + 0 16 10 6 -1. + <_> + 0 18 10 2 3. + <_> + + <_> + 14 13 9 6 -1. + <_> + 14 15 9 2 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 0 18 9 6 -1. + <_> + 0 20 9 2 3. + <_> + + <_> + 14 13 9 6 -1. + <_> + 14 15 9 2 3. + <_> + + <_> + 6 2 6 9 -1. + <_> + 8 2 2 9 3. + <_> + + <_> + 15 8 4 12 -1. + <_> + 15 8 2 12 2. + <_> + + <_> + 8 13 8 8 -1. + <_> + 8 17 8 4 2. + <_> + + <_> + 4 20 18 3 -1. + <_> + 10 20 6 3 3. + <_> + + <_> + 5 8 4 12 -1. + <_> + 7 8 2 12 2. + <_> + + <_> + 7 7 12 3 -1. + <_> + 7 7 6 3 2. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 5 20 18 3 -1. + <_> + 11 20 6 3 3. + <_> + + <_> + 1 20 18 3 -1. + <_> + 7 20 6 3 3. + <_> + + <_> + 18 1 6 20 -1. + <_> + 21 1 3 10 2. + <_> + 18 11 3 10 2. + <_> + + <_> + 0 1 6 20 -1. + <_> + 0 1 3 10 2. + <_> + 3 11 3 10 2. + <_> + + <_> + 13 3 4 18 -1. + <_> + 15 3 2 9 2. + <_> + 13 12 2 9 2. + <_> + + <_> + 0 2 6 12 -1. + <_> + 0 6 6 4 3. + <_> + + <_> + 12 9 12 6 -1. + <_> + 18 9 6 3 2. + <_> + 12 12 6 3 2. + <_> + + <_> + 7 3 4 18 -1. + <_> + 7 3 2 9 2. + <_> + 9 12 2 9 2. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 0 9 12 6 -1. + <_> + 0 9 6 3 2. + <_> + 6 12 6 3 2. + <_> + + <_> + 14 4 8 20 -1. + <_> + 18 4 4 10 2. + <_> + 14 14 4 10 2. + <_> + + <_> + 2 4 8 20 -1. + <_> + 2 4 4 10 2. + <_> + 6 14 4 10 2. + <_> + + <_> + 14 13 9 6 -1. + <_> + 14 15 9 2 3. + <_> + + <_> + 1 13 9 6 -1. + <_> + 1 15 9 2 3. + <_> + + <_> + 3 15 18 3 -1. + <_> + 9 15 6 3 3. + <_> + + <_> + 5 13 9 6 -1. + <_> + 5 15 9 2 3. + <_> + + <_> + 5 0 18 3 -1. + <_> + 5 1 18 1 3. + <_> + + <_> + 8 2 6 7 -1. + <_> + 11 2 3 7 2. + <_> + + <_> + 9 1 9 6 -1. + <_> + 12 1 3 6 3. + <_> + + <_> + 6 1 9 6 -1. + <_> + 9 1 3 6 3. + <_> + + <_> + 5 6 14 6 -1. + <_> + 12 6 7 3 2. + <_> + 5 9 7 3 2. + <_> + + <_> + 8 2 6 13 -1. + <_> + 10 2 2 13 3. + <_> + + <_> + 6 11 12 6 -1. + <_> + 12 11 6 3 2. + <_> + 6 14 6 3 2. + <_> + + <_> + 3 1 18 15 -1. + <_> + 9 1 6 15 3. + <_> + + <_> + 13 0 6 7 -1. + <_> + 13 0 3 7 2. + <_> + + <_> + 3 3 16 6 -1. + <_> + 3 6 16 3 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 7 7 6 9 -1. + <_> + 9 7 2 9 3. + <_> + + <_> + 13 0 4 24 -1. + <_> + 13 0 2 24 2. + <_> + + <_> + 7 0 4 24 -1. + <_> + 9 0 2 24 2. + <_> + + <_> + 11 9 5 12 -1. + <_> + 11 13 5 4 3. + <_> + + <_> + 7 15 9 6 -1. + <_> + 7 17 9 2 3. + <_> + + <_> + 5 7 18 6 -1. + <_> + 5 9 18 2 3. + <_> + + <_> + 8 9 5 12 -1. + <_> + 8 13 5 4 3. + <_> + + <_> + 4 17 17 6 -1. + <_> + 4 19 17 2 3. + <_> + + <_> + 0 3 18 14 -1. + <_> + 0 3 9 7 2. + <_> + 9 10 9 7 2. + <_> + + <_> + 0 1 24 2 -1. + <_> + 0 2 24 1 2. + <_> + + <_> + 0 15 18 3 -1. + <_> + 0 16 18 1 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 3 3 14 12 -1. + <_> + 3 9 14 6 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 8 0 6 9 -1. + <_> + 10 0 2 9 3. + <_> + + <_> + 10 6 6 10 -1. + <_> + 12 6 2 10 3. + <_> + + <_> + 5 0 6 9 -1. + <_> + 7 0 2 9 3. + <_> + + <_> + 2 0 21 7 -1. + <_> + 9 0 7 7 3. + <_> + + <_> + 6 11 12 5 -1. + <_> + 10 11 4 5 3. + <_> + + <_> + 8 7 9 8 -1. + <_> + 11 7 3 8 3. + <_> + + <_> + 9 6 6 18 -1. + <_> + 9 6 3 9 2. + <_> + 12 15 3 9 2. + <_> + + <_> + 15 14 8 10 -1. + <_> + 19 14 4 5 2. + <_> + 15 19 4 5 2. + <_> + + <_> + 1 14 8 10 -1. + <_> + 1 14 4 5 2. + <_> + 5 19 4 5 2. + <_> + + <_> + 11 0 8 10 -1. + <_> + 15 0 4 5 2. + <_> + 11 5 4 5 2. + <_> + + <_> + 5 0 8 10 -1. + <_> + 5 0 4 5 2. + <_> + 9 5 4 5 2. + <_> + + <_> + 6 1 12 5 -1. + <_> + 6 1 6 5 2. + <_> + + <_> + 1 12 18 2 -1. + <_> + 10 12 9 2 2. + <_> + + <_> + 2 8 20 6 -1. + <_> + 12 8 10 3 2. + <_> + 2 11 10 3 2. + <_> + + <_> + 7 6 9 7 -1. + <_> + 10 6 3 7 3. + <_> + + <_> + 10 5 8 16 -1. + <_> + 14 5 4 8 2. + <_> + 10 13 4 8 2. + <_> + + <_> + 3 9 16 8 -1. + <_> + 3 9 8 4 2. + <_> + 11 13 8 4 2. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 8 5 4 2. + <_> + + <_> + 7 12 10 8 -1. + <_> + 7 12 5 4 2. + <_> + 12 16 5 4 2. + <_> + + <_> + 9 19 15 4 -1. + <_> + 14 19 5 4 3. + <_> + + <_> + 1 0 18 9 -1. + <_> + 7 0 6 9 3. + <_> + + <_> + 13 4 10 8 -1. + <_> + 18 4 5 4 2. + <_> + 13 8 5 4 2. + <_> + + <_> + 3 16 18 4 -1. + <_> + 9 16 6 4 3. + <_> + + <_> + 8 7 10 12 -1. + <_> + 13 7 5 6 2. + <_> + 8 13 5 6 2. + <_> + + <_> + 6 7 10 12 -1. + <_> + 6 7 5 6 2. + <_> + 11 13 5 6 2. + <_> + + <_> + 4 6 18 7 -1. + <_> + 10 6 6 7 3. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 3 17 18 3 -1. + <_> + 3 18 18 1 3. + <_> + + <_> + 2 4 6 10 -1. + <_> + 4 4 2 10 3. + <_> + + <_> + 16 0 8 24 -1. + <_> + 16 0 4 24 2. + <_> + + <_> + 4 0 8 15 -1. + <_> + 8 0 4 15 2. + <_> + + <_> + 16 0 8 24 -1. + <_> + 16 0 4 24 2. + <_> + + <_> + 1 4 18 9 -1. + <_> + 7 4 6 9 3. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 3 9 18 6 -1. + <_> + 3 9 9 3 2. + <_> + 12 12 9 3 2. + <_> + + <_> + 18 5 6 9 -1. + <_> + 18 8 6 3 3. + <_> + + <_> + 0 5 6 9 -1. + <_> + 0 8 6 3 3. + <_> + + <_> + 4 7 18 4 -1. + <_> + 13 7 9 2 2. + <_> + 4 9 9 2 2. + <_> + + <_> + 2 1 12 20 -1. + <_> + 2 1 6 10 2. + <_> + 8 11 6 10 2. + <_> + + <_> + 17 0 6 23 -1. + <_> + 17 0 3 23 2. + <_> + + <_> + 1 6 2 18 -1. + <_> + 1 15 2 9 2. + <_> + + <_> + 8 8 10 6 -1. + <_> + 8 10 10 2 3. + <_> + + <_> + 0 6 20 6 -1. + <_> + 0 6 10 3 2. + <_> + 10 9 10 3 2. + <_> + + <_> + 11 12 12 5 -1. + <_> + 15 12 4 5 3. + <_> + + <_> + 0 4 3 19 -1. + <_> + 1 4 1 19 3. + <_> + + <_> + 19 1 3 18 -1. + <_> + 20 1 1 18 3. + <_> + + <_> + 2 1 3 18 -1. + <_> + 3 1 1 18 3. + <_> + + <_> + 3 10 18 3 -1. + <_> + 9 10 6 3 3. + <_> + + <_> + 4 4 10 9 -1. + <_> + 9 4 5 9 2. + <_> + + <_> + 7 13 14 7 -1. + <_> + 7 13 7 7 2. + <_> + + <_> + 3 13 14 7 -1. + <_> + 10 13 7 7 2. + <_> + + <_> + 8 15 9 6 -1. + <_> + 11 15 3 6 3. + <_> + + <_> + 4 14 8 10 -1. + <_> + 4 14 4 5 2. + <_> + 8 19 4 5 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 3 8 5 16 -1. + <_> + 3 16 5 8 2. + <_> + + <_> + 15 10 9 6 -1. + <_> + 15 12 9 2 3. + <_> + + <_> + 0 10 9 6 -1. + <_> + 0 12 9 2 3. + <_> + + <_> + 6 7 12 9 -1. + <_> + 6 10 12 3 3. + <_> + + <_> + 9 10 5 8 -1. + <_> + 9 14 5 4 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 8 15 6 9 -1. + <_> + 10 15 2 9 3. + <_> + + <_> + 16 6 7 6 -1. + <_> + 16 9 7 3 2. + <_> + + <_> + 8 1 4 22 -1. + <_> + 10 1 2 22 2. + <_> + + <_> + 6 6 14 3 -1. + <_> + 6 6 7 3 2. + <_> + + <_> + 0 18 19 3 -1. + <_> + 0 19 19 1 3. + <_> + + <_> + 17 0 6 24 -1. + <_> + 17 0 3 24 2. + <_> + + <_> + 0 13 15 6 -1. + <_> + 5 13 5 6 3. + <_> + + <_> + 9 6 10 14 -1. + <_> + 14 6 5 7 2. + <_> + 9 13 5 7 2. + <_> + + <_> + 1 6 8 10 -1. + <_> + 1 6 4 5 2. + <_> + 5 11 4 5 2. + <_> + + <_> + 7 6 12 5 -1. + <_> + 7 6 6 5 2. + <_> + + <_> + 7 7 9 6 -1. + <_> + 10 7 3 6 3. + <_> + + <_> + 7 8 14 14 -1. + <_> + 14 8 7 7 2. + <_> + 7 15 7 7 2. + <_> + + <_> + 3 8 14 14 -1. + <_> + 3 8 7 7 2. + <_> + 10 15 7 7 2. + <_> + + <_> + 9 8 13 4 -1. + <_> + 9 10 13 2 2. + <_> + + <_> + 3 2 6 12 -1. + <_> + 3 2 3 6 2. + <_> + 6 8 3 6 2. + <_> + + <_> + 6 10 17 6 -1. + <_> + 6 13 17 3 2. + <_> + + <_> + 1 10 17 6 -1. + <_> + 1 13 17 3 2. + <_> + + <_> + 16 7 8 9 -1. + <_> + 16 10 8 3 3. + <_> + + <_> + 0 7 8 9 -1. + <_> + 0 10 8 3 3. + <_> + + <_> + 0 9 24 10 -1. + <_> + 12 9 12 5 2. + <_> + 0 14 12 5 2. + <_> + + <_> + 3 2 15 8 -1. + <_> + 8 2 5 8 3. + <_> + + <_> + 4 2 18 8 -1. + <_> + 10 2 6 8 3. + <_> + + <_> + 0 1 18 4 -1. + <_> + 0 1 9 2 2. + <_> + 9 3 9 2 2. + <_> + + <_> + 20 2 3 18 -1. + <_> + 21 2 1 18 3. + <_> + + <_> + 1 3 3 19 -1. + <_> + 2 3 1 19 3. + <_> + + <_> + 18 8 6 16 -1. + <_> + 20 8 2 16 3. + <_> + + <_> + 0 8 6 16 -1. + <_> + 2 8 2 16 3. + <_> + + <_> + 8 18 11 6 -1. + <_> + 8 20 11 2 3. + <_> + + <_> + 4 6 12 5 -1. + <_> + 8 6 4 5 3. + <_> + + <_> + 7 6 12 5 -1. + <_> + 11 6 4 5 3. + <_> + + <_> + 6 3 9 6 -1. + <_> + 9 3 3 6 3. + <_> + + <_> + 7 6 12 5 -1. + <_> + 7 6 6 5 2. + <_> + + <_> + 9 8 6 7 -1. + <_> + 12 8 3 7 2. + <_> + + <_> + 8 2 9 6 -1. + <_> + 11 2 3 6 3. + <_> + + <_> + 8 14 6 9 -1. + <_> + 8 17 6 3 3. + <_> + + <_> + 8 2 9 6 -1. + <_> + 11 2 3 6 3. + <_> + + <_> + 4 3 16 20 -1. + <_> + 4 3 8 10 2. + <_> + 12 13 8 10 2. + <_> + + <_> + 7 6 10 12 -1. + <_> + 12 6 5 6 2. + <_> + 7 12 5 6 2. + <_> + + <_> + 0 2 7 12 -1. + <_> + 0 6 7 4 3. + <_> + + <_> + 12 17 11 6 -1. + <_> + 12 19 11 2 3. + <_> + + <_> + 4 7 12 8 -1. + <_> + 4 7 6 4 2. + <_> + 10 11 6 4 2. + <_> + + <_> + 8 11 8 10 -1. + <_> + 12 11 4 5 2. + <_> + 8 16 4 5 2. + <_> + + <_> + 9 1 4 9 -1. + <_> + 11 1 2 9 2. + <_> + + <_> + 14 0 3 22 -1. + <_> + 15 0 1 22 3. + <_> + + <_> + 7 0 3 22 -1. + <_> + 8 0 1 22 3. + <_> + + <_> + 4 7 18 4 -1. + <_> + 13 7 9 2 2. + <_> + 4 9 9 2 2. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 0 0 18 13 -1. + <_> + 9 0 9 13 2. + <_> + + <_> + 16 0 3 24 -1. + <_> + 17 0 1 24 3. + <_> + + <_> + 5 0 3 24 -1. + <_> + 6 0 1 24 3. + <_> + + <_> + 10 15 5 8 -1. + <_> + 10 19 5 4 2. + <_> + + <_> + 2 18 18 2 -1. + <_> + 2 19 18 1 2. + <_> + + <_> + 2 8 20 3 -1. + <_> + 2 9 20 1 3. + <_> + + <_> + 7 6 9 6 -1. + <_> + 7 8 9 2 3. + <_> + + <_> + 3 2 19 10 -1. + <_> + 3 7 19 5 2. + <_> + + <_> + 2 7 19 3 -1. + <_> + 2 8 19 1 3. + <_> + + <_> + 15 6 9 4 -1. + <_> + 15 8 9 2 2. + <_> + + <_> + 2 2 18 8 -1. + <_> + 8 2 6 8 3. + <_> + + <_> + 10 9 14 4 -1. + <_> + 10 9 7 4 2. + <_> + + <_> + 4 4 6 16 -1. + <_> + 7 4 3 16 2. + <_> + + <_> + 15 8 9 16 -1. + <_> + 18 8 3 16 3. + <_> + + <_> + 0 8 9 16 -1. + <_> + 3 8 3 16 3. + <_> + + <_> + 18 0 6 14 -1. + <_> + 20 0 2 14 3. + <_> + + <_> + 0 0 6 14 -1. + <_> + 2 0 2 14 3. + <_> + + <_> + 15 0 6 22 -1. + <_> + 17 0 2 22 3. + <_> + + <_> + 3 0 6 22 -1. + <_> + 5 0 2 22 3. + <_> + + <_> + 12 2 12 20 -1. + <_> + 16 2 4 20 3. + <_> + + <_> + 0 2 12 20 -1. + <_> + 4 2 4 20 3. + <_> + + <_> + 11 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 9 0 6 16 -1. + <_> + 12 0 3 16 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 3 4 18 6 -1. + <_> + 3 4 9 3 2. + <_> + 12 7 9 3 2. + <_> + + <_> + 5 5 16 8 -1. + <_> + 13 5 8 4 2. + <_> + 5 9 8 4 2. + <_> + + <_> + 0 13 10 6 -1. + <_> + 0 15 10 2 3. + <_> + + <_> + 8 14 9 6 -1. + <_> + 8 16 9 2 3. + <_> + + <_> + 6 2 9 6 -1. + <_> + 9 2 3 6 3. + <_> + + <_> + 14 1 10 8 -1. + <_> + 19 1 5 4 2. + <_> + 14 5 5 4 2. + <_> + + <_> + 9 1 3 12 -1. + <_> + 9 7 3 6 2. + <_> + + <_> + 6 4 12 9 -1. + <_> + 6 7 12 3 3. + <_> + + <_> + 6 5 12 6 -1. + <_> + 10 5 4 6 3. + <_> + + <_> + 1 1 8 5 -1. + <_> + 5 1 4 5 2. + <_> + + <_> + 12 12 6 8 -1. + <_> + 12 16 6 4 2. + <_> + + <_> + 3 12 12 6 -1. + <_> + 3 14 12 2 3. + <_> + + <_> + 9 18 12 6 -1. + <_> + 15 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 4 13 6 6 -1. + <_> + 4 16 6 3 2. + <_> + + <_> + 11 3 7 18 -1. + <_> + 11 12 7 9 2. + <_> + + <_> + 3 9 18 3 -1. + <_> + 9 9 6 3 3. + <_> + + <_> + 5 3 19 2 -1. + <_> + 5 4 19 1 2. + <_> + + <_> + 4 2 12 6 -1. + <_> + 4 2 6 3 2. + <_> + 10 5 6 3 2. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 16 9 5 15 -1. + <_> + 16 14 5 5 3. + <_> + + <_> + 3 9 5 15 -1. + <_> + 3 14 5 5 3. + <_> + + <_> + 6 6 14 6 -1. + <_> + 13 6 7 3 2. + <_> + 6 9 7 3 2. + <_> + + <_> + 8 6 3 14 -1. + <_> + 8 13 3 7 2. + <_> + + <_> + 0 16 24 5 -1. + <_> + 8 16 8 5 3. + <_> + + <_> + 0 20 20 3 -1. + <_> + 10 20 10 3 2. + <_> + + <_> + 5 10 18 2 -1. + <_> + 5 11 18 1 2. + <_> + + <_> + 0 6 6 10 -1. + <_> + 2 6 2 10 3. + <_> + + <_> + 2 1 20 3 -1. + <_> + 2 2 20 1 3. + <_> + + <_> + 9 13 6 11 -1. + <_> + 11 13 2 11 3. + <_> + + <_> + 9 15 6 8 -1. + <_> + 9 19 6 4 2. + <_> + + <_> + 9 12 6 9 -1. + <_> + 9 15 6 3 3. + <_> + + <_> + 5 11 18 2 -1. + <_> + 5 12 18 1 2. + <_> + + <_> + 2 6 15 6 -1. + <_> + 2 8 15 2 3. + <_> + + <_> + 6 0 18 3 -1. + <_> + 6 1 18 1 3. + <_> + + <_> + 5 0 3 18 -1. + <_> + 6 0 1 18 3. + <_> + + <_> + 18 3 6 10 -1. + <_> + 20 3 2 10 3. + <_> + + <_> + 0 3 6 10 -1. + <_> + 2 3 2 10 3. + <_> + + <_> + 10 5 8 9 -1. + <_> + 10 5 4 9 2. + <_> + + <_> + 6 5 8 9 -1. + <_> + 10 5 4 9 2. + <_> + + <_> + 3 2 20 3 -1. + <_> + 3 3 20 1 3. + <_> + + <_> + 5 2 13 4 -1. + <_> + 5 4 13 2 2. + <_> + + <_> + 17 0 7 14 -1. + <_> + 17 7 7 7 2. + <_> + + <_> + 0 0 7 14 -1. + <_> + 0 7 7 7 2. + <_> + + <_> + 9 11 10 6 -1. + <_> + 9 11 5 6 2. + <_> + + <_> + 5 11 10 6 -1. + <_> + 10 11 5 6 2. + <_> + + <_> + 11 6 3 18 -1. + <_> + 11 12 3 6 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 4 6 9 10 -1. + <_> + 4 11 9 5 2. + <_> + + <_> + 9 7 15 4 -1. + <_> + 9 9 15 2 2. + <_> + + <_> + 5 6 12 6 -1. + <_> + 5 6 6 3 2. + <_> + 11 9 6 3 2. + <_> + + <_> + 6 1 12 9 -1. + <_> + 6 4 12 3 3. + <_> + + <_> + 7 9 6 12 -1. + <_> + 7 9 3 6 2. + <_> + 10 15 3 6 2. + <_> + + <_> + 11 5 13 6 -1. + <_> + 11 7 13 2 3. + <_> + + <_> + 1 11 22 13 -1. + <_> + 12 11 11 13 2. + <_> + + <_> + 18 8 6 6 -1. + <_> + 18 11 6 3 2. + <_> + + <_> + 0 8 6 6 -1. + <_> + 0 11 6 3 2. + <_> + + <_> + 0 6 24 3 -1. + <_> + 0 7 24 1 3. + <_> + + <_> + 0 5 10 6 -1. + <_> + 0 7 10 2 3. + <_> + + <_> + 6 7 18 3 -1. + <_> + 6 8 18 1 3. + <_> + + <_> + 0 0 10 6 -1. + <_> + 0 2 10 2 3. + <_> + + <_> + 19 0 3 19 -1. + <_> + 20 0 1 19 3. + <_> + + <_> + 4 6 12 16 -1. + <_> + 4 6 6 8 2. + <_> + 10 14 6 8 2. + <_> + + <_> + 19 6 4 18 -1. + <_> + 21 6 2 9 2. + <_> + 19 15 2 9 2. + <_> + + <_> + 1 6 4 18 -1. + <_> + 1 6 2 9 2. + <_> + 3 15 2 9 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 3 22 18 1 3. + <_> + + <_> + 0 19 9 4 -1. + <_> + 0 21 9 2 2. + <_> + + <_> + 12 18 12 6 -1. + <_> + 18 18 6 3 2. + <_> + 12 21 6 3 2. + <_> + + <_> + 7 18 9 4 -1. + <_> + 7 20 9 2 2. + <_> + + <_> + 12 16 10 8 -1. + <_> + 17 16 5 4 2. + <_> + 12 20 5 4 2. + <_> + + <_> + 2 16 10 8 -1. + <_> + 2 16 5 4 2. + <_> + 7 20 5 4 2. + <_> + + <_> + 14 0 10 12 -1. + <_> + 19 0 5 6 2. + <_> + 14 6 5 6 2. + <_> + + <_> + 0 0 10 12 -1. + <_> + 0 0 5 6 2. + <_> + 5 6 5 6 2. + <_> + + <_> + 15 14 9 6 -1. + <_> + 15 16 9 2 3. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 14 14 10 6 -1. + <_> + 14 16 10 2 3. + <_> + + <_> + 0 14 10 6 -1. + <_> + 0 16 10 2 3. + <_> + + <_> + 5 18 18 2 -1. + <_> + 5 19 18 1 2. + <_> + + <_> + 0 18 18 3 -1. + <_> + 0 19 18 1 3. + <_> + + <_> + 3 5 18 12 -1. + <_> + 12 5 9 6 2. + <_> + 3 11 9 6 2. + <_> + + <_> + 5 3 7 9 -1. + <_> + 5 6 7 3 3. + <_> + + <_> + 4 0 19 15 -1. + <_> + 4 5 19 5 3. + <_> + + <_> + 3 0 16 4 -1. + <_> + 3 2 16 2 2. + <_> + + <_> + 4 12 16 12 -1. + <_> + 4 12 8 12 2. + <_> + + <_> + 4 3 12 15 -1. + <_> + 10 3 6 15 2. + <_> + + <_> + 16 4 2 19 -1. + <_> + 16 4 1 19 2. + <_> + + <_> + 6 4 2 19 -1. + <_> + 7 4 1 19 2. + <_> + + <_> + 13 14 8 10 -1. + <_> + 17 14 4 5 2. + <_> + 13 19 4 5 2. + <_> + + <_> + 3 14 8 10 -1. + <_> + 3 14 4 5 2. + <_> + 7 19 4 5 2. + <_> + + <_> + 12 6 3 18 -1. + <_> + 12 12 3 6 3. + <_> + + <_> + 5 11 12 6 -1. + <_> + 5 11 6 3 2. + <_> + 11 14 6 3 2. + <_> + + <_> + 10 5 8 10 -1. + <_> + 14 5 4 5 2. + <_> + 10 10 4 5 2. + <_> + + <_> + 6 4 12 10 -1. + <_> + 6 4 6 5 2. + <_> + 12 9 6 5 2. + <_> + + <_> + 6 8 18 10 -1. + <_> + 15 8 9 5 2. + <_> + 6 13 9 5 2. + <_> + + <_> + 0 8 18 10 -1. + <_> + 0 8 9 5 2. + <_> + 9 13 9 5 2. + <_> + + <_> + 12 6 3 18 -1. + <_> + 12 12 3 6 3. + <_> + + <_> + 0 14 18 3 -1. + <_> + 0 15 18 1 3. + <_> + + <_> + 12 6 3 18 -1. + <_> + 12 12 3 6 3. + <_> + + <_> + 9 6 3 18 -1. + <_> + 9 12 3 6 3. + <_> + + <_> + 6 14 18 3 -1. + <_> + 6 15 18 1 3. + <_> + + <_> + 0 5 18 3 -1. + <_> + 0 6 18 1 3. + <_> + + <_> + 2 5 22 3 -1. + <_> + 2 6 22 1 3. + <_> + + <_> + 0 0 21 10 -1. + <_> + 7 0 7 10 3. + <_> + + <_> + 6 3 18 17 -1. + <_> + 12 3 6 17 3. + <_> + + <_> + 0 3 18 17 -1. + <_> + 6 3 6 17 3. + <_> + + <_> + 0 12 24 11 -1. + <_> + 8 12 8 11 3. + <_> + + <_> + 4 10 16 6 -1. + <_> + 4 13 16 3 2. + <_> + + <_> + 12 8 6 8 -1. + <_> + 12 12 6 4 2. + <_> + + <_> + 6 14 8 7 -1. + <_> + 10 14 4 7 2. + <_> + + <_> + 15 10 6 14 -1. + <_> + 18 10 3 7 2. + <_> + 15 17 3 7 2. + <_> + + <_> + 3 10 6 14 -1. + <_> + 3 10 3 7 2. + <_> + 6 17 3 7 2. + <_> + + <_> + 6 12 18 2 -1. + <_> + 6 13 18 1 2. + <_> + + <_> + 5 8 10 6 -1. + <_> + 5 10 10 2 3. + <_> + + <_> + 12 11 9 4 -1. + <_> + 12 13 9 2 2. + <_> + + <_> + 0 11 9 6 -1. + <_> + 0 13 9 2 3. + <_> + + <_> + 11 2 3 18 -1. + <_> + 12 2 1 18 3. + <_> + + <_> + 10 2 3 18 -1. + <_> + 11 2 1 18 3. + <_> + + <_> + 9 12 6 10 -1. + <_> + 11 12 2 10 3. + <_> + + <_> + 1 10 6 9 -1. + <_> + 1 13 6 3 3. + <_> + + <_> + 6 9 16 6 -1. + <_> + 14 9 8 3 2. + <_> + 6 12 8 3 2. + <_> + + <_> + 1 8 9 6 -1. + <_> + 1 10 9 2 3. + <_> + + <_> + 7 7 16 6 -1. + <_> + 7 9 16 2 3. + <_> + + <_> + 0 0 18 3 -1. + <_> + 0 1 18 1 3. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 9 5 6 6 -1. + <_> + 12 5 3 6 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 8 0 6 9 -1. + <_> + 10 0 2 9 3. + <_> + + <_> + 9 1 6 9 -1. + <_> + 9 4 6 3 3. + <_> + + <_> + 1 0 18 9 -1. + <_> + 1 3 18 3 3. + <_> + + <_> + 0 3 24 3 -1. + <_> + 0 4 24 1 3. + <_> + + <_> + 6 14 9 4 -1. + <_> + 6 16 9 2 2. + <_> + + <_> + 8 9 8 10 -1. + <_> + 12 9 4 5 2. + <_> + 8 14 4 5 2. + <_> + + <_> + 5 2 13 9 -1. + <_> + 5 5 13 3 3. + <_> + + <_> + 4 4 16 9 -1. + <_> + 4 7 16 3 3. + <_> + + <_> + 4 4 14 9 -1. + <_> + 4 7 14 3 3. + <_> + + <_> + 8 5 9 6 -1. + <_> + 8 7 9 2 3. + <_> + + <_> + 1 7 16 6 -1. + <_> + 1 9 16 2 3. + <_> + + <_> + 10 5 13 9 -1. + <_> + 10 8 13 3 3. + <_> + + <_> + 1 5 13 9 -1. + <_> + 1 8 13 3 3. + <_> + + <_> + 0 4 24 6 -1. + <_> + 12 4 12 3 2. + <_> + 0 7 12 3 2. + <_> + + <_> + 1 14 10 9 -1. + <_> + 1 17 10 3 3. + <_> + + <_> + 5 17 18 3 -1. + <_> + 5 18 18 1 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 9 17 9 6 -1. + <_> + 9 19 9 2 3. + <_> + + <_> + 1 20 22 4 -1. + <_> + 1 20 11 2 2. + <_> + 12 22 11 2 2. + <_> + + <_> + 8 14 8 6 -1. + <_> + 8 17 8 3 2. + <_> + + <_> + 8 6 8 15 -1. + <_> + 8 11 8 5 3. + <_> + + <_> + 5 4 18 3 -1. + <_> + 5 5 18 1 3. + <_> + + <_> + 9 3 5 10 -1. + <_> + 9 8 5 5 2. + <_> + + <_> + 6 8 12 3 -1. + <_> + 6 8 6 3 2. + <_> + + <_> + 2 6 18 6 -1. + <_> + 2 6 9 3 2. + <_> + 11 9 9 3 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 7 5 6 6 -1. + <_> + 10 5 3 6 2. + <_> + + <_> + 14 5 2 18 -1. + <_> + 14 14 2 9 2. + <_> + + <_> + 8 5 2 18 -1. + <_> + 8 14 2 9 2. + <_> + + <_> + 9 2 10 6 -1. + <_> + 9 2 5 6 2. + <_> + + <_> + 3 1 18 12 -1. + <_> + 12 1 9 12 2. + <_> + + <_> + 5 2 17 22 -1. + <_> + 5 13 17 11 2. + <_> + + <_> + 4 0 12 6 -1. + <_> + 4 2 12 2 3. + <_> + + <_> + 6 9 16 6 -1. + <_> + 14 9 8 3 2. + <_> + 6 12 8 3 2. + <_> + + <_> + 9 0 5 18 -1. + <_> + 9 9 5 9 2. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 9 1 6 12 -1. + <_> + 11 1 2 12 3. + <_> + + <_> + 5 9 13 4 -1. + <_> + 5 11 13 2 2. + <_> + + <_> + 5 8 19 3 -1. + <_> + 5 9 19 1 3. + <_> + + <_> + 9 9 6 8 -1. + <_> + 9 13 6 4 2. + <_> + + <_> + 11 9 4 15 -1. + <_> + 11 14 4 5 3. + <_> + + <_> + 2 0 6 14 -1. + <_> + 2 0 3 7 2. + <_> + 5 7 3 7 2. + <_> + + <_> + 15 1 6 14 -1. + <_> + 18 1 3 7 2. + <_> + 15 8 3 7 2. + <_> + + <_> + 3 1 6 14 -1. + <_> + 3 1 3 7 2. + <_> + 6 8 3 7 2. + <_> + + <_> + 3 20 18 4 -1. + <_> + 12 20 9 2 2. + <_> + 3 22 9 2 2. + <_> + + <_> + 5 0 4 20 -1. + <_> + 5 0 2 10 2. + <_> + 7 10 2 10 2. + <_> + + <_> + 16 8 8 12 -1. + <_> + 20 8 4 6 2. + <_> + 16 14 4 6 2. + <_> + + <_> + 0 8 8 12 -1. + <_> + 0 8 4 6 2. + <_> + 4 14 4 6 2. + <_> + + <_> + 13 13 10 8 -1. + <_> + 18 13 5 4 2. + <_> + 13 17 5 4 2. + <_> + + <_> + 1 13 10 8 -1. + <_> + 1 13 5 4 2. + <_> + 6 17 5 4 2. + <_> + + <_> + 15 8 4 15 -1. + <_> + 15 13 4 5 3. + <_> + + <_> + 5 8 4 15 -1. + <_> + 5 13 4 5 3. + <_> + + <_> + 6 11 16 12 -1. + <_> + 6 15 16 4 3. + <_> + + <_> + 2 11 16 12 -1. + <_> + 2 15 16 4 3. + <_> + + <_> + 14 12 7 9 -1. + <_> + 14 15 7 3 3. + <_> + + <_> + 10 1 3 21 -1. + <_> + 10 8 3 7 3. + <_> + + <_> + 13 11 9 4 -1. + <_> + 13 13 9 2 2. + <_> + + <_> + 3 10 17 9 -1. + <_> + 3 13 17 3 3. + <_> + + <_> + 13 8 8 15 -1. + <_> + 13 13 8 5 3. + <_> + + <_> + 3 8 8 15 -1. + <_> + 3 13 8 5 3. + <_> + + <_> + 11 14 10 8 -1. + <_> + 16 14 5 4 2. + <_> + 11 18 5 4 2. + <_> + + <_> + 0 18 22 6 -1. + <_> + 0 18 11 3 2. + <_> + 11 21 11 3 2. + <_> + + <_> + 0 16 24 4 -1. + <_> + 0 16 12 4 2. + <_> + + <_> + 6 20 12 3 -1. + <_> + 12 20 6 3 2. + <_> + + <_> + 18 12 6 12 -1. + <_> + 21 12 3 6 2. + <_> + 18 18 3 6 2. + <_> + + <_> + 0 12 6 12 -1. + <_> + 0 12 3 6 2. + <_> + 3 18 3 6 2. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 1 6 22 10 -1. + <_> + 1 6 11 5 2. + <_> + 12 11 11 5 2. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 18 18 2 -1. + <_> + 0 19 18 1 2. + <_> + + <_> + 3 15 19 3 -1. + <_> + 3 16 19 1 3. + <_> + + <_> + 0 13 18 3 -1. + <_> + 0 14 18 1 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 17 9 6 -1. + <_> + 0 19 9 2 3. + <_> + + <_> + 12 17 9 6 -1. + <_> + 12 19 9 2 3. + <_> + + <_> + 3 17 9 6 -1. + <_> + 3 19 9 2 3. + <_> + + <_> + 16 2 3 20 -1. + <_> + 17 2 1 20 3. + <_> + + <_> + 0 13 24 8 -1. + <_> + 0 17 24 4 2. + <_> + + <_> + 9 1 6 22 -1. + <_> + 12 1 3 11 2. + <_> + 9 12 3 11 2. + diff --git a/remote_function/requirements.txt b/remote_function/requirements.txt new file mode 100644 index 00000000..89b80f95 --- /dev/null +++ b/remote_function/requirements.txt @@ -0,0 +1,5 @@ +opencv-python==4.5.5.64 +flask +numpy +sk-video +imutils \ No newline at end of file diff --git a/remote_function/udf_server.py b/remote_function/udf_server.py new file mode 100644 index 00000000..922d4e32 --- /dev/null +++ b/remote_function/udf_server.py @@ -0,0 +1,74 @@ +from flask import Flask, request, jsonify, send_file, after_this_request +import cv2 +import numpy as np +import json +from datetime import datetime, timezone +import os +import sys +from collections import defaultdict, deque +import skvideo.io +import imutils + +for entry in os.scandir("functions"): + if entry.is_file(): + string = f"from functions import {entry.name}"[:-3] + exec(string) + +app = Flask(__name__) + +count = 0 + + +def get_current_timestamp(): + dt = datetime.now(timezone.utc) + + utc_time = dt.replace(tzinfo=timezone.utc) + utc_timestamp = utc_time.timestamp() + + return utc_timestamp + + +@app.route("/hello", methods=["GET"]) +def hello(): + return jsonify({"response": "true"}) + + +@app.route("/image", methods=["POST"]) +def image_api(): + json_data = json.loads(request.form["jsonData"]) + image_data = request.files["imageData"] + + format = json_data["format"] if "format" in json_data else "jpg" + + tmpfile = "tmpfile" + str(datetime.now()) + "." + str(format) + + image_data.save(tmpfile) + + udf = globals()[json_data["id"]] + r_img = udf.run(tmpfile, format, json_data) + + return_string = cv2.imencode("." + str(format), r_img)[1].tostring() + os.remove(tmpfile) + return return_string + + +@app.errorhandler(400) +def handle_bad_request(e): + response = e.get_response() + response.data = json.dumps( + { + "code": e.code, + "name": e.name, + "description": e.description, + } + ) + response.content_type = "application/json" + print("400 error:", response) + return response + + +if __name__ == "__main__": + if sys.argv[1] == None: + print("Port missing\n Correct Usage: python3 udf_server.py ") + else: + app.run(host="0.0.0.0", port=int(sys.argv[1])) diff --git a/src/AutoDeleteNode.cc b/src/AutoDeleteNode.cc index 2036a73b..36cc43a4 100644 --- a/src/AutoDeleteNode.cc +++ b/src/AutoDeleteNode.cc @@ -31,22 +31,16 @@ #include "AutoDeleteNode.h" -AutoDeleteNode::AutoDeleteNode(Json::UInt64 new_expiration_timestamp, void* new_node) -{ - _expiration_timestamp = new_expiration_timestamp; - _node = new_node; +AutoDeleteNode::AutoDeleteNode(Json::UInt64 new_expiration_timestamp, + void *new_node) { + _expiration_timestamp = new_expiration_timestamp; + _node = new_node; } -AutoDeleteNode::~AutoDeleteNode() -{ -} +AutoDeleteNode::~AutoDeleteNode() {} -Json::UInt64 AutoDeleteNode::GetExpirationTimestamp() -{ - return _expiration_timestamp; +Json::UInt64 AutoDeleteNode::GetExpirationTimestamp() { + return _expiration_timestamp; } -void* AutoDeleteNode::GetNode() -{ - return _node; -} +void *AutoDeleteNode::GetNode() { return _node; } diff --git a/src/AutoDeleteNode.h b/src/AutoDeleteNode.h index 029132aa..d2ea1605 100644 --- a/src/AutoDeleteNode.h +++ b/src/AutoDeleteNode.h @@ -29,35 +29,32 @@ * */ -#include #include +#include +#include #include -#include #include #include -#include "node.h" #include "iterator.h" +#include "node.h" -class AutoDeleteNode -{ +class AutoDeleteNode { private: - Json::UInt64 _expiration_timestamp; - void* _node; //can use void pointer because query only seraches for Nodes and not edges + Json::UInt64 _expiration_timestamp; + void *_node; // can use void pointer because query only seraches for Nodes and + // not edges public: - AutoDeleteNode(Json::UInt64 new_expiration_timestamp, void* n_node); - ~AutoDeleteNode(); - Json::UInt64 GetExpirationTimestamp(); - void* GetNode(); - + AutoDeleteNode(Json::UInt64 new_expiration_timestamp, void *n_node); + ~AutoDeleteNode(); + Json::UInt64 GetExpirationTimestamp(); + void *GetNode(); }; -struct GreaterThanTimestamp -{ - bool operator()(AutoDeleteNode* lhs, AutoDeleteNode* rhs) const - { - return lhs->GetExpirationTimestamp() > rhs->GetExpirationTimestamp(); - } +struct GreaterThanTimestamp { + bool operator()(AutoDeleteNode *lhs, AutoDeleteNode *rhs) const { + return lhs->GetExpirationTimestamp() > rhs->GetExpirationTimestamp(); + } }; diff --git a/src/BlobCommand.cc b/src/BlobCommand.cc index 1dc92554..b810444a 100644 --- a/src/BlobCommand.cc +++ b/src/BlobCommand.cc @@ -39,205 +39,169 @@ using namespace VDMS; //========= AddBlob definitions ========= -BlobCommand::BlobCommand(const std::string &cmd_name): - RSCommand(cmd_name) -{ -} +BlobCommand::BlobCommand(const std::string &cmd_name) : RSCommand(cmd_name) {} -AddBlob::AddBlob() : BlobCommand("AddBlob") -{ +AddBlob::AddBlob() : BlobCommand("AddBlob") { - _storage_bin = VDMSConfig::instance()->get_path_bin(); + _storage_bin = VDMSConfig::instance()->get_path_bin(); } -int AddBlob::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - // std::cout << " inside ADDBLOB" <(cmd, "_ref", - query.get_available_reference()); - +int AddBlob::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - std::string format = "bin"; - char binary_img_flag = 1; - VCL::Image img((void*)blob.data(), blob.size(), binary_img_flag); + // std::cout << " inside ADDBLOB" <(cmd, "_ref", query.get_available_reference()); + std::string format = "bin"; + char binary_img_flag = 1; + VCL::Image img((void *)blob.data(), blob.size(), binary_img_flag); - std::string blob_root = _storage_bin; - VCL::Image::Format blob_format = VCL::Image::Format::BIN; - std::string file_name = VCL::create_unique(blob_root, format); - // std::cout << "Blob was added in " <<_storage_bin << "\t"<< file_name << std::endl; - Json::Value props = get_value(cmd, "properties"); - props[VDMS_EN_BLOB_PATH_PROP] = file_name; + std::string blob_root = _storage_bin; + VCL::Image::Format blob_format = VCL::Image::Format::BIN; + std::string file_name = VCL::create_unique(blob_root, format); + // std::cout << "Blob was added in " <<_storage_bin << "\t"<< file_name << + // std::endl; + Json::Value props = get_value(cmd, "properties"); + props[VDMS_EN_BLOB_PATH_PROP] = file_name; + query.AddNode(node_ref, VDMS_BLOB_TAG, props, Json::Value()); - query.AddNode(node_ref, VDMS_BLOB_TAG, props, Json::Value()); + img.store(file_name, blob_format); - img.store(file_name, blob_format); + error["Blob_added"] = file_name; + if (cmd.isMember("link")) { + add_link(query, cmd["link"], node_ref, VDMS_BLOB_EDGE_TAG); + } - error["Blob_added"] = file_name; - - if (cmd.isMember("link")) { - add_link(query, cmd["link"], node_ref, VDMS_BLOB_EDGE_TAG); - } - - return 0; + return 0; } //========= UpdateBLOB definitions ========= -UpdateBlob::UpdateBlob() : BlobCommand("UpdateBlob") -{ -} +UpdateBlob::UpdateBlob() : BlobCommand("UpdateBlob") {} + +int UpdateBlob::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + + // Update Image node + query.UpdateNode(get_value(cmd, "_ref", -1), VDMS_BLOB_TAG, + cmd["properties"], cmd["remove_props"], cmd["constraints"], + get_value(cmd, "unique", false)); -int UpdateBlob::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - // Update Image node - query.UpdateNode(get_value(cmd, "_ref", -1), - VDMS_BLOB_TAG, - cmd["properties"], - cmd["remove_props"], - cmd["constraints"], - get_value(cmd, "unique", false)); - - return 0; + return 0; } //========= FindBLOB definitions ========= -FindBlob::FindBlob() : BlobCommand("FindBlob") -{ -} +FindBlob::FindBlob() : BlobCommand("FindBlob") {} -int FindBlob::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; +int FindBlob::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - Json::Value results = get_value(cmd, "results"); + Json::Value results = get_value(cmd, "results"); - // Unless otherwhis specified, we return the blob. - if (get_value(results, "blob", true)){ - results["list"].append(VDMS_EN_BLOB_PATH_PROP); - } + // Unless otherwhis specified, we return the blob. + if (get_value(results, "blob", true)) { + results["list"].append(VDMS_EN_BLOB_PATH_PROP); + } - query.QueryNode( - get_value(cmd, "_ref", -1), - VDMS_BLOB_TAG, - cmd["link"], - cmd["constraints"], - results, - get_value(cmd, "unique", false) - ); + query.QueryNode(get_value(cmd, "_ref", -1), VDMS_BLOB_TAG, cmd["link"], + cmd["constraints"], results, + get_value(cmd, "unique", false)); - return 0; + return 0; } -Json::Value FindBlob::construct_responses( - Json::Value& responses, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - const Json::Value& cmd = json[_cmd_name]; +Json::Value FindBlob::construct_responses(Json::Value &responses, + const Json::Value &json, + protobufs::queryMessage &query_res, + const std::string &blob) { + const Json::Value &cmd = json[_cmd_name]; - Json::Value ret; + Json::Value ret; - auto error = [&](Json::Value& res) - { - ret[_cmd_name] = res; - return ret; - }; - - if (responses.size() != 1) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "PMGD Response Bad Size"; - return error(return_error); - } + auto error = [&](Json::Value &res) { + ret[_cmd_name] = res; + return ret; + }; - Json::Value& findBlob = responses[0]; + if (responses.size() != 1) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "PMGD Response Bad Size"; + return error(return_error); + } - if (findBlob["status"] != 0) { - findBlob["status"] = RSCommand::Error; - // Uses PMGD info error. - return error(findBlob); - } + Json::Value &findBlob = responses[0]; - Json::Value results = get_value(cmd, "results"); + if (findBlob["status"] != 0) { + findBlob["status"] = RSCommand::Error; + // Uses PMGD info error. + return error(findBlob); + } - bool flag_empty = false; + Json::Value results = get_value(cmd, "results"); - // Check if blob (image) must be returned - if (get_value(results, "blob", true)) { + bool flag_empty = false; - for (auto& ent : findBlob["entities"]) { + // Check if blob (image) must be returned + if (get_value(results, "blob", true)) { - assert(ent.isMember(VDMS_EN_BLOB_PATH_PROP)); + for (auto &ent : findBlob["entities"]) { - std::string blob_path = ent[VDMS_EN_BLOB_PATH_PROP].asString(); - ent.removeMember(VDMS_EN_BLOB_PATH_PROP); + assert(ent.isMember(VDMS_EN_BLOB_PATH_PROP)); - if (ent.getMemberNames().size() == 0) { - flag_empty = true; - } + std::string blob_path = ent[VDMS_EN_BLOB_PATH_PROP].asString(); + ent.removeMember(VDMS_EN_BLOB_PATH_PROP); - try { - VCL::Image blob_im(blob_path); + if (ent.getMemberNames().size() == 0) { + flag_empty = true; + } + try { + VCL::Image blob_im(blob_path); - // We will return the image in the format the user - // request, or on its format in disk, except for the case - // of .tdb, where we will encode as png. - VCL::Image::Format format =VCL::Image::Format::BIN; + // We will return the image in the format the user + // request, or on its format in disk, except for the case + // of .tdb, where we will encode as png. + VCL::Image::Format format = VCL::Image::Format::BIN; - std::vector blob_buffer; - blob_buffer = blob_im.get_encoded_image(format); + std::vector blob_buffer; + blob_buffer = blob_im.get_encoded_image(format); - if (!blob_buffer.empty()) { + if (!blob_buffer.empty()) { - std::string* blob_str = query_res.add_blobs(); - blob_str->resize(blob_buffer.size()); - std::memcpy((void*)blob_str->data(), - (void*)blob_buffer.data(), - blob_buffer.size()); - } - else { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Blob Data not found"; - return error(return_error); - } - } catch (VCL::Exception e) { - print_exception(e); - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "VCL Exception"; - return error(return_error); - } + std::string *blob_str = query_res.add_blobs(); + blob_str->resize(blob_buffer.size()); + std::memcpy((void *)blob_str->data(), (void *)blob_buffer.data(), + blob_buffer.size()); + } else { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Blob Data not found"; + return error(return_error); } + } catch (VCL::Exception e) { + print_exception(e); + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "VCL Exception"; + return error(return_error); + } } + } - if (flag_empty) { - findBlob.removeMember("entities"); - } + if (flag_empty) { + findBlob.removeMember("entities"); + } - ret[_cmd_name].swap(findBlob); - return ret; + ret[_cmd_name].swap(findBlob); + return ret; } \ No newline at end of file diff --git a/src/BlobCommand.h b/src/BlobCommand.h index c211a162..5aafaeb3 100644 --- a/src/BlobCommand.h +++ b/src/BlobCommand.h @@ -30,83 +30,64 @@ */ #pragma once -#include +#include "vcl/CustomVCL.h" +#include "vcl/Image.h" #include +#include #include -#include "vcl/Image.h" -#include "vcl/CustomVCL.h" -#include "RSCommand.h" #include "ExceptionsCommand.h" +#include "RSCommand.h" namespace VDMS { // Helper classes for handling various JSON commands. - class BlobCommand: public RSCommand - { - public: - - BlobCommand(const std::string &cmd_name); - - virtual int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error) = 0; - - virtual bool need_blob(const Json::Value& cmd) { return false; } - - - - }; - - class AddBlob: public BlobCommand - { - - std::string _storage_bin; - - public: - AddBlob(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - bool need_blob(const Json::Value& cmd) { return true; } - }; - - class UpdateBlob: public BlobCommand - { - public: - UpdateBlob(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - - }; - - class FindBlob: public BlobCommand - { - public: - FindBlob(); - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - Json::Value construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - }; +class BlobCommand : public RSCommand { +public: + BlobCommand(const std::string &cmd_name); + + virtual int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error) = 0; + + virtual bool need_blob(const Json::Value &cmd) { return false; } +}; + +class AddBlob : public BlobCommand { + + std::string _storage_bin; + +public: + AddBlob(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + bool need_blob(const Json::Value &cmd) { return true; } +}; + +class UpdateBlob : public BlobCommand { +public: + UpdateBlob(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); +}; + +class FindBlob : public BlobCommand { +public: + FindBlob(); + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; }; // namespace VDMS diff --git a/src/BoundingBoxCommand.cc b/src/BoundingBoxCommand.cc index 0172e44e..9aaee45c 100644 --- a/src/BoundingBoxCommand.cc +++ b/src/BoundingBoxCommand.cc @@ -40,334 +40,304 @@ using namespace VDMS; //========= AddBoundingBox definitions ========= -AddBoundingBox::AddBoundingBox() : RSCommand("AddBoundingBox") -{ -} +AddBoundingBox::AddBoundingBox() : RSCommand("AddBoundingBox") {} -int AddBoundingBox::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; +int AddBoundingBox::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - int node_ref = get_value(cmd, "_ref", - query.get_available_reference()); + int node_ref = get_value(cmd, "_ref", query.get_available_reference()); - Json::Value rect = get_value(cmd, "rectangle"); - Json::Value props = get_value(cmd, "properties"); + Json::Value rect = get_value(cmd, "rectangle"); + Json::Value props = get_value(cmd, "properties"); - props[VDMS_ROI_COORD_X_PROP] = get_value(rect, "x"); - props[VDMS_ROI_COORD_Y_PROP] = get_value(rect, "y"); - props[VDMS_ROI_WIDTH_PROP] = get_value(rect, "w"); - props[VDMS_ROI_HEIGHT_PROP] = get_value(rect, "h"); + props[VDMS_ROI_COORD_X_PROP] = get_value(rect, "x"); + props[VDMS_ROI_COORD_Y_PROP] = get_value(rect, "y"); + props[VDMS_ROI_WIDTH_PROP] = get_value(rect, "w"); + props[VDMS_ROI_HEIGHT_PROP] = get_value(rect, "h"); - // Add Region node - query.AddNode(node_ref, VDMS_ROI_TAG, props, Json::Value()); + // Add Region node + query.AddNode(node_ref, VDMS_ROI_TAG, props, Json::Value()); - if ( cmd.isMember("image") ) { - Json::Value img; - img["ref"] = cmd["image"]; - add_link(query, img, node_ref, VDMS_ROI_IMAGE_EDGE); - } + if (cmd.isMember("image")) { + Json::Value img; + img["ref"] = cmd["image"]; + add_link(query, img, node_ref, VDMS_ROI_IMAGE_EDGE); + } - if ( cmd.isMember("link") ) { - Json::Value ent; - ent = cmd["link"]; - add_link(query, ent, node_ref, VDMS_ROI_EDGE_TAG); - } + if (cmd.isMember("link")) { + Json::Value ent; + ent = cmd["link"]; + add_link(query, ent, node_ref, VDMS_ROI_EDGE_TAG); + } - return 0; + return 0; } //========= UpdateBoundingBox definitions ========= -UpdateBoundingBox::UpdateBoundingBox() : RSCommand("UpdateBoundingBox") -{ -} +UpdateBoundingBox::UpdateBoundingBox() : RSCommand("UpdateBoundingBox") {} -int UpdateBoundingBox::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - Json::Value rect = get_value(cmd, "rectangle", Json::Value::null); - Json::Value props = get_value(cmd, "properties"); - - if (rect != Json::Value::null) { - props[VDMS_ROI_COORD_X_PROP] = get_value(rect, "x"); - props[VDMS_ROI_COORD_Y_PROP] = get_value(rect, "y"); - props[VDMS_ROI_WIDTH_PROP] = get_value(rect, "w"); - props[VDMS_ROI_HEIGHT_PROP] = get_value(rect, "h"); - } +int UpdateBoundingBox::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + + Json::Value rect = + get_value(cmd, "rectangle", Json::Value::null); + Json::Value props = get_value(cmd, "properties"); + + if (rect != Json::Value::null) { + props[VDMS_ROI_COORD_X_PROP] = get_value(rect, "x"); + props[VDMS_ROI_COORD_Y_PROP] = get_value(rect, "y"); + props[VDMS_ROI_WIDTH_PROP] = get_value(rect, "w"); + props[VDMS_ROI_HEIGHT_PROP] = get_value(rect, "h"); + } - // Update Bounding Box - query.UpdateNode(get_value(cmd, "_ref", -1), - VDMS_ROI_TAG, - props, - cmd["remove_props"], - cmd["constraints"], - get_value(cmd, "unique", false)); + // Update Bounding Box + query.UpdateNode(get_value(cmd, "_ref", -1), VDMS_ROI_TAG, props, + cmd["remove_props"], cmd["constraints"], + get_value(cmd, "unique", false)); - return 0; + return 0; } //========= FindBoundingBox definitions ========= -FindBoundingBox::FindBoundingBox() : RSCommand("FindBoundingBox") -{ +FindBoundingBox::FindBoundingBox() : RSCommand("FindBoundingBox") { + //_use_aws_storage = VDMSConfig::instance()->get_aws_flag(); } -int FindBoundingBox::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - // if blob is true, make sure we have a reference, that way we can iterate - // over the bounding boxes and find the link to the image (if it exists) - Json::Value results = get_value(cmd, "results"); - int ref = get_value(cmd, "_ref", query.get_available_reference()); - - bool coords = false; - if (results.isMember("list")) { - for (int i = 0; i < results["list"].size(); ++i) { - if (results["list"][i].asString() == "_coordinates") { - Json::Value aux; - results["list"].removeIndex(i, &aux); - coords = true; - break; - } - } - } - - if (get_value(results, "blob")) +int FindBoundingBox::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + + // if blob is true, make sure we have a reference, that way we can iterate + // over the bounding boxes and find the link to the image (if it exists) + Json::Value results = get_value(cmd, "results"); + int ref = get_value(cmd, "_ref", query.get_available_reference()); + + bool coords = false; + if (results.isMember("list")) { + for (int i = 0; i < results["list"].size(); ++i) { + if (results["list"][i].asString() == "_coordinates") { + Json::Value aux; + results["list"].removeIndex(i, &aux); coords = true; - - if (coords) { - results["list"].append(VDMS_ROI_COORD_X_PROP); - results["list"].append(VDMS_ROI_COORD_Y_PROP); - results["list"].append(VDMS_ROI_WIDTH_PROP); - results["list"].append(VDMS_ROI_HEIGHT_PROP); + break; + } } + } + + if (get_value(results, "blob")) + coords = true; + + if (coords) { + results["list"].append(VDMS_ROI_COORD_X_PROP); + results["list"].append(VDMS_ROI_COORD_Y_PROP); + results["list"].append(VDMS_ROI_WIDTH_PROP); + results["list"].append(VDMS_ROI_HEIGHT_PROP); + } + + Json::Value link; + if (cmd.isMember("image")) { + link["ref"] = get_value(cmd, "image", -1); + link["class"] = VDMS_ROI_IMAGE_EDGE; + } else + link = cmd["link"]; + + Json::Value constraints = cmd["constraints"]; + if (cmd.isMember("rectangle")) { + Json::Value rect = get_value(cmd, "rectangle", -1); + constraints[VDMS_ROI_COORD_X_PROP].append(">="); + constraints[VDMS_ROI_COORD_X_PROP].append(get_value(rect, "x")); + constraints[VDMS_ROI_COORD_X_PROP].append("<="); + constraints[VDMS_ROI_COORD_X_PROP].append(get_value(rect, "w")); + + constraints[VDMS_ROI_COORD_Y_PROP].append(">="); + constraints[VDMS_ROI_COORD_Y_PROP].append(get_value(rect, "y")); + constraints[VDMS_ROI_COORD_Y_PROP].append("<="); + constraints[VDMS_ROI_COORD_Y_PROP].append(get_value(rect, "h")); + + constraints[VDMS_ROI_WIDTH_PROP].append("<="); + constraints[VDMS_ROI_WIDTH_PROP].append(get_value(rect, "w") + + get_value(rect, "x")); + + constraints[VDMS_ROI_HEIGHT_PROP].append("<="); + constraints[VDMS_ROI_HEIGHT_PROP].append(get_value(rect, "h") + + get_value(rect, "y")); + } + + query.QueryNode(ref, VDMS_ROI_TAG, link, constraints, results, + get_value(cmd, "unique", false)); + + if (get_value(results, "blob", false)) { + Json::Value imgresults; + imgresults["list"].append(VDMS_IM_PATH_PROP); + + Json::Value imglink; + imglink["ref"] = ref; + + query.QueryNode(-1, VDMS_IM_TAG, imglink, Json::Value::null, imgresults, + get_value(cmd, "unique", false)); + } + + return 0; +} - Json::Value link; - if (cmd.isMember("image")) { - link["ref"] = get_value(cmd, "image", -1); - link["class"] = VDMS_ROI_IMAGE_EDGE; - } - else - link = cmd["link"]; - - Json::Value constraints = cmd["constraints"]; - if (cmd.isMember("rectangle")) { - Json::Value rect = get_value(cmd, "rectangle", -1); - constraints[VDMS_ROI_COORD_X_PROP].append(">="); - constraints[VDMS_ROI_COORD_X_PROP].append(get_value(rect, "x")); - constraints[VDMS_ROI_COORD_X_PROP].append("<="); - constraints[VDMS_ROI_COORD_X_PROP].append(get_value(rect, "w")); - - constraints[VDMS_ROI_COORD_Y_PROP].append(">="); - constraints[VDMS_ROI_COORD_Y_PROP].append(get_value(rect, "y")); - constraints[VDMS_ROI_COORD_Y_PROP].append("<="); - constraints[VDMS_ROI_COORD_Y_PROP].append(get_value(rect, "h")); - - constraints[VDMS_ROI_WIDTH_PROP].append("<="); - constraints[VDMS_ROI_WIDTH_PROP].append(get_value(rect, "w") + - get_value(rect, "x")); - - constraints[VDMS_ROI_HEIGHT_PROP].append("<="); - constraints[VDMS_ROI_HEIGHT_PROP].append(get_value(rect, "h") + - get_value(rect, "y")); - } +Json::Value FindBoundingBox::construct_responses( + Json::Value &responses, const Json::Value &json, + protobufs::queryMessage &query_res, const std::string &blob) { + const Json::Value &cmd = json[_cmd_name]; + const Json::Value &results = cmd["results"]; - query.QueryNode( - ref, - VDMS_ROI_TAG, - link, - constraints, - results, - get_value(cmd, "unique", false) - ); + Json::Value ret; - if (get_value(results, "blob", false)) { - Json::Value imgresults; - imgresults["list"].append(VDMS_IM_PATH_PROP); - - Json::Value imglink; - imglink["ref"] = ref; - - query.QueryNode( - -1, - VDMS_IM_TAG, - imglink, - Json::Value::null, - imgresults, - get_value(cmd, "unique", false) - ); + auto error = [&](Json::Value &res) { + ret[_cmd_name] = res; + return ret; + }; + + if (responses.size() == 0) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "PMGD Found Nothing when Looking for BoundingBoxes"; + return error(return_error); + } + + Json::Value &findBB = responses[0]; + + if (findBB["status"] != 0) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "BoundingBox Not Found"; + return error(return_error); + } + + Json::Value entities = findBB["entities"]; + findBB.removeMember("entities"); + + for (int i = 0; i < entities.size(); ++i) { + auto ent = entities[i]; + Json::Value bb; + + Json::Value coords; + if (ent.isMember(VDMS_ROI_COORD_X_PROP) && + ent.isMember(VDMS_ROI_COORD_Y_PROP) && + ent.isMember(VDMS_ROI_WIDTH_PROP) && + ent.isMember(VDMS_ROI_HEIGHT_PROP)) { + coords["x"] = ent[VDMS_ROI_COORD_X_PROP]; + coords["y"] = ent[VDMS_ROI_COORD_Y_PROP]; + coords["w"] = ent[VDMS_ROI_WIDTH_PROP]; + coords["h"] = ent[VDMS_ROI_HEIGHT_PROP]; } - return 0; -} + if (results.isMember("list")) { + for (int i = 0; i < results["list"].size(); ++i) { + auto current = results["list"][i].asString(); + if (current == "_coordinates") { + bb["_coordinates"] = coords; + } else { + bb[current] = ent[current]; + } + } + } -Json::Value FindBoundingBox::construct_responses( - Json::Value& responses, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - const Json::Value& cmd = json[_cmd_name]; - const Json::Value& results = cmd["results"]; - - Json::Value ret; - - auto error = [&](Json::Value& res) - { - ret[_cmd_name] = res; - return ret; - }; - - if (responses.size() == 0) { + if (get_value(results, "blob", false)) { + if (responses.size() < 1) { Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "PMGD Found Nothing when Looking for BoundingBoxes"; + return_error["status"] = RSCommand::Error; + return_error["info"] = "BoundingBox is Missing Corresponding Blob"; return error(return_error); - } + } + + Json::Value &findImage = responses[1]; + if (findImage["status"] != 0) { + findImage["status"] = RSCommand::Error; + // Uses PMGD info error. + error(findImage); + } + if (findImage["entities"].size() <= i) + continue; + else { + bool flag_empty = true; + + auto img_ent = findImage["entities"][i]; + + assert(img_ent.isMember(VDMS_IM_PATH_PROP)); + std::string im_path = img_ent[VDMS_IM_PATH_PROP].asString(); + img_ent.removeMember(VDMS_IM_PATH_PROP); + + if (img_ent.getMemberNames().size() > 0) { + flag_empty = false; + } - Json::Value& findBB = responses[0]; + try { + std::string bucket_name = ""; + if (_use_aws_storage) { + bucket_name = VDMSConfig::instance()->get_bucket_name(); + } - if (findBB["status"] != 0) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "BoundingBox Not Found"; - return error(return_error); - } + VCL::Image img(im_path, bucket_name); - Json::Value entities = findBB["entities"]; - findBB.removeMember("entities"); - - for ( int i = 0; i < entities.size(); ++i ) { - auto ent = entities[i]; - Json::Value bb; - - Json::Value coords; - if (ent.isMember(VDMS_ROI_COORD_X_PROP) && - ent.isMember(VDMS_ROI_COORD_Y_PROP) && - ent.isMember(VDMS_ROI_WIDTH_PROP) && - ent.isMember(VDMS_ROI_HEIGHT_PROP)) { - coords["x"] = ent[VDMS_ROI_COORD_X_PROP]; - coords["y"] = ent[VDMS_ROI_COORD_Y_PROP]; - coords["w"] = ent[VDMS_ROI_WIDTH_PROP]; - coords["h"] = ent[VDMS_ROI_HEIGHT_PROP]; - } + img.crop(VCL::Rectangle( + get_value(coords, "x"), get_value(coords, "y"), + get_value(coords, "w"), get_value(coords, "h"))); - if (results.isMember("list")) { - for (int i = 0; i < results["list"].size(); ++i) { - auto current = results["list"][i].asString(); - if ( current == "_coordinates") { - bb["_coordinates"] = coords; - } - else { - bb[current] = ent[current]; - } - } - } + VCL::Image::Format format = + img.get_image_format() != VCL::Image::Format::TDB + ? img.get_image_format() + : VCL::Image::Format::PNG; - if (get_value(results, "blob", false)) { - if (responses.size() < 1) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "BoundingBox is Missing Corresponding Blob"; - return error(return_error); - } + if (cmd.isMember("format")) { + std::string requested_format = + get_value(cmd, "format"); - Json::Value& findImage = responses[1]; - if (findImage["status"] != 0) { - findImage["status"] = RSCommand::Error; - // Uses PMGD info error. - error(findImage); - } - if (findImage["entities"].size() <= i) - continue; - else { - bool flag_empty = true; - - auto img_ent = findImage["entities"][i]; - - assert(img_ent.isMember(VDMS_IM_PATH_PROP)); - std::string im_path = img_ent[VDMS_IM_PATH_PROP].asString(); - img_ent.removeMember(VDMS_IM_PATH_PROP); - - if (img_ent.getMemberNames().size() > 0) { - flag_empty = false; - } - - try { - VCL::Image img(im_path); - img.crop(VCL::Rectangle( - get_value(coords, "x"), - get_value(coords, "y"), - get_value(coords, "w"), - get_value(coords, "h"))); - - VCL::Image::Format format = - img.get_image_format() != VCL::Image::Format::TDB ? - img.get_image_format() : VCL::Image::Format::PNG; - - if (cmd.isMember("format")) { - std::string requested_format = - get_value(cmd, "format"); - - if (requested_format == "png") { - format = VCL::Image::Format::PNG; - } - else if(requested_format == "jpg") { - format = VCL::Image::Format::JPG; - } - } - - std::vector roi_enc; - roi_enc = img.get_encoded_image(format); - - if (!roi_enc.empty()) { - std::string* img_str = query_res.add_blobs(); - img_str->resize(roi_enc.size()); - std::memcpy((void*)img_str->data(), - (void*)roi_enc.data(), - roi_enc.size()); - } - else { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Image Data not found"; - error(return_error); - } - } catch (VCL::Exception e) { - print_exception(e); - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "VCL Exception"; - error(return_error); - } - - if (!flag_empty) { - findImage.removeMember("entities"); - } + if (requested_format == "png") { + format = VCL::Image::Format::PNG; + } else if (requested_format == "jpg") { + format = VCL::Image::Format::JPG; } + } + + std::vector roi_enc; + roi_enc = img.get_encoded_image(format); + + if (!roi_enc.empty()) { + std::string *img_str = query_res.add_blobs(); + img_str->resize(roi_enc.size()); + std::memcpy((void *)img_str->data(), (void *)roi_enc.data(), + roi_enc.size()); + } else { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Image Data not found"; + error(return_error); + } + } catch (VCL::Exception e) { + print_exception(e); + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "VCL Exception"; + error(return_error); } - findBB["entities"].append(bb); + if (!flag_empty) { + findImage.removeMember("entities"); + } + } } - findBB["status"] = RSCommand::Success; - ret[_cmd_name] = findBB; + findBB["entities"].append(bb); + } - return ret; + findBB["status"] = RSCommand::Success; + ret[_cmd_name] = findBB; + + return ret; } diff --git a/src/BoundingBoxCommand.h b/src/BoundingBoxCommand.h index 66f9b38b..9aa8a3ba 100644 --- a/src/BoundingBoxCommand.h +++ b/src/BoundingBoxCommand.h @@ -30,55 +30,47 @@ */ #pragma once -#include #include +#include #include -#include "RSCommand.h" #include "ExceptionsCommand.h" +#include "RSCommand.h" namespace VDMS { - class AddBoundingBox : public RSCommand - { - public: - AddBoundingBox(); +class AddBoundingBox : public RSCommand { +public: + AddBoundingBox(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); +}; - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - }; +class UpdateBoundingBox : public RSCommand { +public: + UpdateBoundingBox(); - class UpdateBoundingBox : public RSCommand - { - public: - UpdateBoundingBox(); + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); +}; - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - }; +class FindBoundingBox : public RSCommand { + // bool _use_aws_storage; - class FindBoundingBox : public RSCommand - { - public: - FindBoundingBox(); +public: + FindBoundingBox(); - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); - Json::Value construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - }; + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; }; // namespace VDMS diff --git a/src/CommunicationManager.cc b/src/CommunicationManager.cc index dc778a1b..96adba84 100644 --- a/src/CommunicationManager.cc +++ b/src/CommunicationManager.cc @@ -37,73 +37,67 @@ using namespace VDMS; using namespace PMGD; -CommunicationManager::CommunicationManager() -{ - _num_threads = VDMSConfig::instance() ->get_int_value( - "max_simultaneous_clients", - MAX_CONNECTED_CLIENTS); +CommunicationManager::CommunicationManager() { + _num_threads = VDMSConfig::instance()->get_int_value( + "max_simultaneous_clients", MAX_CONNECTED_CLIENTS); - if (_num_threads > MAX_CONNECTED_CLIENTS) - _num_threads = MAX_CONNECTED_CLIENTS; + if (_num_threads > MAX_CONNECTED_CLIENTS) + _num_threads = MAX_CONNECTED_CLIENTS; - _shutdown = false; - for (int i = 0; i < _num_threads; ++i) - _pool.push_back(std::thread(&CommunicationManager::process_queue, this)); + _shutdown = false; + for (int i = 0; i < _num_threads; ++i) + _pool.push_back(std::thread(&CommunicationManager::process_queue, this)); } -void CommunicationManager::process_queue() -{ - comm::Connection *c; - while(true) { - { - std::unique_lock lock(_mlock); - _cv.wait(lock, [&] { return !_workq.empty(); }); - if (_shutdown) - break; - c = _workq.front(); - _workq.pop(); - } - if (c != NULL) { - _conn_list_lock.lock(); - auto c_it = _conn_list.insert(_conn_list.begin(), c); - _conn_list_lock.unlock(); +void CommunicationManager::process_queue() { + comm::Connection *c; + while (true) { + { + std::unique_lock lock(_mlock); + _cv.wait(lock, [&] { return !_workq.empty(); }); + if (_shutdown) + break; + c = _workq.front(); + _workq.pop(); + } + if (c != NULL) { + _conn_list_lock.lock(); + auto c_it = _conn_list.insert(_conn_list.begin(), c); + _conn_list_lock.unlock(); - QueryHandler qh; - printf("Connection received...\n"); - qh.process_connection(c); + QueryHandler qh; + printf("Connection received...\n"); + qh.process_connection(c); - std::unique_lock conn_list_lock(_conn_list_lock); - _conn_list.erase(c_it); - delete c; - } + std::unique_lock conn_list_lock(_conn_list_lock); + _conn_list.erase(c_it); + delete c; } + } } -CommunicationManager::~CommunicationManager() -{ - // Kill all connections by closing the sockets - // If not, QueryHandler will be blocked on process_connection() - for (auto connection : _conn_list) { - connection->shutdown(); - } +CommunicationManager::~CommunicationManager() { + // Kill all connections by closing the sockets + // If not, QueryHandler will be blocked on process_connection() + for (auto connection : _conn_list) { + connection->shutdown(); + } - for (int i = 0; i < _num_threads; ++i) { - _pool[i].join(); - } + for (int i = 0; i < _num_threads; ++i) { + _pool[i].join(); + } } -void CommunicationManager::add_connection(comm::Connection *c) -{ - { - std::unique_lock lock(_mlock); - _workq.push(c); - } - _cv.notify_one(); +void CommunicationManager::add_connection(comm::Connection *c) { + { + std::unique_lock lock(_mlock); + _workq.push(c); + } + _cv.notify_one(); } -void CommunicationManager::shutdown() -{ - _shutdown = true; - add_connection(NULL); - _cv.notify_all(); +void CommunicationManager::shutdown() { + _shutdown = true; + add_connection(NULL); + _cv.notify_all(); } diff --git a/src/CommunicationManager.h b/src/CommunicationManager.h index f743effe..32300b17 100644 --- a/src/CommunicationManager.h +++ b/src/CommunicationManager.h @@ -31,40 +31,39 @@ #pragma once -#include -#include +#include +#include #include #include -#include -#include +#include +#include #include "comm/Connection.h" #include "pmgd.h" namespace VDMS { - class CommunicationManager - { - static const int MAX_CONNECTED_CLIENTS = 500; +class CommunicationManager { + static const int MAX_CONNECTED_CLIENTS = 500; + + // For the thread pool + std::mutex _mlock; + std::condition_variable _cv; + int _num_threads; + std::vector _pool; - // For the thread pool - std::mutex _mlock; - std::condition_variable _cv; - int _num_threads; - std::vector _pool; + std::mutex _conn_list_lock; + std::list _conn_list; - std::mutex _conn_list_lock; - std::list _conn_list; + // Monitor new connections queued in for worker threads + std::queue _workq; - // Monitor new connections queued in for worker threads - std::queue _workq; + bool _shutdown; - bool _shutdown; - - public: - CommunicationManager(); - ~CommunicationManager(); - void process_queue(); - void add_connection(comm::Connection *c); - void shutdown(); - }; +public: + CommunicationManager(); + ~CommunicationManager(); + void process_queue(); + void add_connection(comm::Connection *c); + void shutdown(); }; +}; // namespace VDMS diff --git a/src/DescriptorsCommand.cc b/src/DescriptorsCommand.cc index 86e19a12..95b367df 100644 --- a/src/DescriptorsCommand.cc +++ b/src/DescriptorsCommand.cc @@ -29,21 +29,22 @@ * */ +#include #include -#include "VDMSConfig.h" #include "DescriptorsCommand.h" #include "ExceptionsCommand.h" +#include "VDMSConfig.h" #include "defines.h" #include "vcl/utils.h" using namespace VDMS; +namespace fs = std::filesystem; -DescriptorsCommand::DescriptorsCommand(const std::string& cmd_name) : - RSCommand(cmd_name) -{ - _dm = DescriptorsManager::instance(); +DescriptorsCommand::DescriptorsCommand(const std::string &cmd_name) + : RSCommand(cmd_name) { + _dm = DescriptorsManager::instance(); } // This function only throws when there is a transaction error, @@ -51,948 +52,952 @@ DescriptorsCommand::DescriptorsCommand(const std::string& cmd_name) : // In case of wrong input, we need to inform to the user what // went wrong. std::string DescriptorsCommand::get_set_path(PMGDQuery &query_tx, - const std::string& set_name, - int& dim) -{ - // Will issue a read-only transaction to check - // if the Set exists - PMGDQuery query(query_tx.get_pmgd_qh()); - - Json::Value constraints, link; - Json::Value name_arr; - name_arr.append("=="); - name_arr.append(set_name); - constraints[VDMS_DESC_SET_NAME_PROP] = name_arr; - - Json::Value results; - Json::Value list_arr; - list_arr.append(VDMS_DESC_SET_PATH_PROP); - list_arr.append(VDMS_DESC_SET_DIM_PROP); - results["list"] = list_arr; - - bool unique = true; - - // Query set node - query.add_group(); - query.QueryNode(-1, VDMS_DESC_SET_TAG, link, constraints, results, unique, true); - - Json::Value& query_responses = query.run(); - - if(query_responses.size() != 1 && query_responses[0].size() != 1) { - throw ExceptionCommand(DescriptorSetError, "PMGD Transaction Error"); - } - - Json::Value& set_json = query_responses[0][0]; - - if(!set_json.isMember("entities")) { - throw ExceptionCommand(DescriptorSetError, "PMGD Transaction Error"); - } - - for (auto& ent : set_json["entities"]) { - assert(ent.isMember(VDMS_DESC_SET_PATH_PROP)); - std::string set_path = ent[VDMS_DESC_SET_PATH_PROP].asString(); - dim = ent[VDMS_DESC_SET_DIM_PROP].asInt(); - return set_path; - } - - return ""; + const std::string &set_name, + int &dim) { + // Will issue a read-only transaction to check + // if the Set exists + PMGDQuery query(query_tx.get_pmgd_qh()); + + Json::Value constraints, link; + Json::Value name_arr; + name_arr.append("=="); + name_arr.append(set_name); + constraints[VDMS_DESC_SET_NAME_PROP] = name_arr; + + Json::Value results; + Json::Value list_arr; + list_arr.append(VDMS_DESC_SET_PATH_PROP); + list_arr.append(VDMS_DESC_SET_DIM_PROP); + results["list"] = list_arr; + + bool unique = true; + + // Query set node + query.add_group(); + query.QueryNode(-1, VDMS_DESC_SET_TAG, link, constraints, results, unique, + true); + + Json::Value &query_responses = query.run(); + + if (query_responses.size() != 1 && query_responses[0].size() != 1) { + throw ExceptionCommand(DescriptorSetError, "PMGD Transaction Error"); + } + + Json::Value &set_json = query_responses[0][0]; + + if (!set_json.isMember("entities")) { + throw ExceptionCommand(DescriptorSetError, "PMGD Transaction Error"); + } + + for (auto &ent : set_json["entities"]) { + assert(ent.isMember(VDMS_DESC_SET_PATH_PROP)); + std::string set_path = ent[VDMS_DESC_SET_PATH_PROP].asString(); + dim = ent[VDMS_DESC_SET_DIM_PROP].asInt(); + return set_path; + } + + return ""; } -bool DescriptorsCommand::check_blob_size(const std::string& blob, const int dimensions, const long n_desc) -{ - return (blob.size() / sizeof(float) / dimensions == n_desc); +bool DescriptorsCommand::check_blob_size(const std::string &blob, + const int dimensions, + const long n_desc) { + return (blob.size() / sizeof(float) / dimensions == n_desc); } // AddDescriptorSet Methods -AddDescriptorSet::AddDescriptorSet() : - DescriptorsCommand("AddDescriptorSet") -{ - _storage_sets = VDMSConfig::instance()->get_path_descriptors(); - _flinng_num_rows=3; //set based on the default values of Flinng - _flinng_cells_per_row=4096; - _flinng_num_hash_tables =512; - _flinng_hashes_per_table=14; - _flinng_sub_hash_bits=2; - _flinng_cut_off=6; -} +AddDescriptorSet::AddDescriptorSet() : DescriptorsCommand("AddDescriptorSet") { + _storage_sets = VDMSConfig::instance()->get_path_descriptors(); + _flinng_num_rows = 3; // set based on the default values of Flinng + _flinng_cells_per_row = 4096; + _flinng_num_hash_tables = 512; + _flinng_hashes_per_table = 14; + _flinng_sub_hash_bits = 2; + _flinng_cut_off = 6; -int AddDescriptorSet::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value &cmd = jsoncmd[_cmd_name]; - - // Create PMGD cmd for AddNode - int node_ref = get_value(cmd, "_ref", - query.get_available_reference()); - - std::string set_name = cmd["name"].asString(); - std::string desc_set_path = _storage_sets + "/" + set_name; - - Json::Value props = get_value(cmd, "properties"); - props[VDMS_DESC_SET_NAME_PROP] = cmd["name"].asString(); - props[VDMS_DESC_SET_DIM_PROP] = cmd["dimensions"].asInt(); - props[VDMS_DESC_SET_PATH_PROP] = desc_set_path; - if (cmd.isMember("flinng_num_rows")) - _flinng_num_rows = cmd["flinng_num_rows"].asInt(); - if (cmd.isMember("flinng_cells_per_row")) - _flinng_cells_per_row =cmd["flinng_cells_per_row"].asInt(); - if (cmd.isMember("flinng_num_hash_tables")) - _flinng_num_hash_tables =cmd["flinng_num_hash_tables"].asInt(); - if (cmd.isMember("flinng_hashes_per_table")) - _flinng_hashes_per_table =cmd["flinng_hashes_per_table"].asInt(); - if (cmd.isMember("flinng_sub_hash_bits")) - _flinng_sub_hash_bits = cmd["flinng_sub_hash_bits"].asInt(); - if (cmd.isMember("flinng_cut_off")) - _flinng_cut_off = cmd["flinng_cut_off"].asInt(); - - Json::Value constraints; - constraints[VDMS_DESC_SET_NAME_PROP].append("=="); - constraints[VDMS_DESC_SET_NAME_PROP].append(cmd["name"].asString()); - - - query.AddNode(node_ref, VDMS_DESC_SET_TAG, props, constraints); - - if (cmd.isMember("link")) { - add_link(query, cmd["link"], node_ref, VDMS_DESC_SET_EDGE_TAG); - } + //_use_aws_storage = VDMSConfig::instance()->get_aws_flag(); +} - return 0; +int AddDescriptorSet::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + + // Create PMGD cmd for AddNode + int node_ref = get_value(cmd, "_ref", query.get_available_reference()); + + std::string set_name = cmd["name"].asString(); + std::string desc_set_path = _storage_sets + "/" + set_name; + + Json::Value props = get_value(cmd, "properties"); + props[VDMS_DESC_SET_NAME_PROP] = cmd["name"].asString(); + props[VDMS_DESC_SET_DIM_PROP] = cmd["dimensions"].asInt(); + props[VDMS_DESC_SET_PATH_PROP] = desc_set_path; + if (cmd.isMember("flinng_num_rows")) + _flinng_num_rows = cmd["flinng_num_rows"].asInt(); + if (cmd.isMember("flinng_cells_per_row")) + _flinng_cells_per_row = cmd["flinng_cells_per_row"].asInt(); + if (cmd.isMember("flinng_num_hash_tables")) + _flinng_num_hash_tables = cmd["flinng_num_hash_tables"].asInt(); + if (cmd.isMember("flinng_hashes_per_table")) + _flinng_hashes_per_table = cmd["flinng_hashes_per_table"].asInt(); + if (cmd.isMember("flinng_sub_hash_bits")) + _flinng_sub_hash_bits = cmd["flinng_sub_hash_bits"].asInt(); + if (cmd.isMember("flinng_cut_off")) + _flinng_cut_off = cmd["flinng_cut_off"].asInt(); + + Json::Value constraints; + constraints[VDMS_DESC_SET_NAME_PROP].append("=="); + constraints[VDMS_DESC_SET_NAME_PROP].append(cmd["name"].asString()); + + query.AddNode(node_ref, VDMS_DESC_SET_TAG, props, constraints); + + if (cmd.isMember("link")) { + add_link(query, cmd["link"], node_ref, VDMS_DESC_SET_EDGE_TAG); + } + + return 0; } Json::Value AddDescriptorSet::construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - const Json::Value &cmd = json[_cmd_name]; - Json::Value resp = check_responses(json_responses); - - Json::Value ret; - - auto error = [&](Json::Value& res) - { - ret[_cmd_name] = res; - return ret; - }; - - if (resp["status"] != RSCommand::Success) { - return error(resp); - } - - int dimensions = cmd["dimensions"].asInt(); - std::string set_name = cmd["name"].asString(); - std::string desc_set_path = _storage_sets + "/" + set_name; - - std::string metric_str = get_value(cmd, "metric", "L2"); - VCL::DistanceMetric metric = metric_str == "L2"? VCL::L2 : VCL::IP; - - // For now, we use the default faiss index. - std::string eng_str = get_value(cmd, "engine", "FaissFlat"); - VCL::DescriptorSetEngine eng; - - if (eng_str == "FaissFlat") - eng = VCL::FaissFlat; - else if (eng_str == "FaissIVFFlat") - eng = VCL::FaissIVFFlat; - else if (eng_str == "TileDBDense") - eng = VCL::TileDBDense; - else if (eng_str == "TileDBSparse") - eng = VCL::TileDBSparse; - else if (eng_str == "Flinng") - eng = VCL::Flinng; - else - throw ExceptionCommand(DescriptorSetError, "Engine not supported"); - - // We can probably set up a mechanism - // to fix a broken link when detected later, same with images. - try { - VCL::DescriptorParams param(_flinng_num_rows, _flinng_cells_per_row, _flinng_num_hash_tables,_flinng_hashes_per_table); - VCL::DescriptorSet desc_set(desc_set_path, dimensions, eng, metric, ¶m); - desc_set.store(); - } - catch (VCL::Exception e) { - print_exception(e); - resp["status"] = RSCommand::Error; - resp["info"] = std::string("VCL Exception: ") + e.msg; - return error(resp); - } + Json::Value &json_responses, const Json::Value &json, + protobufs::queryMessage &query_res, const std::string &blob) { + const Json::Value &cmd = json[_cmd_name]; + Json::Value resp = check_responses(json_responses); - resp.clear(); - resp["status"] = RSCommand::Success; + Json::Value ret; - ret[_cmd_name] = resp; + auto error = [&](Json::Value &res) { + ret[_cmd_name] = res; return ret; + }; + + if (resp["status"] != RSCommand::Success) { + return error(resp); + } + + int dimensions = cmd["dimensions"].asInt(); + std::string set_name = cmd["name"].asString(); + std::string desc_set_path = _storage_sets + "/" + set_name; + + std::string metric_str = get_value(cmd, "metric", "L2"); + VCL::DistanceMetric metric = metric_str == "L2" ? VCL::L2 : VCL::IP; + + // For now, we use the default faiss index. + std::string eng_str = get_value(cmd, "engine", "FaissFlat"); + VCL::DescriptorSetEngine eng; + + if (eng_str == "FaissFlat") + eng = VCL::FaissFlat; + else if (eng_str == "FaissIVFFlat") + eng = VCL::FaissIVFFlat; + else if (eng_str == "TileDBDense") + eng = VCL::TileDBDense; + else if (eng_str == "TileDBSparse") + eng = VCL::TileDBSparse; + else if (eng_str == "Flinng") + eng = VCL::Flinng; + else + throw ExceptionCommand(DescriptorSetError, "Engine not supported"); + + // We can probably set up a mechanism + // to fix a broken link when detected later, same with images. + VCL::DescriptorParams *param = nullptr; + try { + param = new VCL::DescriptorParams(_flinng_num_rows, _flinng_cells_per_row, + _flinng_num_hash_tables, + _flinng_hashes_per_table); + VCL::DescriptorSet desc_set(desc_set_path, dimensions, eng, metric, param); + + if (_use_aws_storage) { + VCL::RemoteConnection *connection = new VCL::RemoteConnection(); + std::string bucket = VDMSConfig::instance()->get_bucket_name(); + connection->_bucket_name = bucket; + desc_set.set_connection(connection); + } + + desc_set.store(); + delete (param); + } catch (VCL::Exception e) { + print_exception(e); + resp["status"] = RSCommand::Error; + resp["info"] = std::string("VCL Exception: ") + e.msg; + delete (param); + return error(resp); + } + + resp.clear(); + resp["status"] = RSCommand::Success; + + ret[_cmd_name] = resp; + return ret; } // AddDescriptor Methods -AddDescriptor::AddDescriptor() : - DescriptorsCommand("AddDescriptor") -{ +AddDescriptor::AddDescriptor() : DescriptorsCommand("AddDescriptor") { + //_use_aws_storage = VDMSConfig::instance()->get_aws_flag(); } -long AddDescriptor::insert_descriptor(const std::string& blob, - const std::string& set_path, - int dim, - const std::string& label, - Json::Value& error) -{ - long id_first; +long AddDescriptor::insert_descriptor(const std::string &blob, + const std::string &set_path, int dim, + const std::string &label, + Json::Value &error) { + long id_first; - try { + try { - VCL::DescriptorSet* desc_set = _dm->get_descriptors_handler(set_path); - - if (blob.length()/4 != dim) { - std::cerr << "AddDescriptor::insert_descriptor: "; - std::cerr << "Dimensions mismatch: "; - std::cerr << blob.length()/4 << " " << dim << std::endl; - error["info"] = "Blob Dimensions Mismatch"; - return -1; - } + VCL::DescriptorSet *desc_set = _dm->get_descriptors_handler(set_path); - if (!label.empty()) { - long label_id = desc_set->get_label_id(label); - long* label_ptr = &label_id; - id_first = desc_set->add((float*)blob.data(), 1, label_ptr); - } - else { - id_first = desc_set->add((float*)blob.data(), 1); - } + if (blob.length() / 4 != dim) { + std::cerr << "AddDescriptor::insert_descriptor: "; + std::cerr << "Dimensions mismatch: "; + std::cerr << blob.length() / 4 << " " << dim << std::endl; + error["info"] = "Blob Dimensions Mismatch"; + return -1; + } - } catch (VCL::Exception e) { - print_exception(e); - error["info"] = "VCL Descriptors Exception"; - return -1; + if (!label.empty()) { + long label_id = desc_set->get_label_id(label); + long *label_ptr = &label_id; + id_first = desc_set->add((float *)blob.data(), 1, label_ptr); + } else { + id_first = desc_set->add((float *)blob.data(), 1); } - return id_first; + } catch (VCL::Exception e) { + print_exception(e); + error["info"] = "VCL Descriptors Exception"; + return -1; + } + + return id_first; +} + +void AddDescriptor::retrieve_aws_descriptorSet(const std::string &set_path) { + // check if folder already exists at path, if so, don't even try to hit AWS + if (fs::exists(set_path)) { + return; + } + + VCL::RemoteConnection *connection = new VCL::RemoteConnection(); + std::string bucket = VDMSConfig::instance()->get_bucket_name(); + connection->_bucket_name = bucket; + + if (!connection->connected()) { + connection->start(); + } + if (!connection->connected()) { + throw VCLException(SystemNotFound, "No remote connection started"); + } + + std::vector files = connection->ListFilesInFolder(set_path); + for (auto file : files) { + // if file isn't already on disk, retrieve it from AWS + if (!fs::exists(file)) { + connection->RetrieveFile(file); + } + } } -int AddDescriptor::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value &cmd = jsoncmd[_cmd_name]; +int AddDescriptor::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - const std::string set_name = cmd["set"].asString(); + const std::string set_name = cmd["set"].asString(); - Json::Value props = get_value(cmd, "properties"); + Json::Value props = get_value(cmd, "properties"); - std::string label = get_value(cmd, "label", "None"); - props[VDMS_DESC_LABEL_PROP] = label; + std::string label = get_value(cmd, "label", "None"); + props[VDMS_DESC_LABEL_PROP] = label; - int dimensions; - std::string set_path = get_set_path(query, set_name, dimensions); + int dimensions; + std::string set_path = get_set_path(query, set_name, dimensions); - if (set_path.empty()) { - error["info"] = "Set " + set_name + " not found"; - error["status"] = RSCommand::Error; - return -1; - } + if (set_path.empty()) { + error["info"] = "Set " + set_name + " not found"; + error["status"] = RSCommand::Error; + return -1; + } + + // retrieve the descriptor set from AWS here + // operations are currently done in memory with no subsequent write to disk + // so there's no need to re-upload to AWS + if (_use_aws_storage) { + retrieve_aws_descriptorSet(set_path); + } + + long id = insert_descriptor(blob, set_path, dimensions, label, error); - long id = insert_descriptor(blob, set_path, dimensions, label, error); + if (id < 0) { + error["status"] = RSCommand::Error; - if (id < 0) { - error["status"] = RSCommand::Error; - return -1; + if (_use_aws_storage) { + // delete files in set_path + std::uintmax_t n = fs::remove_all(set_path); + std::cout << "Deleted " << n << " files or directories\n"; } - props[VDMS_DESC_ID_PROP] = Json::Int64(id); + return -1; + } - int node_ref = get_value(cmd, "_ref", - query.get_available_reference()); + props[VDMS_DESC_ID_PROP] = Json::Int64(id); - query.AddNode(node_ref, VDMS_DESC_TAG, props, Json::nullValue); + int node_ref = get_value(cmd, "_ref", query.get_available_reference()); - // It passed the checker, so it exists. - int set_ref = query.get_available_reference(); + query.AddNode(node_ref, VDMS_DESC_TAG, props, Json::nullValue); - Json::Value link; - Json::Value results; - Json::Value list_arr; - list_arr.append(VDMS_DESC_SET_PATH_PROP); - list_arr.append(VDMS_DESC_SET_DIM_PROP); - results["list"] = list_arr; + // It passed the checker, so it exists. + int set_ref = query.get_available_reference(); - Json::Value constraints; - Json::Value name_arr; - name_arr.append("=="); - name_arr.append(set_name); - constraints[VDMS_DESC_SET_NAME_PROP] = name_arr; + Json::Value link; + Json::Value results; + Json::Value list_arr; + list_arr.append(VDMS_DESC_SET_PATH_PROP); + list_arr.append(VDMS_DESC_SET_DIM_PROP); + results["list"] = list_arr; - bool unique = true; + Json::Value constraints; + Json::Value name_arr; + name_arr.append("=="); + name_arr.append(set_name); + constraints[VDMS_DESC_SET_NAME_PROP] = name_arr; - // Query set node - query.QueryNode(set_ref, VDMS_DESC_SET_TAG, link, constraints, results, unique); + bool unique = true; - if (cmd.isMember("link")) { - add_link(query, cmd["link"], node_ref, VDMS_DESC_EDGE_TAG); - } + // Query set node + query.QueryNode(set_ref, VDMS_DESC_SET_TAG, link, constraints, results, + unique); + + if (cmd.isMember("link")) { + add_link(query, cmd["link"], node_ref, VDMS_DESC_EDGE_TAG); + } + + Json::Value props_edge; + query.AddEdge(-1, set_ref, node_ref, VDMS_DESC_SET_EDGE_TAG, props_edge); - Json::Value props_edge; - query.AddEdge(-1, set_ref, node_ref, VDMS_DESC_SET_EDGE_TAG, props_edge); + // TODO: deleting files here causes problems with concurrency (TestRetail.py) + // keeping local copies as a temporary solution + // if(_use_aws_storage) + // { + // //delete files in set_path + // std::uintmax_t n = fs::remove_all(set_path); + // std::cout << "Deleted " << n << " files or directories\n"; + // } - return 0; + return 0; } Json::Value AddDescriptor::construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - Json::Value resp = check_responses(json_responses); - - Json::Value ret; - ret[_cmd_name] = resp; - return ret; + Json::Value &json_responses, const Json::Value &json, + protobufs::queryMessage &query_res, const std::string &blob) { + Json::Value resp = check_responses(json_responses); + + Json::Value ret; + ret[_cmd_name] = resp; + return ret; } // ClassifyDescriptors Methods -ClassifyDescriptor::ClassifyDescriptor() : - DescriptorsCommand("ClassifyDescriptor") -{ -} +ClassifyDescriptor::ClassifyDescriptor() + : DescriptorsCommand("ClassifyDescriptor") {} -int ClassifyDescriptor::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value &cmd = jsoncmd[_cmd_name]; +int ClassifyDescriptor::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - const std::string set_name = cmd["set"].asString(); + const std::string set_name = cmd["set"].asString(); - int dimensions; - const std::string set_path = get_set_path(query, set_name, dimensions); + int dimensions; + const std::string set_path = get_set_path(query, set_name, dimensions); - if (set_path.empty()) { - error["status"] = RSCommand::Error; - error["info"] = "DescritorSet Not Found!"; - return -1; - } + if (set_path.empty()) { + error["status"] = RSCommand::Error; + error["info"] = "DescritorSet Not Found!"; + return -1; + } - Json::Value link; - Json::Value results; - Json::Value list_arr; - list_arr.append(VDMS_DESC_SET_PATH_PROP); - list_arr.append(VDMS_DESC_SET_DIM_PROP); - results["list"] = list_arr; + Json::Value link; + Json::Value results; + Json::Value list_arr; + list_arr.append(VDMS_DESC_SET_PATH_PROP); + list_arr.append(VDMS_DESC_SET_DIM_PROP); + results["list"] = list_arr; - Json::Value constraints; - Json::Value name_arr; - name_arr.append("=="); - name_arr.append(set_name); - constraints[VDMS_DESC_SET_NAME_PROP] = name_arr; + Json::Value constraints; + Json::Value name_arr; + name_arr.append("=="); + name_arr.append(set_name); + constraints[VDMS_DESC_SET_NAME_PROP] = name_arr; - bool unique = true; + bool unique = true; - // Query set node - query.QueryNode( - get_value(cmd, "_ref", -1), - VDMS_DESC_SET_TAG, - link, constraints, results, unique); + // Query set node + query.QueryNode(get_value(cmd, "_ref", -1), VDMS_DESC_SET_TAG, link, + constraints, results, unique); - return 0; + return 0; } Json::Value ClassifyDescriptor::construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - Json::Value classifyDesc; - const Json::Value &cmd = json[_cmd_name]; + Json::Value &json_responses, const Json::Value &json, + protobufs::queryMessage &query_res, const std::string &blob) { + Json::Value classifyDesc; + const Json::Value &cmd = json[_cmd_name]; - Json::Value ret; + Json::Value ret; - bool flag_error = false; + bool flag_error = false; - if (json_responses.size() == 0) { - classifyDesc["status"] = RSCommand::Error; - classifyDesc["info"] = "Not Found!"; - flag_error = true; - ret[_cmd_name] = classifyDesc; - return ret; + if (json_responses.size() == 0) { + classifyDesc["status"] = RSCommand::Error; + classifyDesc["info"] = "Not Found!"; + flag_error = true; + ret[_cmd_name] = classifyDesc; + return ret; + } + + for (auto res : json_responses) { + + if (res["status"] != 0) { + flag_error = true; + break; } - for (auto res : json_responses) { + if (!res.isMember("entities")) + continue; - if (res["status"] != 0) { - flag_error = true; - break; - } + classifyDesc = res; - if (!res.isMember("entities")) - continue; - - classifyDesc = res; - - for (auto& ent : classifyDesc["entities"]) { - - assert(ent.isMember(VDMS_DESC_SET_PATH_PROP)); - std::string set_path = ent[VDMS_DESC_SET_PATH_PROP].asString(); - try { - VCL::DescriptorSet* set = _dm->get_descriptors_handler(set_path); - - auto labels = set->classify((float*)blob.data(), 1); - - if (labels.size() == 0) { - classifyDesc["info"] = "No labels, cannot classify"; - classifyDesc["status"] = RSCommand::Error; - } - else { - classifyDesc["label"] = (set->label_id_to_string(labels)).at(0); - } - } catch (VCL::Exception e) { - print_exception(e); - classifyDesc["status"] = RSCommand::Error; - classifyDesc["info"] = "VCL Exception"; - flag_error = true; - break; - } + for (auto &ent : classifyDesc["entities"]) { + + assert(ent.isMember(VDMS_DESC_SET_PATH_PROP)); + std::string set_path = ent[VDMS_DESC_SET_PATH_PROP].asString(); + try { + VCL::DescriptorSet *set = _dm->get_descriptors_handler(set_path); + + auto labels = set->classify((float *)blob.data(), 1); + + if (labels.size() == 0) { + classifyDesc["info"] = "No labels, cannot classify"; + classifyDesc["status"] = RSCommand::Error; + } else { + classifyDesc["label"] = (set->label_id_to_string(labels)).at(0); } + } catch (VCL::Exception e) { + print_exception(e); + classifyDesc["status"] = RSCommand::Error; + classifyDesc["info"] = "VCL Exception"; + flag_error = true; + break; + } } + } - if (!flag_error) { - classifyDesc["status"] = RSCommand::Success; - } + if (!flag_error) { + classifyDesc["status"] = RSCommand::Success; + } - classifyDesc.removeMember("entities"); + classifyDesc.removeMember("entities"); - ret[_cmd_name] = classifyDesc; + ret[_cmd_name] = classifyDesc; - return ret; + return ret; } // FindDescriptors Methods -FindDescriptor::FindDescriptor() : - DescriptorsCommand("FindDescriptor") -{ -} +FindDescriptor::FindDescriptor() : DescriptorsCommand("FindDescriptor") {} -bool FindDescriptor::need_blob(const Json::Value& cmd) -{ - return cmd[_cmd_name].isMember("k_neighbors"); +bool FindDescriptor::need_blob(const Json::Value &cmd) { + return cmd[_cmd_name].isMember("k_neighbors"); } -int FindDescriptor::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& cp_result) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; +int FindDescriptor::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &cp_result) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + + const std::string set_name = cmd["set"].asString(); + + int dimensions; + const std::string set_path = get_set_path(query, set_name, dimensions); + + if (set_path.empty()) { + cp_result["status"] = RSCommand::Error; + cp_result["info"] = "DescritorSet Not Found!"; + return -1; + } + + Json::Value results_set; + Json::Value list_arr_set; + list_arr_set.append(VDMS_DESC_SET_PATH_PROP); + list_arr_set.append(VDMS_DESC_SET_DIM_PROP); + results_set["list"] = list_arr_set; + + Json::Value constraints_set; + Json::Value name_arr; + name_arr.append("=="); + name_arr.append(set_name); + constraints_set[VDMS_DESC_SET_NAME_PROP] = name_arr; + + bool unique = true; + + Json::Value constraints = cmd["constraints"]; + if (constraints.isMember("_label")) { + constraints[VDMS_DESC_LABEL_PROP] = constraints["_label"]; + constraints.removeMember("_label"); + } + if (constraints.isMember("_id")) { + constraints[VDMS_DESC_ID_PROP] = constraints["_id"]; + constraints.removeMember("_id"); + } + + Json::Value results = cmd["results"]; + + // Add label/id as required. + // Remove the variables with "_" + if (results.isMember("list")) { + int pos = -1; + for (int i = 0; i < results["list"].size(); ++i) { + if (results["list"][i].asString() == "_label" || + results["list"][i].asString() == "_id" || + results["list"][i].asString() == "_distance") { + pos = i; + Json::Value aux; + results["list"].removeIndex(i, &aux); + --i; + } + } + } - const std::string set_name = cmd["set"].asString(); + results["list"].append(VDMS_DESC_LABEL_PROP); + results["list"].append(VDMS_DESC_ID_PROP); - int dimensions; - const std::string set_path = get_set_path(query, set_name, dimensions); + // Case (1) + if (cmd.isMember("link")) { - if (set_path.empty()) { - cp_result["status"] = RSCommand::Error; - cp_result["info"] = "DescritorSet Not Found!"; - return -1; - } + // Query for the Descriptors related to user-defined link + // that match the user-defined constraints + // We will need to do the AND operation + // on the construct_response. - Json::Value results_set; - Json::Value list_arr_set; - list_arr_set.append(VDMS_DESC_SET_PATH_PROP); - list_arr_set.append(VDMS_DESC_SET_DIM_PROP); - results_set["list"] = list_arr_set; + int desc_ref = get_value(cmd, "_ref", query.get_available_reference()); - Json::Value constraints_set; - Json::Value name_arr; - name_arr.append("=="); - name_arr.append(set_name); - constraints_set[VDMS_DESC_SET_NAME_PROP] = name_arr; + query.QueryNode(desc_ref, VDMS_DESC_TAG, cmd["link"], constraints, results, + false); - bool unique = true; + Json::Value link_to_desc; + link_to_desc["ref"] = desc_ref; - Json::Value constraints = cmd["constraints"]; - if (constraints.isMember("_label")) { - constraints[VDMS_DESC_LABEL_PROP] = constraints["_label"]; - constraints.removeMember("_label"); - } - if (constraints.isMember("_id")) { - constraints[VDMS_DESC_ID_PROP] = constraints["_id"]; - constraints.removeMember("_id"); - } + // Query for the set + query.QueryNode(-1, VDMS_DESC_SET_TAG, link_to_desc, constraints_set, + results_set, unique); + } + // Case (2) + else if (!cmd.isMember("k_neighbors")) { - Json::Value results = cmd["results"]; - - // Add label/id as required. - // Remove the variables with "_" - if (results.isMember("list")) { - int pos = -1; - for (int i = 0; i < results["list"].size(); ++i) { - if (results["list"][i].asString() == "_label" || - results["list"][i].asString() == "_id" || - results["list"][i].asString() == "_distance" ) { - pos = i; - Json::Value aux; - results["list"].removeIndex(i, &aux); - --i; - } - } - } + // In this case, we either need properties of the descriptor + // ("list") on the results block, or we need the descriptor nodes + // because the user defined a reference. - results["list"].append(VDMS_DESC_LABEL_PROP); - results["list"].append(VDMS_DESC_ID_PROP); + int ref_set = query.get_available_reference(); - // Case (1) - if (cmd.isMember("link")) { + Json::Value link_set; // null - // Query for the Descriptors related to user-defined link - // that match the user-defined constraints - // We will need to do the AND operation - // on the construct_response. + // Query for the set + query.QueryNode(ref_set, VDMS_DESC_SET_TAG, link_set, constraints_set, + results_set, unique, true); - int desc_ref = get_value(cmd, "_ref", - query.get_available_reference()); + Json::Value link_to_set; + link_to_set["ref"] = ref_set; - query.QueryNode( - desc_ref, - VDMS_DESC_TAG, - cmd["link"], constraints, results, false); + // Query for the Descriptors related to that set + // that match the user-defined constraints + query.QueryNode(get_value(cmd, "_ref", -1), VDMS_DESC_TAG, link_to_set, + constraints, results, false, false); + } + // Case (3), Just want the descriptor by value, we only need the set + else { + Json::Value link_null; // null - Json::Value link_to_desc; - link_to_desc["ref"] = desc_ref; + const int k_neighbors = get_value(cmd, "k_neighbors", 0); - // Query for the set - query.QueryNode( - -1, - VDMS_DESC_SET_TAG, - link_to_desc, constraints_set, results_set, unique); - } - // Case (2) - else if (!cmd.isMember("k_neighbors")) { + int ref_set = query.get_available_reference(); - // In this case, we either need properties of the descriptor - // ("list") on the results block, or we need the descriptor nodes - // because the user defined a reference. + // Query for the set and detect if exist during transaction. + query.QueryNode(ref_set, VDMS_DESC_SET_TAG, Json::nullValue, + constraints_set, results_set, true); - int ref_set = query.get_available_reference(); + Json::Value link_to_set; + link_to_set["ref"] = ref_set; - Json::Value link_set; // null + if (!check_blob_size(blob, dimensions, 1)) { + cp_result["status"] = RSCommand::Error; + cp_result["info"] = "Blob (required) is null or size invalid"; + return -1; + } - // Query for the set - query.QueryNode( - ref_set, - VDMS_DESC_SET_TAG, - link_set, constraints_set, results_set, unique, true); + try { + VCL::DescriptorSet *set = _dm->get_descriptors_handler(set_path); - Json::Value link_to_set; - link_to_set["ref"] = ref_set; + // This is a way to pass state to the construct_response + // We just pass the cache_object_id. + auto cache_obj_id = VCL::get_uint64(); + cp_result["cache_obj_id"] = Json::Int64(cache_obj_id); - // Query for the Descriptors related to that set - // that match the user-defined constraints - query.QueryNode( - get_value(cmd, "_ref", -1), - VDMS_DESC_TAG, - link_to_set, constraints, results, false, false); - } - // Case (3), Just want the descriptor by value, we only need the set - else { - Json::Value link_null; // null + _cache_map[cache_obj_id] = new IDDistancePair(); - const int k_neighbors = get_value(cmd, "k_neighbors", 0); + IDDistancePair *pair = _cache_map[cache_obj_id]; + std::vector &ids = pair->first; + std::vector &distances = pair->second; - int ref_set = query.get_available_reference(); + set->search((float *)blob.data(), 1, k_neighbors, ids, distances); - // Query for the set and detect if exist during transaction. - query.QueryNode( - ref_set, - VDMS_DESC_SET_TAG, - Json::nullValue, constraints_set, results_set, true); + long returned_counter = 0; + std::string blob_return; - Json::Value link_to_set; - link_to_set["ref"] = ref_set; + Json::Value ids_array; - if (!check_blob_size(blob, dimensions, 1)) { - cp_result["status"] = RSCommand::Error; - cp_result["info"] = "Blob (required) is null or size invalid"; - return -1; + for (int i = 0; i < ids.size(); ++i) { + if (ids[i] >= 0) { + ids_array.append(Json::Int64(ids[i])); + } else { + ids.erase(ids.begin() + i, ids.end()); + distances.erase(distances.begin() + i, distances.end()); + break; } + } - try { - VCL::DescriptorSet* set = _dm->get_descriptors_handler(set_path); + // This are needed to construct the response. + if (!results.isMember("list")) { + results["list"].append(VDMS_DESC_LABEL_PROP); + results["list"].append(VDMS_DESC_ID_PROP); + } - // This is a way to pass state to the construct_response - // We just pass the cache_object_id. - auto cache_obj_id = VCL::get_uint64(); - cp_result["cache_obj_id"] = Json::Int64(cache_obj_id); + Json::Value node_constraints = constraints; + cp_result["ids_array"] = ids_array; - _cache_map[cache_obj_id] = new IDDistancePair(); + query.QueryNode(get_value(cmd, "_ref", -1), VDMS_DESC_TAG, + link_to_set, node_constraints, results, false); - IDDistancePair* pair = _cache_map[cache_obj_id]; - std::vector& ids = pair->first; - std::vector& distances = pair->second; + } catch (VCL::Exception e) { + print_exception(e); + cp_result["status"] = RSCommand::Error; + cp_result["info"] = "VCL Exception"; + return -1; + } + } - set->search((float*)blob.data(), 1, k_neighbors, ids, distances); + return 0; +} - long returned_counter = 0; - std::string blob_return; +void FindDescriptor::populate_blobs(const std::string &set_path, + const Json::Value &results, + Json::Value &entities, + protobufs::queryMessage &query_res) { + if (get_value(results, "blob", false)) { - Json::Value ids_array; + VCL::DescriptorSet *set = _dm->get_descriptors_handler(set_path); + int dim = set->get_dimensions(); - for (int i = 0; i < ids.size(); ++i) { - if (ids[i] >= 0) { - ids_array.append(Json::Int64(ids[i])); - } - else { - ids.erase(ids.begin() + i, ids.end()); - distances.erase(distances.begin() + i, distances.end()); - break; - } - } + for (auto &ent : entities) { + long id = ent[VDMS_DESC_ID_PROP].asInt64(); - // This are needed to construct the response. - if (!results.isMember("list")) { - results["list"].append(VDMS_DESC_LABEL_PROP); - results["list"].append(VDMS_DESC_ID_PROP); - } + ent["blob"] = true; - Json::Value node_constraints = constraints; - cp_result["ids_array"] = ids_array; + std::string *desc_blob = query_res.add_blobs(); + desc_blob->resize(sizeof(float) * dim); - query.QueryNode( - get_value(cmd, "_ref", -1), - VDMS_DESC_TAG, - link_to_set, node_constraints, results, false); + set->get_descriptors(&id, 1, (float *)(*desc_blob).data()); + } + } +} - } catch (VCL::Exception e) { - print_exception(e); - cp_result["status"] = RSCommand::Error; - cp_result["info"] = "VCL Exception"; - return -1; - } +void FindDescriptor::convert_properties(Json::Value &entities, + Json::Value &list) { + bool flag_label = false; + bool flag_id = false; + + for (auto &prop : list) { + if (prop.asString() == "_label") { + flag_label = true; } + if (prop.asString() == "_id") { + flag_id = true; + } + } + + for (auto &element : entities) { - return 0; + if (element.isMember(VDMS_DESC_LABEL_PROP)) { + if (flag_label) + element["_label"] = element[VDMS_DESC_LABEL_PROP]; + element.removeMember(VDMS_DESC_LABEL_PROP); + } + if (element.isMember(VDMS_DESC_ID_PROP)) { + if (flag_id) + element["_id"] = element[VDMS_DESC_ID_PROP]; + element.removeMember(VDMS_DESC_ID_PROP); + } + } } -void FindDescriptor::populate_blobs(const std::string& set_path, - const Json::Value& results, - Json::Value& entities, - protobufs::queryMessage &query_res) -{ - if (get_value(results, "blob", false)) { +Json::Value FindDescriptor::construct_responses( + Json::Value &json_responses, const Json::Value &json, + protobufs::queryMessage &query_res, const std::string &blob) { + Json::Value findDesc; + const Json::Value &cmd = json[_cmd_name]; + const Json::Value &cache = json["cp_result"]; - VCL::DescriptorSet* set = _dm->get_descriptors_handler(set_path); - int dim = set->get_dimensions(); + Json::Value ret; - for (auto& ent : entities) { - long id = ent[VDMS_DESC_ID_PROP].asInt64(); + bool flag_error = false; - ent["blob"] = true; + auto error = [&](Json::Value &res) { + ret[_cmd_name] = res; + return ret; + }; - std::string* desc_blob = query_res.add_blobs(); - desc_blob->resize(sizeof(float) * dim); + if (json_responses.size() == 0) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Not Found!"; + return error(return_error); + } - set->get_descriptors(&id, 1,(float*)(*desc_blob).data()); - } - } -} + const Json::Value &results = cmd["results"]; + Json::Value list = get_value(results, "list"); -void FindDescriptor::convert_properties(Json::Value& entities, - Json::Value& list) -{ - bool flag_label = false; - bool flag_id = false; + // Case (1) + if (cmd.isMember("link")) { - for (auto& prop : list) { - if (prop.asString() == "_label") { - flag_label = true; - } - if (prop.asString() == "_id") { - flag_id = true; - } - } + assert(json_responses.size() == 2); - for (auto& element : entities) { + findDesc = json_responses[0]; - if (element.isMember(VDMS_DESC_LABEL_PROP)) { - if (flag_label) - element["_label"] = element[VDMS_DESC_LABEL_PROP]; - element.removeMember(VDMS_DESC_LABEL_PROP); - } - if (element.isMember(VDMS_DESC_ID_PROP)) { - if (flag_id) - element["_id"] = element[VDMS_DESC_ID_PROP]; - element.removeMember(VDMS_DESC_ID_PROP); - } + if (findDesc["status"] != 0) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Descriptors Not Found"; + return error(return_error); } -} -Json::Value FindDescriptor::construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - Json::Value findDesc; - const Json::Value &cmd = json[_cmd_name]; - const Json::Value &cache = json["cp_result"]; - - Json::Value ret; - - bool flag_error = false; - - auto error = [&](Json::Value& res) - { - ret[_cmd_name] = res; - return ret; - }; - - if (json_responses.size() == 0) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Not Found!"; - return error(return_error); - } + const Json::Value &set_response = json_responses[1]; + const Json::Value &set = set_response["entities"][0]; - const Json::Value& results = cmd["results"]; - Json::Value list = get_value(results, "list"); + // These properties should always exist + assert(set.isMember(VDMS_DESC_SET_PATH_PROP)); + assert(set.isMember(VDMS_DESC_SET_DIM_PROP)); + std::string set_path = set[VDMS_DESC_SET_PATH_PROP].asString(); + int dim = set[VDMS_DESC_SET_DIM_PROP].asInt(); + + if (findDesc.isMember("entities")) { + try { + Json::Value &entities = findDesc["entities"]; + populate_blobs(set_path, results, entities, query_res); + convert_properties(entities, list); + } catch (VCL::Exception e) { + print_exception(e); + findDesc["status"] = RSCommand::Error; + findDesc["info"] = "VCL Exception"; + return error(findDesc); + } + } + } + // Case (2) + else if (!cmd.isMember("k_neighbors")) { - // Case (1) - if (cmd.isMember("link")) { + assert(json_responses.size() == 2); - assert(json_responses.size() == 2); + const Json::Value &set_response = json_responses[0]; + const Json::Value &set = set_response["entities"][0]; - findDesc = json_responses[0]; + // These properties should always exist + assert(set.isMember(VDMS_DESC_SET_PATH_PROP)); + assert(set.isMember(VDMS_DESC_SET_DIM_PROP)); + std::string set_path = set[VDMS_DESC_SET_PATH_PROP].asString(); + int dim = set[VDMS_DESC_SET_DIM_PROP].asInt(); - if (findDesc["status"] != 0) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Descriptors Not Found"; - return error(return_error); - } + findDesc = json_responses[1]; - const Json::Value& set_response = json_responses[1]; - const Json::Value& set = set_response["entities"][0]; - - // These properties should always exist - assert(set.isMember(VDMS_DESC_SET_PATH_PROP)); - assert(set.isMember(VDMS_DESC_SET_DIM_PROP)); - std::string set_path = set[VDMS_DESC_SET_PATH_PROP].asString(); - int dim = set[VDMS_DESC_SET_DIM_PROP].asInt(); - - if (findDesc.isMember("entities")) { - try { - Json::Value& entities = findDesc["entities"]; - populate_blobs(set_path, results, entities, query_res); - convert_properties(entities, list); - } catch (VCL::Exception e) { - print_exception(e); - findDesc["status"] = RSCommand::Error; - findDesc["info"] = "VCL Exception"; - return error(findDesc); - } - } + if (findDesc.isMember("entities")) { + try { + Json::Value &entities = findDesc["entities"]; + populate_blobs(set_path, results, entities, query_res); + convert_properties(entities, list); + } catch (VCL::Exception e) { + print_exception(e); + findDesc["status"] = RSCommand::Error; + findDesc["info"] = "VCL Exception"; + return error(findDesc); + } } - // Case (2) - else if (!cmd.isMember("k_neighbors")) { - - assert(json_responses.size() == 2); - - const Json::Value& set_response = json_responses[0]; - const Json::Value& set = set_response["entities"][0]; - - // These properties should always exist - assert(set.isMember(VDMS_DESC_SET_PATH_PROP)); - assert(set.isMember(VDMS_DESC_SET_DIM_PROP)); - std::string set_path = set[VDMS_DESC_SET_PATH_PROP].asString(); - int dim = set[VDMS_DESC_SET_DIM_PROP].asInt(); - - findDesc = json_responses[1]; - - if (findDesc.isMember("entities")) { - try { - Json::Value& entities = findDesc["entities"]; - populate_blobs(set_path, results, entities, query_res); - convert_properties(entities, list); - } catch (VCL::Exception e) { - print_exception(e); - findDesc["status"] = RSCommand::Error; - findDesc["info"] = "VCL Exception"; - return error(findDesc); - } - } - if (findDesc["status"] != 0) { - std::cerr << json_responses.toStyledString() << std::endl; - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Descriptors Not Found"; - return error(return_error); - } + if (findDesc["status"] != 0) { + std::cerr << json_responses.toStyledString() << std::endl; + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Descriptors Not Found"; + return error(return_error); } - // Case (3) - else{ + } + // Case (3) + else { - assert(json_responses.size() == 2); + assert(json_responses.size() == 2); - // Get Set info. - const Json::Value& set_response = json_responses[0]; + // Get Set info. + const Json::Value &set_response = json_responses[0]; - if (set_response["status"] != 0 || - !set_response.isMember("entities")) { + if (set_response["status"] != 0 || !set_response.isMember("entities")) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Set Not Found"; - return error(return_error); - } + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Set Not Found"; + return error(return_error); + } - assert(set_response["entities"].size() == 1); + assert(set_response["entities"].size() == 1); - const Json::Value& set = set_response["entities"][0]; + const Json::Value &set = set_response["entities"][0]; - // This properties should always exist - assert(set.isMember(VDMS_DESC_SET_PATH_PROP)); - assert(set.isMember(VDMS_DESC_SET_DIM_PROP)); - std::string set_path = set[VDMS_DESC_SET_PATH_PROP].asString(); - int dim = set[VDMS_DESC_SET_DIM_PROP].asInt(); + // This properties should always exist + assert(set.isMember(VDMS_DESC_SET_PATH_PROP)); + assert(set.isMember(VDMS_DESC_SET_DIM_PROP)); + std::string set_path = set[VDMS_DESC_SET_PATH_PROP].asString(); + int dim = set[VDMS_DESC_SET_DIM_PROP].asInt(); - if (!check_blob_size(blob, dim, 1)) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Blob (required) is null or size invalid"; - return error(return_error); - } + if (!check_blob_size(blob, dim, 1)) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Blob (required) is null or size invalid"; + return error(return_error); + } - std::vector* ids; - std::vector* distances; + std::vector *ids; + std::vector *distances; - bool compute_distance = false; + bool compute_distance = false; - Json::Value list = get_value(results, "list"); + Json::Value list = get_value(results, "list"); - for (auto& prop : list) { - if (prop.asString() == "_distance") { - compute_distance = true; - break; - } - } + for (auto &prop : list) { + if (prop.asString() == "_distance") { + compute_distance = true; + break; + } + } - // Test whether there is any cached result. - assert(cache.isMember("cache_obj_id")); + // Test whether there is any cached result. + assert(cache.isMember("cache_obj_id")); - long cache_obj_id = cache["cache_obj_id"].asInt64(); + long cache_obj_id = cache["cache_obj_id"].asInt64(); - assert(cache.isMember("ids_array")); - Json::Value ids_array = cache["ids_array"]; + assert(cache.isMember("ids_array")); + Json::Value ids_array = cache["ids_array"]; - // Get from Cache - IDDistancePair* pair = _cache_map[cache_obj_id]; - ids = &(pair->first); - distances = &(pair->second); + // Get from Cache + IDDistancePair *pair = _cache_map[cache_obj_id]; + ids = &(pair->first); + distances = &(pair->second); - findDesc = json_responses[1]; + findDesc = json_responses[1]; - if (findDesc["status"] != 0 || !findDesc.isMember("entities")) { + if (findDesc["status"] != 0 || !findDesc.isMember("entities")) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Descriptor Not Found in graph!"; - return error(return_error); - } + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Descriptor Not Found in graph!"; + return error(return_error); + } - Json::Value aux_entities = findDesc["entities"]; - findDesc.removeMember("entities"); + Json::Value aux_entities = findDesc["entities"]; + findDesc.removeMember("entities"); - uint64_t new_cnt = 0; - for (int i = 0; i < (*ids).size(); ++i) { - - Json::Value desc_data; - - long d_id = (*ids)[i]; - bool pass_constraints = false; - - for (auto ent : aux_entities) { - if (ent[VDMS_DESC_ID_PROP].asInt64() == d_id) { - for (int idx=0; idx< ids_array.size(); ++idx){ - if (ent[VDMS_DESC_ID_PROP].asInt64() == ids_array[idx].asInt64()) { - desc_data = ent; - pass_constraints = true; - break; - } - } - } - if(pass_constraints){ - break; - } - } + uint64_t new_cnt = 0; + for (int i = 0; i < (*ids).size(); ++i) { - if (!pass_constraints) - continue; + Json::Value desc_data; - if (compute_distance) { - desc_data["_distance"] = (*distances)[i]; + long d_id = (*ids)[i]; + bool pass_constraints = false; - // Should be already sorted, - // but if not, we need to match the id with - // whatever is on the cache - // desc_data["cache_id"] = Json::Int64((*ids)[i]); + for (auto ent : aux_entities) { + if (ent[VDMS_DESC_ID_PROP].asInt64() == d_id) { + for (int idx = 0; idx < ids_array.size(); ++idx) { + if (ent[VDMS_DESC_ID_PROP].asInt64() == ids_array[idx].asInt64()) { + desc_data = ent; + pass_constraints = true; + break; } - - findDesc["entities"].append(desc_data); - new_cnt++; + } } - - if (findDesc.isMember("returned")) - findDesc["returned"] = Json::Int64(new_cnt); - - if (findDesc.isMember("entities")) { - try { - Json::Value& entities = findDesc["entities"]; - populate_blobs(set_path, results, entities, query_res); - convert_properties(entities, list); - } catch (VCL::Exception e) { - print_exception(e); - findDesc["status"] = RSCommand::Error; - findDesc["info"] = "VCL Exception"; - return error(findDesc); - } + if (pass_constraints) { + break; } + } - if (cache.isMember("cache_obj_id")) { - // We remove the vectors associated with that entry to - // free memory, without removing the entry from _cache_map - // because tbb does not have a lock free way to do this. - IDDistancePair* pair = _cache_map[cache["cache_obj_id"].asInt64()]; - delete pair; - } + if (!pass_constraints) + continue; + + if (compute_distance) { + desc_data["_distance"] = (*distances)[i]; + + // Should be already sorted, + // but if not, we need to match the id with + // whatever is on the cache + // desc_data["cache_id"] = Json::Int64((*ids)[i]); + } + + findDesc["entities"].append(desc_data); + new_cnt++; } + if (findDesc.isMember("returned")) + findDesc["returned"] = Json::Int64(new_cnt); + if (findDesc.isMember("entities")) { - for (auto& ent : findDesc["entities"]) { - if (ent.getMemberNames().size() == 0) { - findDesc.removeMember("entities"); - break; - } - } + try { + Json::Value &entities = findDesc["entities"]; + populate_blobs(set_path, results, entities, query_res); + convert_properties(entities, list); + } catch (VCL::Exception e) { + print_exception(e); + findDesc["status"] = RSCommand::Error; + findDesc["info"] = "VCL Exception"; + return error(findDesc); + } } - findDesc["status"] = RSCommand::Success; - ret[_cmd_name] = findDesc; + if (cache.isMember("cache_obj_id")) { + // We remove the vectors associated with that entry to + // free memory, without removing the entry from _cache_map + // because tbb does not have a lock free way to do this. + IDDistancePair *pair = _cache_map[cache["cache_obj_id"].asInt64()]; + delete pair; + } + } - return ret; + if (findDesc.isMember("entities")) { + for (auto &ent : findDesc["entities"]) { + if (ent.getMemberNames().size() == 0) { + findDesc.removeMember("entities"); + break; + } + } + } + + findDesc["status"] = RSCommand::Success; + ret[_cmd_name] = findDesc; + + return ret; } diff --git a/src/DescriptorsCommand.h b/src/DescriptorsCommand.h index 664cc132..30be90fc 100644 --- a/src/DescriptorsCommand.h +++ b/src/DescriptorsCommand.h @@ -30,158 +30,139 @@ */ #pragma once -#include #include -#include +#include #include +#include -#include #include +#include -#include "QueryHandler.h" // to provide the database connection #include "DescriptorsManager.h" +#include "QueryHandler.h" // to provide the database connection #include "tbb/concurrent_unordered_map.h" -namespace VDMS{ - - typedef std::pair, std::vector> IDDistancePair; - - // This class encapsulates common behavior of Descriptors-related cmds. - class DescriptorsCommand : public RSCommand - { - protected: - DescriptorsManager* _dm; - - // IDDistancePair is a pointer so that we can free its content - // without having to use erase methods, which are not lock free - // for this data structure in tbb - tbb::concurrent_unordered_map _cache_map; - - // Will return the path to the set and the dimensions - std::string get_set_path(PMGDQuery& query_tx, - const std::string& set, int& dim); - - bool check_blob_size(const std::string& blob, const int dimensions, - const long n_desc); - - public: - DescriptorsCommand(const std::string& cmd_name); - - virtual bool need_blob(const Json::Value& cmd) { return false; } - - virtual int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error) = 0; - - virtual Json::Value construct_responses( - Json::Value& json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob) = 0; - }; - - class AddDescriptorSet: public DescriptorsCommand - { - std::string _storage_sets; - uint64_t _flinng_num_rows; - uint64_t _flinng_cells_per_row; - uint64_t _flinng_num_hash_tables; - uint64_t _flinng_hashes_per_table; - uint64_t _flinng_sub_hash_bits; //sub_hash_bits * hashes_per_table must be less than 32, otherwise segfault will happen - uint64_t _flinng_cut_off; - - public: - AddDescriptorSet(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - Json::Value construct_responses( - Json::Value& json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - }; - - class AddDescriptor: public DescriptorsCommand - { - long insert_descriptor(const std::string& blob, - const std::string& path, - int dim, - const std::string& label, - Json::Value& error); - - public: - AddDescriptor(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - bool need_blob(const Json::Value& cmd) { return true; } - - Json::Value construct_responses( - Json::Value& json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - }; - - class ClassifyDescriptor: public DescriptorsCommand - { - - public: - ClassifyDescriptor(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - bool need_blob(const Json::Value& cmd) { return true; } - - Json::Value construct_responses( - Json::Value& json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - - }; - - class FindDescriptor: public DescriptorsCommand - { - - private: - void convert_properties(Json::Value& entities, Json::Value& list); - void populate_blobs(const std::string& set_path, - const Json::Value& results, - Json::Value& entities, - protobufs::queryMessage &query_res); - - public: - FindDescriptor(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - bool need_blob(const Json::Value& cmd); - - Json::Value construct_responses( - Json::Value& json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - - }; - } +namespace VDMS { + +typedef std::pair, std::vector> IDDistancePair; + +// This class encapsulates common behavior of Descriptors-related cmds. +class DescriptorsCommand : public RSCommand { +protected: + DescriptorsManager *_dm; + + // IDDistancePair is a pointer so that we can free its content + // without having to use erase methods, which are not lock free + // for this data structure in tbb + tbb::concurrent_unordered_map _cache_map; + + // Will return the path to the set and the dimensions + std::string get_set_path(PMGDQuery &query_tx, const std::string &set, + int &dim); + + bool check_blob_size(const std::string &blob, const int dimensions, + const long n_desc); + +public: + DescriptorsCommand(const std::string &cmd_name); + + virtual bool need_blob(const Json::Value &cmd) { return false; } + + virtual int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error) = 0; + + virtual Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob) = 0; +}; + +class AddDescriptorSet : public DescriptorsCommand { + std::string _storage_sets; + uint64_t _flinng_num_rows; + uint64_t _flinng_cells_per_row; + uint64_t _flinng_num_hash_tables; + uint64_t _flinng_hashes_per_table; + uint64_t + _flinng_sub_hash_bits; // sub_hash_bits * hashes_per_table must be + // less than 32, otherwise segfault will happen + uint64_t _flinng_cut_off; + // bool _use_aws_storage; + +public: + AddDescriptorSet(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; + +class AddDescriptor : public DescriptorsCommand { + // bool _use_aws_storage; + + long insert_descriptor(const std::string &blob, const std::string &path, + int dim, const std::string &label, Json::Value &error); + + void retrieve_aws_descriptorSet(const std::string &set_path); + +public: + AddDescriptor(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + bool need_blob(const Json::Value &cmd) { return true; } + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; + +class ClassifyDescriptor : public DescriptorsCommand { + +public: + ClassifyDescriptor(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + bool need_blob(const Json::Value &cmd) { return true; } + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; + +class FindDescriptor : public DescriptorsCommand { + +private: + void convert_properties(Json::Value &entities, Json::Value &list); + void populate_blobs(const std::string &set_path, const Json::Value &results, + Json::Value &entities, + protobufs::queryMessage &query_res); + +public: + FindDescriptor(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + bool need_blob(const Json::Value &cmd); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; +} // namespace VDMS diff --git a/src/DescriptorsManager.cc b/src/DescriptorsManager.cc index 9c7d0a77..ddabaeed 100644 --- a/src/DescriptorsManager.cc +++ b/src/DescriptorsManager.cc @@ -27,59 +27,51 @@ * */ -#include #include "DescriptorsManager.h" +#include using namespace VDMS; -DescriptorsManager* DescriptorsManager::_dm; +DescriptorsManager *DescriptorsManager::_dm; -bool DescriptorsManager::init() -{ - if(_dm) - return false; +bool DescriptorsManager::init() { + if (_dm) + return false; - _dm = new DescriptorsManager(); - return true; + _dm = new DescriptorsManager(); + return true; } -DescriptorsManager* DescriptorsManager::instance() -{ - if(_dm) - return _dm; +DescriptorsManager *DescriptorsManager::instance() { + if (_dm) + return _dm; - std::cerr << "ERROR: DescriptorsManager not init" << std::endl; - return NULL; + std::cerr << "ERROR: DescriptorsManager not init" << std::endl; + return NULL; } -DescriptorsManager::DescriptorsManager() -{ -} +DescriptorsManager::DescriptorsManager() {} -void DescriptorsManager::flush() -{ - for (auto desc_set : _descriptors_handlers) { - desc_set.second->store(); - delete desc_set.second; - } - _descriptors_handlers.clear(); +void DescriptorsManager::flush() { + for (auto desc_set : _descriptors_handlers) { + desc_set.second->store(); + delete desc_set.second; + } + _descriptors_handlers.clear(); } -VCL::DescriptorSet* DescriptorsManager::get_descriptors_handler( - std::string path) -{ - VCL::DescriptorSet* desc_ptr; +VCL::DescriptorSet * +DescriptorsManager::get_descriptors_handler(std::string path) { + VCL::DescriptorSet *desc_ptr; - auto element = _descriptors_handlers.find(path); + auto element = _descriptors_handlers.find(path); - if (element == _descriptors_handlers.end()) { - desc_ptr = new VCL::DescriptorSet(path); - _descriptors_handlers[path] = desc_ptr; - } - else { - desc_ptr = element->second; - } + if (element == _descriptors_handlers.end()) { + desc_ptr = new VCL::DescriptorSet(path); + _descriptors_handlers[path] = desc_ptr; + } else { + desc_ptr = element->second; + } - return desc_ptr; + return desc_ptr; } - diff --git a/src/DescriptorsManager.h b/src/DescriptorsManager.h index 28f063bc..711a7f64 100644 --- a/src/DescriptorsManager.h +++ b/src/DescriptorsManager.h @@ -29,36 +29,34 @@ #pragma once -#include -#include #include #include +#include +#include -#include "vcl/DescriptorSet.h" #include "tbb/concurrent_unordered_map.h" +#include "vcl/DescriptorSet.h" namespace VDMS { - class DescriptorsManager - { - static DescriptorsManager* _dm; - tbb::concurrent_unordered_map - _descriptors_handlers; - - DescriptorsManager(); - - public: - - static bool init(); - static DescriptorsManager* instance(); - - /** - * Handles descriptors and lock for the descriptor - * This is a blocking call until the descriptor is free - * - * @param path Path to the descriptor set - */ - VCL::DescriptorSet* get_descriptors_handler(std::string path); - void flush(); - }; +class DescriptorsManager { + static DescriptorsManager *_dm; + tbb::concurrent_unordered_map + _descriptors_handlers; + + DescriptorsManager(); + +public: + static bool init(); + static DescriptorsManager *instance(); + + /** + * Handles descriptors and lock for the descriptor + * This is a blocking call until the descriptor is free + * + * @param path Path to the descriptor set + */ + VCL::DescriptorSet *get_descriptors_handler(std::string path); + void flush(); }; +}; // namespace VDMS diff --git a/src/Exception.h b/src/Exception.h index cbf552b3..3b2a2763 100644 --- a/src/Exception.h +++ b/src/Exception.h @@ -33,56 +33,44 @@ #include - namespace VDMS { - enum ExceptionServerType { - FATAL_Server_Error, +enum ExceptionServerType { + FATAL_Server_Error, - SignalHandler, - NullConnection, + SignalHandler, + NullConnection, - Undefined = 100,// Any undefined error - }; + Undefined = 100, // Any undefined error +}; - struct ExceptionServer { - // Which exception - int num; ///< Exception number - const char *name; ///< Exception name +struct ExceptionServer { + // Which exception + int num; ///< Exception number + const char *name; ///< Exception name - // Additional information - std::string msg; - int errno_val; + // Additional information + std::string msg; + int errno_val; - // Where it was thrown - const char *file; ///< Source file name - int line; ///< Source line number + // Where it was thrown + const char *file; ///< Source file name + int line; ///< Source line number - ExceptionServer(int exc, const char *exc_name, const char *f, int l) - : num(exc), name(exc_name), - msg(), errno_val(0), - file(f), line(l) - {} + ExceptionServer(int exc, const char *exc_name, const char *f, int l) + : num(exc), name(exc_name), msg(), errno_val(0), file(f), line(l) {} - ExceptionServer(int exc, const char *exc_name, - const std::string &m, + ExceptionServer(int exc, const char *exc_name, const std::string &m, const char *f, int l) - : num(exc), name(exc_name), - msg(m), errno_val(0), - file(f), line(l) - {} + : num(exc), name(exc_name), msg(m), errno_val(0), file(f), line(l) {} - ExceptionServer(int exc, const char *exc_name, - int err, const std::string &m, + ExceptionServer(int exc, const char *exc_name, int err, const std::string &m, const char *f, int l) - : num(exc), name(exc_name), - msg(m), errno_val(err), - file(f), line(l) - {} - }; - -#define ExceptionServer(name, ...) \ - ExceptionServer(VDMS::name, #name, ##__VA_ARGS__, __FILE__, __LINE__) + : num(exc), name(exc_name), msg(m), errno_val(err), file(f), line(l) {} }; +#define ExceptionServer(name, ...) \ + ExceptionServer(VDMS::name, #name, ##__VA_ARGS__, __FILE__, __LINE__) +}; // namespace VDMS + extern void print_exception(const VDMS::ExceptionServer &e, FILE *f = stdout); diff --git a/src/ExceptionsCommand.cc b/src/ExceptionsCommand.cc index e9622aaa..5cb0af94 100644 --- a/src/ExceptionsCommand.cc +++ b/src/ExceptionsCommand.cc @@ -32,11 +32,10 @@ #include "ExceptionsCommand.h" -void print_exception(const VDMS::ExceptionCommand &e, FILE *f) -{ - fprintf(f, "[ExceptionCommand] %s at %s:%d\n", e.name, e.file, e.line); - if (e.errno_val != 0) - fprintf(f, "%s: %s\n", e.msg.c_str(), strerror(e.errno_val)); - else if (!e.msg.empty()) - fprintf(f, "%s\n", e.msg.c_str()); +void print_exception(const VDMS::ExceptionCommand &e, FILE *f) { + fprintf(f, "[ExceptionCommand] %s at %s:%d\n", e.name, e.file, e.line); + if (e.errno_val != 0) + fprintf(f, "%s: %s\n", e.msg.c_str(), strerror(e.errno_val)); + else if (!e.msg.empty()) + fprintf(f, "%s\n", e.msg.c_str()); } \ No newline at end of file diff --git a/src/ExceptionsCommand.h b/src/ExceptionsCommand.h index f3d5fe44..3287db57 100644 --- a/src/ExceptionsCommand.h +++ b/src/ExceptionsCommand.h @@ -35,58 +35,47 @@ namespace VDMS { - enum ExceptionCommandType { - FATAL_Query_Handler_Error, +enum ExceptionCommandType { + FATAL_Query_Handler_Error, - EntityError, - ImageError, - DescriptorError, - DescriptorSetError, - PMGDTransactiontError, - LockTimeout, - LockError, + EntityError, + ImageError, + DescriptorError, + DescriptorSetError, + PMGDTransactiontError, + LockTimeout, + LockError, - Undefined = 100,// Any undefined error - }; - - struct ExceptionCommand { - // Which exception - int num; ///< Exception number - const char *name; ///< Exception name + Undefined = 100, // Any undefined error +}; - // Additional information - std::string msg; - int errno_val; +struct ExceptionCommand { + // Which exception + int num; ///< Exception number + const char *name; ///< Exception name - // Where it was thrown - const char *file; ///< Source file name - int line; ///< Source line number + // Additional information + std::string msg; + int errno_val; - ExceptionCommand(int exc, const char *exc_name, const char *f, int l) - : num(exc), name(exc_name), - msg(), errno_val(0), - file(f), line(l) - {} + // Where it was thrown + const char *file; ///< Source file name + int line; ///< Source line number - ExceptionCommand(int exc, const char *exc_name, - const std::string &m, - const char *f, int l) - : num(exc), name(exc_name), - msg(m), errno_val(0), - file(f), line(l) - {} + ExceptionCommand(int exc, const char *exc_name, const char *f, int l) + : num(exc), name(exc_name), msg(), errno_val(0), file(f), line(l) {} - ExceptionCommand(int exc, const char *exc_name, - int err, const std::string &m, - const char *f, int l) - : num(exc), name(exc_name), - msg(m), errno_val(err), - file(f), line(l) - {} - }; + ExceptionCommand(int exc, const char *exc_name, const std::string &m, + const char *f, int l) + : num(exc), name(exc_name), msg(m), errno_val(0), file(f), line(l) {} -#define ExceptionCommand(name, ...) \ - ExceptionCommand(VDMS::name, #name, ##__VA_ARGS__, __FILE__, __LINE__) + ExceptionCommand(int exc, const char *exc_name, int err, const std::string &m, + const char *f, int l) + : num(exc), name(exc_name), msg(m), errno_val(err), file(f), line(l) {} }; +#define ExceptionCommand(name, ...) \ + ExceptionCommand(VDMS::name, #name, ##__VA_ARGS__, __FILE__, __LINE__) +}; // namespace VDMS + extern void print_exception(const VDMS::ExceptionCommand &e, FILE *f = stdout); diff --git a/src/ImageCommand.cc b/src/ImageCommand.cc index 0ff24af4..757b3841 100644 --- a/src/ImageCommand.cc +++ b/src/ImageCommand.cc @@ -5,7 +5,7 @@ * * The MIT License * - * @copyright Copyright (c) 2017 Intel Corporation + * @copyright Copyright (c) 2023 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), @@ -35,354 +35,415 @@ #include "VDMSConfig.h" #include "defines.h" +#include "ImageLoop.h" +#include "stats/SystemStats.h" + using namespace VDMS; //========= AddImage definitions ========= -ImageCommand::ImageCommand(const std::string &cmd_name): - RSCommand(cmd_name) -{ -} - -int ImageCommand::enqueue_operations(VCL::Image& img, const Json::Value& ops) -{ - // Correct operation type and parameters are guaranteed at this point - for (auto& op : ops) { - const std::string& type = get_value(op, "type"); - if (type == "threshold") { - img.threshold(get_value(op, "value")); - } - else if (type == "resize") { - img.resize(get_value(op, "height"), - get_value(op, "width") ); - } - else if (type == "crop") { - img.crop(VCL::Rectangle ( - get_value(op, "x"), - get_value(op, "y"), - get_value(op, "width"), - get_value(op, "height") )); - } - else if (type == "flip") { - img.flip(get_value(op, "code")); - } - else if (type == "rotate") { - img.rotate(get_value(op, "angle"), - get_value(op, "resize")); - } - else if (type == "custom") - { - VCL::Image* tmp_image = new VCL::Image(img , true); - try - { - if(custom_vcl_function(img, op) != 0) - { - img.deep_copy_cv(tmp_image->get_cvmat(true)); // function completed but error detected - return -1; - } - } - catch ( ... ) - { - img.deep_copy_cv(tmp_image->get_cvmat(true)); // function threw exception - return -1; - } - delete tmp_image; +ImageCommand::ImageCommand(const std::string &cmd_name) : RSCommand(cmd_name) {} + +int ImageCommand::enqueue_operations(VCL::Image &img, const Json::Value &ops, + bool is_addition) { + // Correct operation type and parameters are guaranteed at this point + for (auto &op : ops) { + const std::string &type = get_value(op, "type"); + if (type == "threshold") { + img.threshold(get_value(op, "value")); + } else if (type == "resize") { + img.resize(get_value(op, "height"), get_value(op, "width")); + } else if (type == "crop") { + img.crop(VCL::Rectangle(get_value(op, "x"), get_value(op, "y"), + get_value(op, "width"), + get_value(op, "height"))); + } else if (type == "flip") { + img.flip(get_value(op, "code")); + } else if (type == "rotate") { + img.rotate(get_value(op, "angle"), get_value(op, "resize")); + } else if (type == "syncremoteOp") { + VCL::Image *tmp_image = new VCL::Image(img, true); + + try { + img.syncremoteOperation(get_value(op, "url"), + get_value(op, "options")); + } catch (const std::exception &e) { + img.deep_copy_cv(tmp_image->get_cvmat(true)); + std::cerr << e.what() << '\n'; + return -1; + } + delete tmp_image; + } else if (type == "remoteOp") { + VCL::Image *tmp_image = new VCL::Image(img, true); + + try { + if (is_addition) { + img.syncremoteOperation(get_value(op, "url"), + get_value(op, "options")); + } else { + img.remoteOperation(get_value(op, "url"), + get_value(op, "options")); } - else { - throw ExceptionCommand(ImageError, "Operation not defined"); - return -1; + } catch (const std::exception &e) { + img.deep_copy_cv(tmp_image->get_cvmat(true)); + std::cerr << e.what() << '\n'; + return -1; + } + delete tmp_image; + } else if (type == "userOp") { + VCL::Image *tmp_image = new VCL::Image(img, true); + + try { + img.userOperation(get_value(op, "options")); + } catch (const std::exception &e) { + img.deep_copy_cv(tmp_image->get_cvmat(true)); + std::cerr << e.what() << '\n'; + return -1; + } + delete tmp_image; + } else if (type == "custom") { + VCL::Image *tmp_image = new VCL::Image(img, true); + try { + if (custom_vcl_function(img, op) != 0) { + img.deep_copy_cv(tmp_image->get_cvmat( + true)); // function completed but error detected + delete tmp_image; + return -1; } + } catch (...) { + img.deep_copy_cv( + tmp_image->get_cvmat(true)); // function threw exception + delete tmp_image; + return -1; + } + delete tmp_image; + } else { + throw ExceptionCommand(ImageError, "Operation not defined"); + return -1; } - return 0; + } + return 0; } -VCL::Image::Format ImageCommand::get_requested_format(const Json::Value& cmd) -{ - VCL::Image::Format format; - - std::string requested_format = get_value(cmd, "format", ""); - - if (requested_format == "png") { - return VCL::Image::Format::PNG; - } - if (requested_format == "jpg") { - return VCL::Image::Format::JPG; - } - if (requested_format == "tdb") { - return VCL::Image::Format::TDB; - } - if (requested_format == "bin") { - return VCL::Image::Format::BIN; - } - - return VCL::Image::Format::NONE_IMAGE; +VCL::Image::Format ImageCommand::get_requested_format(const Json::Value &cmd) { + VCL::Image::Format format; + + std::string requested_format = get_value(cmd, "format", ""); + + if (requested_format == "png") { + return VCL::Image::Format::PNG; + } + if (requested_format == "jpg") { + return VCL::Image::Format::JPG; + } + if (requested_format == "tdb") { + return VCL::Image::Format::TDB; + } + if (requested_format == "bin") { + return VCL::Image::Format::BIN; + } + + return VCL::Image::Format::NONE_IMAGE; } //========= AddImage definitions ========= -AddImage::AddImage() : ImageCommand("AddImage") -{ - _storage_tdb = VDMSConfig::instance()->get_path_tdb(); - _storage_png = VDMSConfig::instance()->get_path_png(); - _storage_jpg = VDMSConfig::instance()->get_path_jpg(); - _storage_bin = VDMSConfig::instance()->get_path_bin(); +AddImage::AddImage() : ImageCommand("AddImage") { + _storage_tdb = VDMSConfig::instance()->get_path_tdb(); + _storage_png = VDMSConfig::instance()->get_path_png(); + _storage_jpg = VDMSConfig::instance()->get_path_jpg(); + _storage_bin = VDMSConfig::instance()->get_path_bin(); + //_use_aws_storage = VDMSConfig::instance()->get_aws_flag(); } -int AddImage::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - int operation_flags = 0; +int AddImage::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + int operation_flags = 0; + + int node_ref = get_value(cmd, "_ref", query.get_available_reference()); + + std::string format = get_value(cmd, "format", ""); + char binary_img_flag = 0; + if (format == "bin") { + binary_img_flag = 1; + } + + VCL::Image img((void *)blob.data(), blob.size(), binary_img_flag); + if (_use_aws_storage) { + VCL::RemoteConnection *connection = new VCL::RemoteConnection(); + std::string bucket = VDMSConfig::instance()->get_bucket_name(); + connection->_bucket_name = bucket; + img.set_connection(connection); + } + + if (cmd.isMember("operations")) { + operation_flags = enqueue_operations(img, cmd["operations"], true); + } + + std::string img_root = _storage_tdb; + VCL::Image::Format vcl_format = img.get_image_format(); + + if (operation_flags != 0) { + error["info"] = "custom function process not found"; + error["status"] = RSCommand::Error; + return -1; + } else if (cmd.isMember("format")) { + + if (format == "png") { + vcl_format = VCL::Image::Format::PNG; + img_root = _storage_png; + } else if (format == "tdb") { + vcl_format = VCL::Image::Format::TDB; + img_root = _storage_tdb; + } else if (format == "jpg") { + vcl_format = VCL::Image::Format::JPG; + img_root = _storage_jpg; + } else if (format == "bin") { + vcl_format = VCL::Image::Format::BIN; + img_root = _storage_bin; + } else { + error["info"] = format + ": format not implemented"; + error["status"] = RSCommand::Error; + return -1; + } + } - int node_ref = get_value(cmd, "_ref", - query.get_available_reference()); + std::string file_name = VCL::create_unique(img_root, format); + // Modifiyng the existing properties that the user gives + // is a good option to make the AddNode more simple. + // This is not ideal since we are manupulating with user's + // input, but for now it is an acceptable solution. + Json::Value props = get_value(cmd, "properties"); + props[VDMS_IM_PATH_PROP] = file_name; - std::string format = get_value(cmd, "format", ""); - char binary_img_flag = 0; - if(format == "bin") - { - binary_img_flag = 1; - } - - VCL::Image img((void*)blob.data(), blob.size(), binary_img_flag); - if (cmd.isMember("operations")) { - operation_flags = enqueue_operations(img, cmd["operations"]); - } + // Add Image node + query.AddNode(node_ref, VDMS_IM_TAG, props, Json::Value()); - std::string img_root = _storage_tdb; - VCL::Image::Format vcl_format = img.get_image_format(); + img.store(file_name, vcl_format); - if(operation_flags != 0) - { - error["info"] = "custom function process not found"; - error["status"] = RSCommand::Error; - return -1; - } - else if (cmd.isMember("format")) { + // In case we need to cleanup the query + error["image_added"] = file_name; - if (format == "png") { - vcl_format = VCL::Image::Format::PNG; - img_root = _storage_png; - } - else if (format == "tdb") { - vcl_format = VCL::Image::Format::TDB; - img_root = _storage_tdb; - } - else if (format == "jpg") { - vcl_format = VCL::Image::Format::JPG; - img_root = _storage_jpg; - } - else if (format == "bin") { - vcl_format = VCL::Image::Format::BIN; - img_root = _storage_bin; - } - else { - error["info"] = format + ": format not implemented"; - error["status"] = RSCommand::Error; - return -1; - } - } + if (cmd.isMember("link")) { + add_link(query, cmd["link"], node_ref, VDMS_IM_EDGE_TAG); + } - std::string file_name = VCL::create_unique(img_root, format); - - // Modifiyng the existing properties that the user gives - // is a good option to make the AddNode more simple. - // This is not ideal since we are manupulating with user's - // input, but for now it is an acceptable solution. - Json::Value props = get_value(cmd, "properties"); - props[VDMS_IM_PATH_PROP] = file_name; + return 0; +} - // Add Image node - query.AddNode(node_ref, VDMS_IM_TAG, props, Json::Value()); +//========= UpdateImage definitions ========= - img.store(file_name, vcl_format); +UpdateImage::UpdateImage() : ImageCommand("UpdateImage") {} - // In case we need to cleanup the query - error["image_added"] = file_name; +int UpdateImage::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - if (cmd.isMember("link")) { - add_link(query, cmd["link"], node_ref, VDMS_IM_EDGE_TAG); - } + // Update Image node + query.UpdateNode(get_value(cmd, "_ref", -1), VDMS_IM_TAG, + cmd["properties"], cmd["remove_props"], cmd["constraints"], + get_value(cmd, "unique", false)); - return 0; + return 0; } -//========= UpdateImage definitions ========= +//========= FindImage definitions ========= -UpdateImage::UpdateImage() : ImageCommand("UpdateImage") -{ +FindImage::FindImage() : ImageCommand("FindImage") { + //_use_aws_storage = VDMSConfig::instance()->get_aws_flag(); } -int UpdateImage::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - // Update Image node - query.UpdateNode(get_value(cmd, "_ref", -1), - VDMS_IM_TAG, - cmd["properties"], - cmd["remove_props"], - cmd["constraints"], - get_value(cmd, "unique", false)); - - return 0; -} +int FindImage::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; -//========= FindImage definitions ========= + Json::Value results = get_value(cmd, "results"); + + // Unless otherwise specified, we return the blob. + if (get_value(results, "blob", true)) { + results["list"].append(VDMS_IM_PATH_PROP); + } -FindImage::FindImage() : ImageCommand("FindImage") -{ + query.QueryNode(get_value(cmd, "_ref", -1), VDMS_IM_TAG, cmd["link"], + cmd["constraints"], results, + get_value(cmd, "unique", false)); + + return 0; } -int FindImage::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; +Json::Value FindImage::construct_responses(Json::Value &responses, + const Json::Value &json, + protobufs::queryMessage &query_res, + const std::string &blob) { + const Json::Value &cmd = json[_cmd_name]; + int operation_flags = 0; + bool has_operations = false; + std::string no_op_def_image; + SystemStats systemStats; - Json::Value results = get_value(cmd, "results"); + Json::Value ret; - // Unless otherwhis specified, we return the blob. - if (get_value(results, "blob", true)){ - results["list"].append(VDMS_IM_PATH_PROP); - } + std::map formats; - query.QueryNode( - get_value(cmd, "_ref", -1), - VDMS_IM_TAG, - cmd["link"], - cmd["constraints"], - results, - get_value(cmd, "unique", false) - ); + auto error = [&](Json::Value &res) { + ret[_cmd_name] = res; + return ret; + }; - return 0; -} + auto empty = [&](Json::Value &res) { + ret[_cmd_name] = res; + return ret; + }; -Json::Value FindImage::construct_responses( - Json::Value& responses, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - const Json::Value& cmd = json[_cmd_name]; - int operation_flags = 0; + if (responses.size() != 1) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "PMGD Response Bad Size"; + return error(return_error); + } - Json::Value ret; + Json::Value &findImage = responses[0]; - auto error = [&](Json::Value& res) - { - ret[_cmd_name] = res; - return ret; - }; + if (findImage["status"] != 0) { + findImage["status"] = RSCommand::Error; + // Uses PMGD info error. + return error(findImage); + } - if (responses.size() != 1) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "PMGD Response Bad Size"; - return error(return_error); - } + Json::Value results = get_value(cmd, "results"); - Json::Value& findImage = responses[0]; + bool flag_empty = false; - if (findImage["status"] != 0) { - findImage["status"] = RSCommand::Error; - // Uses PMGD info error. - return error(findImage); - } + if (findImage["entities"].size() == 0) { + Json::Value return_empty; + return_empty["status"] = RSCommand::Success; + return_empty["info"] = "No entities found"; + return empty(return_empty); + } + + // Check if blob (image) must be returned + if (get_value(results, "blob", true)) { + + ImageLoop eventloop; + eventloop.set_nrof_entities(findImage["entities"].size()); + + for (auto &ent : findImage["entities"]) { + assert(ent.isMember(VDMS_IM_PATH_PROP)); - Json::Value results = get_value(cmd, "results"); - - bool flag_empty = false; - - // Check if blob (image) must be returned - if (get_value(results, "blob", true)) { - - for (auto& ent : findImage["entities"]) { - - assert(ent.isMember(VDMS_IM_PATH_PROP)); - - std::string im_path = ent[VDMS_IM_PATH_PROP].asString(); - ent.removeMember(VDMS_IM_PATH_PROP); - - if (ent.getMemberNames().size() == 0) { - flag_empty = true; - } - - try { - VCL::Image img(im_path); - - if (cmd.isMember("operations")) { - operation_flags = enqueue_operations(img, cmd["operations"]); - } - - // We will return the image in the format the user - // request, or on its format in disk, except for the case - // of .tdb, where we will encode as png. - VCL::Image::Format format = - img.get_image_format() != VCL::Image::Format::TDB ? - img.get_image_format() : VCL::Image::Format::PNG; - - if(operation_flags != 0) - { - Json::Value return_error; - return_error["info"] = "custom function process not found"; - return_error["status"] = RSCommand::Error; - return error(return_error); - } - if (cmd.isMember("format")) { - format = get_requested_format(cmd); - if (format == VCL::Image::Format::NONE_IMAGE || - format == VCL::Image::Format::TDB) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Invalid Requested Format for FindImage"; - return error(return_error); - } - } - - std::vector img_enc; - img_enc = img.get_encoded_image(format); - - if (!img_enc.empty()) { - - std::string* img_str = query_res.add_blobs(); - img_str->resize(img_enc.size()); - std::memcpy((void*)img_str->data(), - (void*)img_enc.data(), - img_enc.size()); - } - else { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Image Data not found"; - return error(return_error); - } - } catch (VCL::Exception e) { - print_exception(e); - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "VCL Exception"; - return error(return_error); - } + std::string im_path = ent[VDMS_IM_PATH_PROP].asString(); + ent.removeMember(VDMS_IM_PATH_PROP); + + if (ent.getMemberNames().size() == 0) { + flag_empty = true; + } + + try { + VCL::Image img(im_path); + + if (_use_aws_storage) { + VCL::RemoteConnection *connection = new VCL::RemoteConnection(); + std::string bucket = VDMSConfig::instance()->get_bucket_name(); + connection->_bucket_name = bucket; + img.set_connection(connection); + } + + if (cmd.isMember("operations")) { + operation_flags = enqueue_operations(img, cmd["operations"]); + has_operations = true; + } + + // We will return the image in the format the user + // request, or on its format in disk, except for the case + // of .tdb, where we will encode as png. + VCL::Image::Format format = + img.get_image_format() != VCL::Image::Format::TDB + ? img.get_image_format() + : VCL::Image::Format::PNG; + + if (operation_flags != 0) { + Json::Value return_error; + return_error["info"] = "custom function process not found"; + return_error["status"] = RSCommand::Error; + return error(return_error); + } + if (cmd.isMember("format")) { + format = get_requested_format(cmd); + if (format == VCL::Image::Format::NONE_IMAGE || + format == VCL::Image::Format::TDB) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Invalid Requested Format for FindImage"; + return error(return_error); + } + } + + if (has_operations) { + formats.insert(std::pair( + img.get_image_id(), format)); + eventloop.enqueue(&img); + } else { + std::vector img_enc; + img_enc = img.get_encoded_image(format); + no_op_def_image = img.get_image_id(); + if (!img_enc.empty()) { + + std::string *img_str = query_res.add_blobs(); + img_str->resize(img_enc.size()); + std::memcpy((void *)img_str->data(), (void *)img_enc.data(), + img_enc.size()); + } else { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Image Data not found"; + return error(return_error); + } } - } - if (flag_empty) { - findImage.removeMember("entities"); + } catch (VCL::Exception e) { + print_exception(e); + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "VCL Exception"; + return error(return_error); + } } - ret[_cmd_name].swap(findImage); - return ret; + if (has_operations) { + while (eventloop.is_loop_running()) { + continue; + } + std::map imageMap = eventloop.get_image_map(); + std::map::iterator iter = imageMap.begin(); + + while (iter != imageMap.end()) { + std::vector img_enc = + iter->second->get_encoded_image_async(formats[iter->first]); + if (!img_enc.empty()) { + std::string *img_str = query_res.add_blobs(); + img_str->resize(img_enc.size()); + std::memcpy((void *)img_str->data(), (void *)img_enc.data(), + img_enc.size()); + } else { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Image Data not found"; + return error(return_error); + } + iter++; + } + } else { + eventloop.close_no_operation_loop(no_op_def_image); + } + } + if (flag_empty) { + findImage.removeMember("entities"); + } + ret[_cmd_name].swap(findImage); + return ret; } diff --git a/src/ImageCommand.h b/src/ImageCommand.h index e53498bb..7041911c 100644 --- a/src/ImageCommand.h +++ b/src/ImageCommand.h @@ -5,7 +5,7 @@ * * The MIT License * - * @copyright Copyright (c) 2017 Intel Corporation + * @copyright Copyright (c) 2023 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), @@ -30,91 +30,83 @@ */ #pragma once -#include +#include "vcl/CustomVCL.h" +#include "vcl/Image.h" #include +#include #include -#include "vcl/Image.h" -#include "vcl/CustomVCL.h" -#include "RSCommand.h" #include "ExceptionsCommand.h" +#include "RSCommand.h" + +#include namespace VDMS { // Helper classes for handling various JSON commands. - class ImageCommand: public RSCommand - { - public: - - ImageCommand(const std::string &cmd_name); - - virtual int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error) = 0; - - virtual bool need_blob(const Json::Value& cmd) { return false; } - - // We use this function for enqueueing operations for an 'Image' object - // that is allocated outside of <*>Image operations - int enqueue_operations(VCL::Image& img, const Json::Value& op); - - // Checks if 'format' parameter is specified, and if so, returns the - // corresponding VCL::Image::Format type. - VCL::Image::Format get_requested_format(const Json::Value& cmd); - }; - - class AddImage: public ImageCommand - { - std::string _storage_tdb; - std::string _storage_png; - std::string _storage_jpg; - std::string _storage_bin; - - public: - AddImage(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - bool need_blob(const Json::Value& cmd) { return true; } - }; - - class UpdateImage: public ImageCommand - { - public: - UpdateImage(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - // TODO In order to support "format" or "operations", we could - // implement VCL save operation by adding construct_responses method. - }; - - class FindImage: public ImageCommand - { - public: - FindImage(); - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - Json::Value construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - }; +class ImageCommand : public RSCommand { +public: + ImageCommand(const std::string &cmd_name); + + virtual int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error) = 0; + + virtual bool need_blob(const Json::Value &cmd) { return false; } + + // We use this function for enqueueing operations for an 'Image' object + // that is allocated outside of <*>Image operations + int enqueue_operations(VCL::Image &img, const Json::Value &op, + bool is_addition = false); + + // Checks if 'format' parameter is specified, and if so, returns the + // corresponding VCL::Image::Format type. + VCL::Image::Format get_requested_format(const Json::Value &cmd); +}; + +class AddImage : public ImageCommand { + std::string _storage_tdb; + std::string _storage_png; + std::string _storage_jpg; + std::string _storage_bin; + // bool _use_aws_storage; + +public: + AddImage(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + bool need_blob(const Json::Value &cmd) { return true; } +}; + +class UpdateImage : public ImageCommand { +public: + UpdateImage(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + // TODO In order to support "format" or "operations", we could + // implement VCL save operation by adding construct_responses method. +}; + +class FindImage : public ImageCommand { + // bool _use_aws_storage; + +public: + FindImage(); + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; }; // namespace VDMS diff --git a/src/ImageLoop.cc b/src/ImageLoop.cc new file mode 100644 index 00000000..8e8a9a47 --- /dev/null +++ b/src/ImageLoop.cc @@ -0,0 +1,341 @@ +/** + * @file ImageLoop.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2023 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ImageLoop.h" +#include + +ImageLoop::~ImageLoop() noexcept { + VCL::Image img(imageMap.begin()->first); + m_running = false; + r_running = false; + destroyed = true; + + enqueue(&img); + m_thread.join(); + + r_enqueue(&img); + r_thread.join(); +} + +bool ImageLoop::is_loop_running() { + if (m_running || r_running) { + return true; + } else { + return false; + } +} + +void ImageLoop::close_no_operation_loop(std::string imageid) { + VCL::Image img(imageid); + auto const result = + imageMap.insert(std::pair(imageid, &img)); + if (not result.second) { + result.first->second = &img; + } +} + +void ImageLoop::set_nrof_entities(int nrof_entities) { + _nrof_entities = nrof_entities; +} + +void ImageLoop::enqueue(VCL::Image *img) noexcept { + { + std::lock_guard guard(m_mutex); + m_writeBuffer.push_back(new VCL::Image(*img)); + } + m_condVar.notify_one(); +} + +void ImageLoop::r_enqueue(VCL::Image *img) noexcept { + { + std::lock_guard guard(r_mutex); + r_writeBuffer.push_back(new VCL::Image(*img)); + } + r_condVar.notify_one(); +} + +std::map ImageLoop::get_image_map() { + return imageMap; +} + +void ImageLoop::operationThread() noexcept { + std::vector readBuffer; + + while (m_running) { + { + std::unique_lock lock(m_mutex); + m_condVar.wait(lock, [this] { return !m_writeBuffer.empty(); }); + readBuffer.swap(m_writeBuffer); + } + int flag = 0; + for (VCL::Image *img : readBuffer) { + int enqueued_operations = img->get_enqueued_operation_count(); + + for (int i = img->get_op_completed(); i < enqueued_operations; i++) { + int response = img->execute_operation(); + if (response != 0) { + r_enqueue(img); + flag = 1; + break; + } else { + auto const result = imageMap.insert( + std::pair(img->get_image_id(), img)); + if (not result.second) { + result.first->second = img; + } + } + } + } + readBuffer.clear(); + if (flag == 0 && _remote_running == false && m_writeBuffer.size() == 0 && + r_writeBuffer.size() == 0) { + m_running = false; + r_running = false; + } + } +} + +size_t writeCallback(char *ip, size_t size, size_t nmemb, void *op) { + ((std::string *)op)->append((char *)ip, size * nmemb); + return size * nmemb; +} + +cv::Mat write_image(std::string readBuffer) { + std::vector vectordata(readBuffer.begin(), readBuffer.end()); + cv::Mat data_mat(vectordata, true); + cv::Mat decoded_mat(cv::imdecode(data_mat, 1)); + return decoded_mat; +} + +CURL *ImageLoop::get_easy_handle(VCL::Image *img, std::string &readBuffer) { + CURL *curl = NULL; + CURLcode res; + struct curl_slist *headers = NULL; + curl_mime *form = NULL; + curl_mimepart *field = NULL; + + Json::Value rParams = img->get_remoteOp_params(); + std::string url = rParams["url"].toStyledString().data(); + url.erase(std::remove(url.begin(), url.end(), '\n'), url.end()); + url = url.substr(1, url.size() - 2); + Json::Value options = rParams["options"]; + + curl = curl_easy_init(); + + if (curl) { + std::string imageId = img->get_image_id().data(); + form = curl_mime_init(curl); + + auto time_now = std::chrono::system_clock::now(); + std::chrono::duration utc_time = time_now.time_since_epoch(); + + VCL::Image::Format img_format = img->get_image_format(); + std::string format = img->format_to_string(img_format); + + if (format == "" && options.isMember("format")) { + format = options["format"].toStyledString().data(); + format.erase(std::remove(format.begin(), format.end(), '\n'), + format.end()); + format = format.substr(1, format.size() - 2); + } else { + format = "jpg"; + } + + std::string filePath = + "/tmp/tempfile" + std::to_string(utc_time.count()) + "." + format; + cv::imwrite(filePath, img->get_cvmat(false, false)); + _tempfiles.push_back(filePath); + + field = curl_mime_addpart(form); + curl_mime_name(field, "imageData"); + curl_mime_filedata(field, filePath.data()); + + field = curl_mime_addpart(form); + curl_mime_name(field, "jsonData"); + curl_mime_data(field, options.toStyledString().data(), + options.toStyledString().length()); + + // Post data + url = url + "?id=" + imageId; + curl_easy_setopt(curl, CURLOPT_URL, url.data()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); + curl_easy_setopt(curl, CURLOPT_MIMEPOST, form); + + return curl; + } + + return NULL; +} + +void clear_temp_files(std::vector tempfiles) { + for (std::string fPath : tempfiles) { + if (std::remove(fPath.data()) != 0) { + continue; + } + } +} + +void ImageLoop::execute_remote_operations( + std::vector &readBuffer) { + int flag = 0; + int start_index = 0; + int step = 10; + int end_index = readBuffer.size() > step ? step : readBuffer.size(); + std::vector responseBuffer(readBuffer.size()); + int rindex = 0; + std::vector redoBuffer; + std::vector pendingImages; + while (start_index != readBuffer.size()) { + CURLM *multi_handle; + CURLMsg *msg = NULL; + CURL *eh = NULL; + CURLcode return_code; + int still_running = 0, i = 0, msgs_left = 0; + int http_status_code; + char *szUrl; + + multi_handle = curl_multi_init(); + + auto start = readBuffer.begin() + start_index; + auto end = readBuffer.begin() + end_index; + + std::vector tempBuffer(start, end); + + for (VCL::Image *img : tempBuffer) { + CURL *curl = get_easy_handle(img, responseBuffer[rindex]); + rindex++; + curl_multi_add_handle(multi_handle, curl); + } + + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + if (still_running) + mc = curl_multi_wait(multi_handle, NULL, 0, 1000, NULL); + + if (mc) { + break; + } + } while (still_running); + + while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) { + if (msg->msg == CURLMSG_DONE) { + eh = msg->easy_handle; + + return_code = msg->data.result; + + // Get HTTP status code + szUrl = NULL; + long rsize = 0; + + curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &http_status_code); + curl_easy_getinfo(eh, CURLINFO_EFFECTIVE_URL, &szUrl); + curl_easy_getinfo(eh, CURLINFO_REQUEST_SIZE, &rsize); + + if (http_status_code != 200) { + std::string delimiter = "="; + + char *p = std::strtok(szUrl, delimiter.data()); + p = std::strtok(NULL, delimiter.data()); + + std::string id(p); + redoBuffer.push_back(id); + } + + curl_multi_remove_handle(multi_handle, eh); + curl_easy_cleanup(eh); + } else { + fprintf(stderr, "error: after curl_multi_info_read(), CURLMsg=%d\n", + msg->msg); + } + } + + tempBuffer.clear(); + start_index = end_index; + end_index = readBuffer.size() > (end_index + step) ? (end_index + step) + : readBuffer.size(); + } + rindex = -1; + for (VCL::Image *img : readBuffer) { + rindex++; + if (std::find(redoBuffer.begin(), redoBuffer.end(), + img->get_image_id().data()) != redoBuffer.end()) { + pendingImages.push_back(img); + continue; + } + int rthresh = 0; + auto t_start = std::chrono::high_resolution_clock::now(); + bool rflag = false; + while (responseBuffer[rindex].size() == 0) { + continue; + } + cv::Mat dmat = write_image(responseBuffer[rindex]); + if (dmat.empty()) { + pendingImages.push_back(img); + } + img->shallow_copy_cv(dmat); + img->update_op_completed(); + auto const result = imageMap.insert( + std::pair(img->get_image_id(), img)); + if (not result.second) { + result.first->second = img; + } + if (rindex == readBuffer.size() - 1 && pendingImages.size() == 0) { + _remote_running = false; + } + enqueue(img); + } + readBuffer.clear(); + std::swap(readBuffer, pendingImages); +} + +void ImageLoop::remoteOperationThread() noexcept { + std::vector readBuffer; + + while (r_running) { + { + std::unique_lock rlock(r_mutex); + r_condVar.wait(rlock, [this] { return !r_writeBuffer.empty(); }); + if (r_writeBuffer.size() == _nrof_entities) { + std::swap(readBuffer, r_writeBuffer); + } + } + + if (readBuffer.size() == _nrof_entities && destroyed == false) { + _remote_running = true; + while (readBuffer.size() > 0) { + execute_remote_operations(readBuffer); + } + clear_temp_files(_tempfiles); + _remote_running = false; + } + } +} \ No newline at end of file diff --git a/src/ImageLoop.h b/src/ImageLoop.h new file mode 100644 index 00000000..80b5e8dc --- /dev/null +++ b/src/ImageLoop.h @@ -0,0 +1,82 @@ +/** + * @file ImageLoop.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2023 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "vcl/Image.h" +#include +#include +#include +#include +#include + +class ImageLoop { +public: + ImageLoop() = default; + ImageLoop(const ImageLoop &) = delete; + ImageLoop(ImageLoop &&) noexcept = delete; + ~ImageLoop() noexcept; + + ImageLoop &operator=(const ImageLoop &) = delete; + ImageLoop &operator=(ImageLoop &&) noexcept = delete; + + void set_nrof_entities(int nrof_entities); + + void enqueue(VCL::Image *img) noexcept; + void r_enqueue(VCL::Image *img) noexcept; + + std::map get_image_map(); + + bool is_loop_running(); + void close_no_operation_loop(std::string imageid); + +private: + int _nrof_entities = 0; + bool destroyed = false; + bool _remote_running = false; + std::vector _tempfiles; + std::map imageMap; + + std::vector m_writeBuffer; + std::mutex m_mutex; + std::condition_variable m_condVar; + bool m_running{true}; + std::thread m_thread{&ImageLoop::operationThread, this}; + void operationThread() noexcept; + + std::vector r_writeBuffer; + std::mutex r_mutex; + std::condition_variable r_condVar; + bool r_running{true}; + std::thread r_thread{&ImageLoop::remoteOperationThread, this}; + void remoteOperationThread() noexcept; + + CURL *get_easy_handle(VCL::Image *img, std::string &readBuffer); + void execute_remote_operations(std::vector &readBuffer); +}; \ No newline at end of file diff --git a/src/PMGDIterators.cc b/src/PMGDIterators.cc index 6d88eab4..250ad5bf 100644 --- a/src/PMGDIterators.cc +++ b/src/PMGDIterators.cc @@ -36,93 +36,85 @@ using namespace VDMS; namespace VDMS { template <> -PMGDQueryHandler::ReusableIterator:: -ReusableIterator() : - _ti(NULL), - _it(_traversed.end()) -{ -} +PMGDQueryHandler::ReusableIterator::ReusableIterator() + : _ti(NULL), _it(_traversed.end()) {} -template<> -void PMGDQueryHandler::ReusableIterator::add(PMGD::Edge *e) -{ - // Easiest to add to the end of list. If we are in middle of - // traversal, then this edge might get skipped. Use this function - // with that understanding *** - _traversed.insert(_traversed.end(), e); -} +template <> +void PMGDQueryHandler::ReusableIterator::add( + PMGD::Edge *e) { + // Easiest to add to the end of list. If we are in middle of + // traversal, then this edge might get skipped. Use this function + // with that understanding *** + _traversed.insert(_traversed.end(), e); } +} // namespace VDMS -bool PMGDQueryHandler::MultiNeighborIteratorImpl::_next() -{ - while (_start_ni != NULL && bool(*_start_ni)) { - delete _neighb_i; +bool PMGDQueryHandler::MultiNeighborIteratorImpl::_next() { + while (_start_ni != NULL && bool(*_start_ni)) { + delete _neighb_i; - // TODO Maybe unique can have a default value of false. - // TODO No support in case unique is true but get it from LDBC. - // Eventually need to add a get_union(NodeIterator, vector) - // call to PMGD. - // TODO Any way to skip new? - _neighb_i = new PMGD::NodeIterator(_search_neighbors.eval_nodes(**_start_ni, - _dir, _edge_tag)); - _start_ni->next(); - if (bool(*_neighb_i)) - return true; - } - _start_ni = NULL; - return false; + // TODO Maybe unique can have a default value of false. + // TODO No support in case unique is true but get it from LDBC. + // Eventually need to add a get_union(NodeIterator, vector) + // call to PMGD. + // TODO Any way to skip new? + _neighb_i = new PMGD::NodeIterator( + _search_neighbors.eval_nodes(**_start_ni, _dir, _edge_tag)); + _start_ni->next(); + if (bool(*_neighb_i)) + return true; + } + _start_ni = NULL; + return false; } -bool PMGDQueryHandler::MultiNeighborIteratorImpl::next() -{ - if (_neighb_i != NULL && bool(*_neighb_i)) { - _neighb_i->next(); - if (bool(*_neighb_i)) - return true; - } - return _next(); +bool PMGDQueryHandler::MultiNeighborIteratorImpl::next() { + if (_neighb_i != NULL && bool(*_neighb_i)) { + _neighb_i->next(); + if (bool(*_neighb_i)) + return true; + } + return _next(); } -bool PMGDQueryHandler::NodeEdgeIteratorImpl::next() -{ +bool PMGDQueryHandler::NodeEdgeIteratorImpl::next() { + _edge_it->next(); + while (_edge_it != NULL && bool(*_edge_it)) { + if (check_predicates()) + return true; _edge_it->next(); - while (_edge_it != NULL && bool(*_edge_it)) { + } + return _next(); +} + +bool PMGDQueryHandler::NodeEdgeIteratorImpl::_next() { + while (_src_ni != NULL && bool(*_src_ni)) { + // delete _edge_it; + _src_ni->next(); + if (bool(*_src_ni)) { + _edge_it.reset( + new PMGD::EdgeIterator((*_src_ni)->get_edges(_dir, _expr.tag()))); + while (_edge_it != NULL && bool(*_edge_it)) { if (check_predicates()) - return true; + return true; _edge_it->next(); - } - return _next(); + } + } else + break; + } + return false; } -bool PMGDQueryHandler::NodeEdgeIteratorImpl::_next() -{ - while (_src_ni != NULL && bool(*_src_ni)) { - // delete _edge_it; - _src_ni->next(); - if (bool(*_src_ni)) { - _edge_it.reset( new PMGD::EdgeIterator((*_src_ni)->get_edges(_dir, _expr.tag()))); - while (_edge_it != NULL && bool(*_edge_it)) { - if (check_predicates()) - return true; - _edge_it->next(); - } - } - else - break; - } +bool PMGDQueryHandler::NodeEdgeIteratorImpl::check_predicates() { + PMGD::Edge *e = get_edge(); + for (std::size_t i = _pred_start; i < _num_predicates; i++) { + PMGD::PropertyFilter pf(_expr.get_node_predicate(i)); + if (pf(*e) == PMGD::DontPass) + return false; + } + if (_check_dest && + _dest_nodes.find(&(e->get_destination())) == _dest_nodes.end()) return false; -} - -bool PMGDQueryHandler::NodeEdgeIteratorImpl::check_predicates() -{ - PMGD::Edge *e = get_edge(); - for (std::size_t i = _pred_start; i < _num_predicates; i++) { - PMGD::PropertyFilter pf(_expr.get_node_predicate(i)); - if (pf(*e) == PMGD::DontPass) - return false; - } - if (_check_dest && - _dest_nodes.find(&(e->get_destination()) ) == _dest_nodes.end()) - return false; - return true; + return true; } diff --git a/src/PMGDIterators.h b/src/PMGDIterators.h index 7bf1fd92..d2fd8e96 100644 --- a/src/PMGDIterators.h +++ b/src/PMGDIterators.h @@ -33,247 +33,230 @@ #include -#include "pmgd.h" #include "PMGDQueryHandler.h" #include "SearchExpression.h" +#include "pmgd.h" namespace VDMS { - template - class PMGDQueryHandler::ReusableIterator - { - // Iterator for the starting nodes. - Ti _ti; // Type Iterator - - // TODO Is list the best data structure - // if we could potentially sort? - typedef std::list base_container; - base_container _traversed; - - // Current postion of list iterator - typedef typename base_container::iterator list_iterator; - list_iterator _it; - - bool _next() { - if (_it != _traversed.end()) { - ++_it; - if (_it != _traversed.end()) - return true; - } - if (bool(_ti)) { - _it = _traversed.insert(_traversed.end(), &static_cast(*_ti)); - _ti.next(); - return true; - } - return false; - } - - T *ref() - { - if (!bool(*this)) - throw PMGDException(NullIterator, "Null impl"); - return *_it; - } - - // TODO Is this the best way to do this - struct compare_propkey_ascending - { - PMGD::StringID _propid; - bool operator()(const T *n1, const T *n2) - { return n1->get_property(_propid) < n2->get_property(_propid); } - }; - - struct compare_propkey_descending - { - PMGD::StringID _propid; - bool operator()(const T *n1, const T *n2) - { return n1->get_property(_propid) > n2->get_property(_propid); } - }; - - public: - // Make sure this is not auto-declared. The move one won't be. - ReusableIterator(const ReusableIterator &) = delete; - ReusableIterator(Ti ti) - : _ti(ti), - _it(_traversed.begin()) - { _next(); } - - // Add this to clean up the NewNodeIterator requirement - ReusableIterator(T *n) - : _ti(NULL), - _it(_traversed.insert(_traversed.end(), n)) - {} - - ReusableIterator(); - - operator bool() const { return _it != _traversed.end(); } - bool next() { return _next(); } - T &operator *() { return *ref(); } - T *operator ->() { return ref(); } - void reset() { _it = _traversed.begin(); } - void traverse_all() - { - for( ; _ti; _ti.next()) - _traversed.insert(_traversed.end(), &static_cast(*_ti)); - } - - // Sort the list. Once the list is sorted, all operations - // following that happen in a sorted manner. And this function - // resets the iterator to the beginning. - void sort(PMGD::StringID sortkey, bool descending = false){ - // First finish traversal - traverse_all(); - if (descending) - _traversed.sort(compare_propkey_descending{sortkey}); - else - _traversed.sort(compare_propkey_ascending{sortkey}); - - _it = _traversed.begin(); - } - - // Allow adding of edges as we construct this iterator in add_edge - // call. This is different than add_node since once add_edge can - // cause multiple edges to be created depending on how many nodes - // matched the source/destination conditions - void add(T *t); - }; - - // Specialization for PMGDQueryHandler::ReusableIterator - - template <> - PMGDQueryHandler::ReusableIterator:: - ReusableIterator(); - - template<> - void PMGDQueryHandler::ReusableIterator:: - add(PMGD::Edge *e); - - // End of specialization for PMGDQueryHandler::ReusableIterator - - class PMGDQueryHandler::MultiNeighborIteratorImpl : - public PMGD::NodeIteratorImplIntf - { - // Iterator for the starting nodes. - ReusableNodeIterator *_start_ni; - SearchExpression _search_neighbors; - PMGD::NodeIterator *_neighb_i; - PMGD::Direction _dir; - PMGD::StringID _edge_tag; - - bool _next(); - - public: - MultiNeighborIteratorImpl(ReusableNodeIterator *start_ni, - SearchExpression search_neighbors, - PMGD::Direction dir, - PMGD::StringID edge_tag) - : _start_ni(start_ni), - _search_neighbors(search_neighbors), - _neighb_i(NULL), - _dir(dir), - _edge_tag(edge_tag) - { _next(); } - - ~MultiNeighborIteratorImpl() - { - delete _neighb_i; - } - - operator bool() const { return _neighb_i != NULL ? bool(*_neighb_i) : false; } - - /// No next matching node - bool next(); - - PMGD::Node *ref() { return &**_neighb_i; } - }; - - class PMGDQueryHandler::NodeEdgeIteratorImpl : public PMGD::EdgeIteratorImplIntf - { - /// Reference to expression to evaluate - const SearchExpression _expr; - const size_t _num_predicates; - - ReusableNodeIterator *_src_ni; - ReusableNodeIterator *_dest_ni; - - // In order to check if the other end of an edge is in the nodes - // covered by the dest_ni, it is best to store those nodes in an - // easily searchable data structure, which a list inside ReusableNodeIterator - // is not. Besides, it doesn't make sense to expose that list here. - std::unordered_set _dest_nodes; - - std::size_t _pred_start; - PMGD::Direction _dir; - bool _check_dest; - - // PMGD::EdgeIterator *_edge_it; - std::unique_ptr _edge_it; - - bool _next(); - bool check_predicates(); - - PMGD::EdgeIterator return_iterator() - { - _dir = PMGD::Direction::Outgoing; - if (_src_ni == NULL) { - if (_dest_ni == NULL) - _pred_start = 1; - else { - _dir = PMGD::Direction::Incoming; - _src_ni = _dest_ni; - _dest_ni = NULL; - } - } - - // !bool(*_src_ni) will never be empty because of how the code is - // right now, but we should change in the future because we want - // to continue with the transaction even if some querynode did not - // find anything. We leave it for now. - if (_src_ni == NULL || !bool(*_src_ni)) { - PMGD::PropertyPredicate pp; - if (_num_predicates > 0) - pp = _expr.get_node_predicate(0); - else - pp = PMGD::PropertyPredicate(); - return _expr.db().get_edges(_expr.tag(), pp); - } - else { - return (*_src_ni)->get_edges(_dir, _expr.tag()); - } - } - - public: - NodeEdgeIteratorImpl(const SearchExpression &expr, - ReusableNodeIterator *src_ni = NULL, - ReusableNodeIterator *dest_ni = NULL) - : _expr(expr), _num_predicates(_expr.num_node_predicates()), - _src_ni(src_ni), _dest_ni(dest_ni), - _pred_start(0), _check_dest(false) - - { - _edge_it.reset(new PMGD::EdgeIterator(return_iterator())); - // If the first criteria did not return any edges, - // there is no node checking on either side. - if (!bool(*_edge_it)) - return; - if (_dest_ni != NULL) { - for (; bool(*_dest_ni); _dest_ni->next()) - _dest_nodes.insert(&(**_dest_ni)); - // This iterator will be reset outside - _dest_ni = NULL; - _check_dest = true; - } - if (!check_predicates()) - next(); - } - - operator bool() const { return bool(*_edge_it); } - - bool next(); - PMGD::EdgeRef *ref() { return &(**_edge_it); } - PMGD::StringID get_tag() const { return (*_edge_it)->get_tag(); } - PMGD::Node &get_source() const { return (*_edge_it)->get_source(); } - PMGD::Node &get_destination() const { return (*_edge_it)->get_destination(); } - PMGD::Edge *get_edge() const { return &static_cast(**_edge_it); } - }; -} +template class PMGDQueryHandler::ReusableIterator { + // Iterator for the starting nodes. + Ti _ti; // Type Iterator + + // TODO Is list the best data structure + // if we could potentially sort? + typedef std::list base_container; + base_container _traversed; + + // Current postion of list iterator + typedef typename base_container::iterator list_iterator; + list_iterator _it; + + bool _next() { + if (_it != _traversed.end()) { + ++_it; + if (_it != _traversed.end()) + return true; + } + if (bool(_ti)) { + _it = _traversed.insert(_traversed.end(), &static_cast(*_ti)); + _ti.next(); + return true; + } + return false; + } + + T *ref() { + if (!bool(*this)) + throw PMGDException(NullIterator, "Null impl"); + return *_it; + } + + // TODO Is this the best way to do this + struct compare_propkey_ascending { + PMGD::StringID _propid; + bool operator()(const T *n1, const T *n2) { + return n1->get_property(_propid) < n2->get_property(_propid); + } + }; + + struct compare_propkey_descending { + PMGD::StringID _propid; + bool operator()(const T *n1, const T *n2) { + return n1->get_property(_propid) > n2->get_property(_propid); + } + }; + +public: + // Make sure this is not auto-declared. The move one won't be. + ReusableIterator(const ReusableIterator &) = delete; + ReusableIterator(Ti ti) : _ti(ti), _it(_traversed.begin()) { _next(); } + + // Add this to clean up the NewNodeIterator requirement + ReusableIterator(T *n) + : _ti(NULL), _it(_traversed.insert(_traversed.end(), n)) {} + + ReusableIterator(); + + operator bool() const { return _it != _traversed.end(); } + bool next() { return _next(); } + T &operator*() { return *ref(); } + T *operator->() { return ref(); } + void reset() { _it = _traversed.begin(); } + void traverse_all() { + for (; _ti; _ti.next()) + _traversed.insert(_traversed.end(), &static_cast(*_ti)); + } + + // Sort the list. Once the list is sorted, all operations + // following that happen in a sorted manner. And this function + // resets the iterator to the beginning. + void sort(PMGD::StringID sortkey, bool descending = false) { + // First finish traversal + traverse_all(); + if (descending) + _traversed.sort(compare_propkey_descending{sortkey}); + else + _traversed.sort(compare_propkey_ascending{sortkey}); + + _it = _traversed.begin(); + } + + // Allow adding of edges as we construct this iterator in add_edge + // call. This is different than add_node since once add_edge can + // cause multiple edges to be created depending on how many nodes + // matched the source/destination conditions + void add(T *t); +}; + +// Specialization for PMGDQueryHandler::ReusableIterator + +template <> +PMGDQueryHandler::ReusableIterator::ReusableIterator(); + +template <> +void PMGDQueryHandler::ReusableIterator::add( + PMGD::Edge *e); + +// End of specialization for PMGDQueryHandler::ReusableIterator + +class PMGDQueryHandler::MultiNeighborIteratorImpl + : public PMGD::NodeIteratorImplIntf { + // Iterator for the starting nodes. + ReusableNodeIterator *_start_ni; + SearchExpression _search_neighbors; + PMGD::NodeIterator *_neighb_i; + PMGD::Direction _dir; + PMGD::StringID _edge_tag; + + bool _next(); + +public: + MultiNeighborIteratorImpl(ReusableNodeIterator *start_ni, + SearchExpression search_neighbors, + PMGD::Direction dir, PMGD::StringID edge_tag) + : _start_ni(start_ni), _search_neighbors(search_neighbors), + _neighb_i(NULL), _dir(dir), _edge_tag(edge_tag) { + _next(); + } + + ~MultiNeighborIteratorImpl() { delete _neighb_i; } + + operator bool() const { return _neighb_i != NULL ? bool(*_neighb_i) : false; } + + /// No next matching node + bool next(); + + PMGD::Node *ref() { return &**_neighb_i; } +}; + +class PMGDQueryHandler::NodeEdgeIteratorImpl + : public PMGD::EdgeIteratorImplIntf { + /// Reference to expression to evaluate + const SearchExpression _expr; + const size_t _num_predicates; + + ReusableNodeIterator *_src_ni; + ReusableNodeIterator *_dest_ni; + + // In order to check if the other end of an edge is in the nodes + // covered by the dest_ni, it is best to store those nodes in an + // easily searchable data structure, which a list inside ReusableNodeIterator + // is not. Besides, it doesn't make sense to expose that list here. + std::unordered_set _dest_nodes; + + std::size_t _pred_start; + PMGD::Direction _dir; + bool _check_dest; + + // PMGD::EdgeIterator *_edge_it; + std::unique_ptr _edge_it; + + bool _next(); + bool check_predicates(); + + PMGD::EdgeIterator return_iterator() { + _dir = PMGD::Direction::Outgoing; + if (_src_ni == NULL) { + if (_dest_ni == NULL) + _pred_start = 1; + else { + _dir = PMGD::Direction::Incoming; + _src_ni = _dest_ni; + _dest_ni = NULL; + } + } + + // !bool(*_src_ni) will never be empty because of how the code is + // right now, but we should change in the future because we want + // to continue with the transaction even if some querynode did not + // find anything. We leave it for now. + if (_src_ni == NULL || !bool(*_src_ni)) { + PMGD::PropertyPredicate pp; + if (_num_predicates > 0) + pp = _expr.get_node_predicate(0); + else + pp = PMGD::PropertyPredicate(); + return _expr.db().get_edges(_expr.tag(), pp); + } else { + return (*_src_ni)->get_edges(_dir, _expr.tag()); + } + } + +public: + NodeEdgeIteratorImpl(const SearchExpression &expr, + ReusableNodeIterator *src_ni = NULL, + ReusableNodeIterator *dest_ni = NULL) + : _expr(expr), _num_predicates(_expr.num_node_predicates()), + _src_ni(src_ni), _dest_ni(dest_ni), _pred_start(0), _check_dest(false) + + { + _edge_it.reset(new PMGD::EdgeIterator(return_iterator())); + // If the first criteria did not return any edges, + // there is no node checking on either side. + if (!bool(*_edge_it)) + return; + if (_dest_ni != NULL) { + for (; bool(*_dest_ni); _dest_ni->next()) + _dest_nodes.insert(&(**_dest_ni)); + // This iterator will be reset outside + _dest_ni = NULL; + _check_dest = true; + } + if (!check_predicates()) + next(); + } + + operator bool() const { return bool(*_edge_it); } + + bool next(); + PMGD::EdgeRef *ref() { return &(**_edge_it); } + PMGD::StringID get_tag() const { return (*_edge_it)->get_tag(); } + PMGD::Node &get_source() const { return (*_edge_it)->get_source(); } + PMGD::Node &get_destination() const { return (*_edge_it)->get_destination(); } + PMGD::Edge *get_edge() const { + return &static_cast(**_edge_it); + } +}; +} // namespace VDMS diff --git a/src/PMGDQuery.cc b/src/PMGDQuery.cc index 4e03592f..18faf2d4 100644 --- a/src/PMGDQuery.cc +++ b/src/PMGDQuery.cc @@ -29,14 +29,14 @@ * */ -#include -#include -#include #include +#include +#include +#include -#include "PMGDQueryHandler.h" -#include "PMGDQuery.h" #include "ExceptionsCommand.h" +#include "PMGDQuery.h" +#include "PMGDQueryHandler.h" #include #include @@ -46,774 +46,704 @@ using namespace VDMS; // This is for internal reference of the transaction -#define REFERENCE_RANGE_START 20000 - -PMGDQuery::PMGDQuery(PMGDQueryHandler& pmgd_qh) : - _pmgd_qh(pmgd_qh), _current_ref(REFERENCE_RANGE_START), - _readonly(true),_resultdeletion(false),_resultexpiration(false) -{ - _current_group_id = 0; - //this command to start a new transaction - PMGDCmd* cmdtx = new PMGDCmd; - //this the protobuf of a new TxBegin - cmdtx->set_cmd_id(PMGDCmd::TxBegin); - cmdtx->set_cmd_grp_id(_current_group_id); //give it an ID - _cmds.push_back(cmdtx); //push the creating command to the vector - - // Every node in database automatically - _expiration_limit = VDMSConfig::instance()->get_int_value(PARAM_NODE_EXPIRATION, DEFAULT_NODE_EXPIRATION); +#define REFERENCE_RANGE_START 20000 + +PMGDQuery::PMGDQuery(PMGDQueryHandler &pmgd_qh) + : _pmgd_qh(pmgd_qh), _current_ref(REFERENCE_RANGE_START), _readonly(true), + _resultdeletion(false), _resultexpiration(false) { + _current_group_id = 0; + // this command to start a new transaction + PMGDCmd *cmdtx = new PMGDCmd; + // this the protobuf of a new TxBegin + cmdtx->set_cmd_id(PMGDCmd::TxBegin); + cmdtx->set_cmd_grp_id(_current_group_id); // give it an ID + _cmds.push_back(cmdtx); // push the creating command to the vector + + // Every node in database automatically + _expiration_limit = VDMSConfig::instance()->get_int_value( + PARAM_NODE_EXPIRATION, DEFAULT_NODE_EXPIRATION); } -PMGDQuery::~PMGDQuery() -{ - for (auto cmd : _cmds) { - delete cmd; - } +PMGDQuery::~PMGDQuery() { + for (auto cmd : _cmds) { + delete cmd; + } } -Json::Value& PMGDQuery::run(bool autodlete_init) -{ - add_group(); // will set _current_group_id correctly - - // End of the transaction - PMGDCmd* cmdtxend = new PMGDCmd; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend->set_cmd_id(PMGDCmd::TxCommit); - cmdtxend->set_cmd_grp_id(_current_group_id); - _cmds.push_back(cmdtxend); - - // execute the queries using the PMGDQueryHandler object - std::vector> _pmgd_responses; - _pmgd_responses = _pmgd_qh.process_queries(_cmds, _current_group_id + 1, _readonly, _resultdeletion, autodlete_init); - - if (_pmgd_responses.size() != _current_group_id + 1) { - if (_pmgd_responses.size() == 1 && _pmgd_responses[0].size() == 1) { - _json_responses["status"] = -1; - _json_responses["info"] = _pmgd_responses[0][0]->error_msg(); - return _json_responses; - } - _json_responses["status"] = -1; - _json_responses["info"] = "PMGDQuery: PMGD Transacion Error"; - return _json_responses; +Json::Value &PMGDQuery::run(bool autodlete_init) { + add_group(); // will set _current_group_id correctly + + // End of the transaction + PMGDCmd *cmdtxend = new PMGDCmd; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend->set_cmd_id(PMGDCmd::TxCommit); + cmdtxend->set_cmd_grp_id(_current_group_id); + _cmds.push_back(cmdtxend); + + // execute the queries using the PMGDQueryHandler object + std::vector> _pmgd_responses; + _pmgd_responses = _pmgd_qh.process_queries( + _cmds, _current_group_id + 1, _readonly, _resultdeletion, autodlete_init); + + if (_pmgd_responses.size() != _current_group_id + 1) { + if (_pmgd_responses.size() == 1 && _pmgd_responses[0].size() == 1) { + _json_responses["status"] = -1; + _json_responses["info"] = _pmgd_responses[0][0]->error_msg(); + return _json_responses; } - - // Get rid of txbeg and txend - for (int i = 1; i < _pmgd_responses.size() - 1; ++i) { - auto vec_responses = _pmgd_responses[i]; - Json::Value arr; - for (auto response : vec_responses) { - arr.append(parse_response(response)); - } - _json_responses.append(arr); + _json_responses["status"] = -1; + _json_responses["info"] = "PMGDQuery: PMGD Transacion Error"; + return _json_responses; + } + + // Get rid of txbeg and txend + for (int i = 1; i < _pmgd_responses.size() - 1; ++i) { + auto vec_responses = _pmgd_responses[i]; + Json::Value arr; + for (auto response : vec_responses) { + arr.append(parse_response(response)); } + _json_responses.append(arr); + } - for (auto& group : _pmgd_responses) { - for (auto ptr : group) { - delete ptr; - } - group.clear(); + for (auto &group : _pmgd_responses) { + for (auto ptr : group) { + delete ptr; } + group.clear(); + } - return _json_responses; + return _json_responses; } -void PMGDQuery::add_link(const Json::Value& link, PMGDQueryNode* qn) -{ - PMGD::protobufs::LinkInfo *qnl = qn->mutable_link(); +void PMGDQuery::add_link(const Json::Value &link, PMGDQueryNode *qn) { + PMGD::protobufs::LinkInfo *qnl = qn->mutable_link(); - qnl->set_start_identifier(link["ref"].asInt()); - qnl->set_dir(PMGD::protobufs::LinkInfo::Any); + qnl->set_start_identifier(link["ref"].asInt()); + qnl->set_dir(PMGD::protobufs::LinkInfo::Any); - if (link.isMember("direction")) { - const std::string& direction = link["direction"].asString(); + if (link.isMember("direction")) { + const std::string &direction = link["direction"].asString(); - if (direction == "out") - qnl->set_dir(PMGD::protobufs::LinkInfo::Outgoing); - else if ( direction == "in") - qnl->set_dir(PMGD::protobufs::LinkInfo::Incoming); - } + if (direction == "out") + qnl->set_dir(PMGD::protobufs::LinkInfo::Outgoing); + else if (direction == "in") + qnl->set_dir(PMGD::protobufs::LinkInfo::Incoming); + } - if (link.isMember("unique")) - qnl->set_nb_unique(link["unique"].asBool()); - else - qnl->set_nb_unique(false); + if (link.isMember("unique")) + qnl->set_nb_unique(link["unique"].asBool()); + else + qnl->set_nb_unique(false); - if (link.isMember("class")) - qnl->set_e_tag(link["class"].asString()); + if (link.isMember("class")) + qnl->set_e_tag(link["class"].asString()); - if (link.isMember("constraints")) { - qnl->set_p_op(PMGD::protobufs::And); - parse_query_constraints(link["constraints"], qnl); - } + if (link.isMember("constraints")) { + qnl->set_p_op(PMGD::protobufs::And); + parse_query_constraints(link["constraints"], qnl); + } } -void PMGDQuery::set_value(const std::string& key, const PMGDProp& p, - Json::Value& prop) -{ - switch(p.type()) { - case PMGDProp::BooleanType: - prop[key] = p.bool_value(); - break; +void PMGDQuery::set_value(const std::string &key, const PMGDProp &p, + Json::Value &prop) { + switch (p.type()) { + case PMGDProp::BooleanType: + prop[key] = p.bool_value(); + break; - case PMGDProp::IntegerType: - prop[key] = (Json::Value::Int64) p.int_value(); - break; + case PMGDProp::IntegerType: + prop[key] = (Json::Value::Int64)p.int_value(); + break; - case PMGDProp::StringType: - prop[key] = p.string_value(); - break; + case PMGDProp::StringType: + prop[key] = p.string_value(); + break; - case PMGDProp::TimeType: - prop[key] = p.time_value(); - break; + case PMGDProp::TimeType: + prop[key] = p.time_value(); + break; - case PMGDProp::FloatType: - prop[key] = p.float_value(); - break; + case PMGDProp::FloatType: + prop[key] = p.float_value(); + break; - default: - throw ExceptionCommand(PMGDTransactiontError, "Type Error"); - } + default: + throw ExceptionCommand(PMGDTransactiontError, "Type Error"); + } } -void PMGDQuery::set_property(PMGDProp* p, const std::string& key, - const Json::Value& val) -{ - p->set_key(key); - - switch (val.type()) { - case Json::intValue: - case Json::uintValue: - p->set_type(PMGDProp::IntegerType); - p->set_int_value(val.asInt64()); - break; - - case Json::booleanValue: - p->set_type(PMGDProp::BooleanType); - p->set_bool_value(val.asBool()); - break; - - case Json::realValue: - p->set_type(PMGDProp::FloatType); - p->set_float_value(val.asDouble()); - break; - - case Json::stringValue: - p->set_type(PMGDProp::StringType); - p->set_string_value(val.asString()); - break; - - case Json::objectValue: - if (val.isMember("_date")) { - p->set_type(PMGDProp::TimeType); - p->set_time_value(val["_date"].asString()); - } - else if (val.isMember("_blob")) { - // the blob value is read and stored as a string - p->set_type(PMGDProp::StringType); - p->set_string_value(val["_blob"].asString()); - } - else { - printf("%s\n", key.c_str()); - throw ExceptionCommand(PMGDTransactiontError, - "Object Type Error"); - } - break; - - default: - printf("%s\n", key.c_str()); - throw ExceptionCommand(PMGDTransactiontError, - "Object Type Error"); +void PMGDQuery::set_property(PMGDProp *p, const std::string &key, + const Json::Value &val) { + p->set_key(key); + + switch (val.type()) { + case Json::intValue: + case Json::uintValue: + p->set_type(PMGDProp::IntegerType); + p->set_int_value(val.asInt64()); + break; + + case Json::booleanValue: + p->set_type(PMGDProp::BooleanType); + p->set_bool_value(val.asBool()); + break; + + case Json::realValue: + p->set_type(PMGDProp::FloatType); + p->set_float_value(val.asDouble()); + break; + + case Json::stringValue: + p->set_type(PMGDProp::StringType); + p->set_string_value(val.asString()); + break; + + case Json::objectValue: + if (val.isMember("_date")) { + p->set_type(PMGDProp::TimeType); + p->set_time_value(val["_date"].asString()); + } else if (val.isMember("_blob")) { + // the blob value is read and stored as a string + p->set_type(PMGDProp::StringType); + p->set_string_value(val["_blob"].asString()); + } else { + printf("%s\n", key.c_str()); + throw ExceptionCommand(PMGDTransactiontError, "Object Type Error"); } + break; + + default: + printf("%s\n", key.c_str()); + throw ExceptionCommand(PMGDTransactiontError, "Object Type Error"); + } } -Json::Value PMGDQuery::construct_error_response(PMGDCmdResponse *response) -{ - Json::Value ret; - ret["status"] = response->error_code(); - ret["info"] = response->error_msg(); - return ret; +Json::Value PMGDQuery::construct_error_response(PMGDCmdResponse *response) { + Json::Value ret; + ret["status"] = response->error_code(); + ret["info"] = response->error_msg(); + return ret; } -Json::Value PMGDQuery::parse_response(PMGDCmdResponse* response) -{ - Json::Value ret; - int return_code = response->error_code(); - - auto response_success_or_exists = [&return_code]() { - return return_code == PMGDCmdResponse::Success && - return_code == PMGDCmdResponse::Exists; - }; - - auto response_success = [&return_code]() { - return return_code == PMGDCmdResponse::Success; - }; - - switch (response->r_type()) { - - case PMGD::protobufs::NodeID: - if (!response_success_or_exists()) { - return construct_error_response(response); - } - break; - - case PMGD::protobufs::EdgeID: - if (!response_success_or_exists()) { - return construct_error_response(response); - } - break; - - case PMGD::protobufs::Cached: - if (!response_success()) - return construct_error_response(response); - break; - - case PMGD::protobufs::List: - if (response_success()) { - Json::Value list(Json::arrayValue); - auto& mymap = response->prop_values(); - - // assert(mymap.size() > 0); - - uint64_t count = response->op_int_value(); - - for (uint64_t i = 0; i < count; ++i) { - Json::Value prop; - - for (auto& key : mymap) { - const PMGDPropList& p = key.second; - set_value(key.first, p.values(i), prop); - } - - list.append(prop); - } - - // if count <= 0, we return an empty list (json array) - ret["returned"] = (Json::UInt64) count; - if (response->node_edge()) - ret["entities"] = list; - else - ret["connections"] = list; - } - else { - return construct_error_response(response); - } - break; - - case PMGD::protobufs::Average: - if (response_success()) { - assert(response->op_oneof_case() == PMGDCmdResponse::kOpFloatValue); - double average = response->op_float_value(); - ret["average"] = double(average); - } - else { - return construct_error_response(response); - } - break; - - case PMGD::protobufs::Sum: - if (response_success()) { - if (response->op_oneof_case() == PMGDCmdResponse::kOpFloatValue) - ret["sum"] = response->op_float_value(); - else - ret["sum"] = (Json::UInt64)response->op_int_value(); - } - else { - return construct_error_response(response); - } - break; - - case PMGD::protobufs::Count: - if (response_success()) { - ret["count"] = (Json::UInt64) response->op_int_value(); - } - else { - return construct_error_response(response); - } - break; - - default: - return construct_error_response(response); +Json::Value PMGDQuery::parse_response(PMGDCmdResponse *response) { + Json::Value ret; + int return_code = response->error_code(); + + auto response_success_or_exists = [&return_code]() { + return return_code == PMGDCmdResponse::Success && + return_code == PMGDCmdResponse::Exists; + }; + + auto response_success = [&return_code]() { + return return_code == PMGDCmdResponse::Success; + }; + + switch (response->r_type()) { + + case PMGD::protobufs::NodeID: + if (!response_success_or_exists()) { + return construct_error_response(response); } + break; - ret["status"] = PMGDCmdResponse::Success; - return ret; -} + case PMGD::protobufs::EdgeID: + if (!response_success_or_exists()) { + return construct_error_response(response); + } + break; -template -bool PMGDQuery::parse_query_constraints(const Json::Value& constraints, - T* pb_constraints, bool purge_query) -{ - bool expiration_query_match = false; - bool deletion_query_match = false; - bool final_purge_query = false; - for (auto it = constraints.begin(); it != constraints.end(); ++it) { - bool expiration_iteration = false; - const Json::Value& predicate = *it; - const std::string& key = it.key().asString(); - - if(key.compare("_deletion") == 0) - { - deletion_query_match = true; - } - else - { - if(key.compare("_expiration") == 0) //TODO: Or in configuration - { - expiration_query_match = true; - expiration_iteration = true; - } - - // Will either have 2 or 4 arguments as verified when parsing - // JSON - if (predicate.size() == 2 && predicate[1].isArray()) { - // This will make the entire query OR, - // not sure if it is right. - pb_constraints->set_p_op(PMGD::protobufs::Or); - - const std::string& pred1 = predicate[0].asString(); - - PMGDPropPred::Op op = PMGDPropPred::Eq; - - if (pred1 == ">") - { - op = PMGDPropPred::Gt; - //ddm if comtraint is _expiration and predicate 2 is less tham curremt time - expiration_query_match = false; - } - else if (pred1 == ">=") - { - op = PMGDPropPred::Ge; - expiration_query_match = false; - } - else if (pred1 == "<") - { - op = PMGDPropPred::Lt; - } - else if (pred1 == "<=") - { - op = PMGDPropPred::Le; - } - else if (pred1 == "==") - { - op = PMGDPropPred::Eq; - // expiration_query_match = false; - } - else if (pred1 == "!=") - { - op = PMGDPropPred::Ne; - expiration_query_match = false; - } - else - { - throw ExceptionCommand(PMGDTransactiontError, - "Invalid comparsion predicate"); - } - - for (auto& value : predicate[1]) { - PMGDPropPred* pp = pb_constraints->add_predicates(); - pp->set_key(key); //assign the property predicate key - pp->set_op(op); - PMGDProp* p1 = pp->mutable_v1(); - set_property(p1, key, value); - } - - } - else if (predicate.size() == 2) { - PMGDPropPred* pp = pb_constraints->add_predicates(); - pp->set_key(key); //assign the property predicate key - - PMGDProp* p1 = pp->mutable_v1(); - set_property(p1, key, predicate[1]); - - const std::string& pred1 = predicate[0].asString(); - - if (pred1 == ">") - { - pp->set_op(PMGDPropPred::Gt); - expiration_query_match = false; - } - else if (pred1 == ">=") - { - pp->set_op(PMGDPropPred::Ge); - expiration_query_match = false; - } - else if (pred1 == "<") - { - pp->set_op(PMGDPropPred::Lt); - } - else if (pred1 == "<=") - { - pp->set_op(PMGDPropPred::Le); - } - else if (pred1 == "==") - { - pp->set_op(PMGDPropPred::Eq); - } - else if (pred1 == "!=") - { - pp->set_op(PMGDPropPred::Ne); - expiration_query_match = false; - } - - //ddm if query still matches - check to ensure that ti,e is in the past - if(expiration_query_match && expiration_iteration) - { - if(predicate[1].asUInt64() >= 1+ std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count()) - { - expiration_query_match = false; - } - } - - } - else { - - PMGDPropPred* pp = pb_constraints->add_predicates(); - pp->set_key(key); //assign the property predicate key - - PMGDProp* p1 = pp->mutable_v1(); - set_property(p1, key, predicate[1]); - - const std::string& pred1 = predicate[0].asString(); - - PMGDProp* p2 = pp->mutable_v2(); - set_property(p2, key, predicate[3]); - - const std::string& pred2 = predicate[2].asString(); - - if (pred1 == ">" && pred2 == "<") - pp->set_op(PMGDPropPred::GtLt); - else if (pred1 == ">=" && pred2 == "<") - pp->set_op(PMGDPropPred::GeLt); - else if (pred1 == ">" && pred2 == "<=") - pp->set_op(PMGDPropPred::GtLe); - else if (pred1 == ">=" && pred2 == "<=") - pp->set_op(PMGDPropPred::GeLe); - - } - } + case PMGD::protobufs::Cached: + if (!response_success()) + return construct_error_response(response); + break; - if(expiration_query_match || deletion_query_match) - { - final_purge_query = true; + case PMGD::protobufs::List: + if (response_success()) { + Json::Value list(Json::arrayValue); + auto &mymap = response->prop_values(); + + // assert(mymap.size() > 0); + + uint64_t count = response->op_int_value(); + + for (uint64_t i = 0; i < count; ++i) { + Json::Value prop; + + for (auto &key : mymap) { + const PMGDPropList &p = key.second; + set_value(key.first, p.values(i), prop); } + list.append(prop); + } + + // if count <= 0, we return an empty list (json array) + ret["returned"] = (Json::UInt64)count; + if (response->node_edge()) + ret["entities"] = list; + else + ret["connections"] = list; + } else { + return construct_error_response(response); } - return final_purge_query; -} + break; + + case PMGD::protobufs::Average: + if (response_success()) { + assert(response->op_oneof_case() == PMGDCmdResponse::kOpFloatValue); + double average = response->op_float_value(); + ret["average"] = double(average); + } else { + return construct_error_response(response); + } + break; + + case PMGD::protobufs::Sum: + if (response_success()) { + if (response->op_oneof_case() == PMGDCmdResponse::kOpFloatValue) + ret["sum"] = response->op_float_value(); + else + ret["sum"] = (Json::UInt64)response->op_int_value(); + } else { + return construct_error_response(response); + } + break; -void PMGDQuery::get_response_type(const Json::Value& res, PMGDQueryResultInfo *qn) -{ - for (auto it = res.begin(); it != res.end(); it++) { - std::string *r_key= qn->add_response_keys(); - *r_key = (*it).asString(); + case PMGD::protobufs::Count: + if (response_success()) { + ret["count"] = (Json::UInt64)response->op_int_value(); + } else { + return construct_error_response(response); } -} + break; -void PMGDQuery::parse_query_results(const Json::Value& results, - PMGDQueryResultInfo *qn) -{ - for (auto it = results.begin(); it != results.end(); it++) { - const std::string& key = it.key().asString(); + default: + return construct_error_response(response); + } - if (key == "list") { - qn->set_r_type(PMGD::protobufs::List); - get_response_type(*it, qn); - } - else if (key == "count") { - qn->set_r_type(PMGD::protobufs::Count); - } - else if (key == "sum") { - qn->set_r_type(PMGD::protobufs::Sum); - get_response_type(*it, qn); - } - else if (key == "sort") { - qn->set_sort(true); - std::string *sort_key= qn->mutable_sort_key(); - - if ((*it).isObject()) { - *sort_key = (*it)["key"].asString(); - if ((*it).isMember("order")) { - qn->set_descending((*it)["order"] == "descending" ? - true : false); - } - else { - // Default is False (i.e. result in ascending order) - qn->set_descending(false); - } - } - else { - *sort_key = (*it).asString(); - qn->set_descending(false); - } - } - else if (key == "limit") { - int limit = (*it).asUInt(); - qn->set_limit(limit); + ret["status"] = PMGDCmdResponse::Success; + return ret; +} + +template +bool PMGDQuery::parse_query_constraints(const Json::Value &constraints, + T *pb_constraints, bool purge_query) { + bool expiration_query_match = false; + bool deletion_query_match = false; + bool final_purge_query = false; + for (auto it = constraints.begin(); it != constraints.end(); ++it) { + bool expiration_iteration = false; + const Json::Value &predicate = *it; + const std::string &key = it.key().asString(); + + if (key.compare("_deletion") == 0) { + deletion_query_match = true; + } else { + if (key.compare("_expiration") == 0) // TODO: Or in configuration + { + expiration_query_match = true; + expiration_iteration = true; + } + + // Will either have 2 or 4 arguments as verified when parsing + // JSON + if (predicate.size() == 2 && predicate[1].isArray()) { + // This will make the entire query OR, + // not sure if it is right. + pb_constraints->set_p_op(PMGD::protobufs::Or); + + const std::string &pred1 = predicate[0].asString(); + + PMGDPropPred::Op op = PMGDPropPred::Eq; + + if (pred1 == ">") { + op = PMGDPropPred::Gt; + // ddm if comtraint is _expiration and predicate 2 is less tham + // curremt time + expiration_query_match = false; + } else if (pred1 == ">=") { + op = PMGDPropPred::Ge; + expiration_query_match = false; + } else if (pred1 == "<") { + op = PMGDPropPred::Lt; + } else if (pred1 == "<=") { + op = PMGDPropPred::Le; + } else if (pred1 == "==") { + op = PMGDPropPred::Eq; + // expiration_query_match = false; + } else if (pred1 == "!=") { + op = PMGDPropPred::Ne; + expiration_query_match = false; + } else { + throw ExceptionCommand(PMGDTransactiontError, + "Invalid comparsion predicate"); } - else if (key == "average") { - qn->set_r_type(PMGD::protobufs::Average); - get_response_type(*it, qn); + + for (auto &value : predicate[1]) { + PMGDPropPred *pp = pb_constraints->add_predicates(); + pp->set_key(key); // assign the property predicate key + pp->set_op(op); + PMGDProp *p1 = pp->mutable_v1(); + set_property(p1, key, value); } - } -} -void PMGDQuery::AddNode(int ref, - const std::string& tag, - const Json::Value& props, - const Json::Value& constraints) -{ - _readonly = false; - bool expiration_query_match = false; - - PMGDCmd* cmdadd = new PMGDCmd(); - cmdadd->set_cmd_id(PMGDCmd::AddNode); - cmdadd->set_cmd_grp_id(_current_group_id); - PMGD::protobufs::AddNode *an = cmdadd->mutable_add_node(); - an->set_identifier(ref); - - PMGD::protobufs::Node *n = an->mutable_node(); - n->set_tag(tag); - - for (auto it = props.begin(); it != props.end(); ++it) { - //add a extra properties in the event that special keyword _expiration is present in properties - if(std::string(it.key().asString()).compare("_expiration") == 0) - { - auto now = std::chrono::system_clock::now(); - Json::UInt64 creation_time = std::chrono::time_point_cast(now).time_since_epoch().count(); - Json::UInt64 expiration_time = creation_time + it->asUInt64(); - PMGDProp* q = n->add_properties(); - set_property(q, "_creation", Json::Value(creation_time)); - q = n->add_properties(); - set_property(q, "_expiration", Json::Value(expiration_time)); - expiration_query_match = true; - an->set_expiration_flag(true); + } else if (predicate.size() == 2) { + PMGDPropPred *pp = pb_constraints->add_predicates(); + pp->set_key(key); // assign the property predicate key + + PMGDProp *p1 = pp->mutable_v1(); + set_property(p1, key, predicate[1]); + + const std::string &pred1 = predicate[0].asString(); + + if (pred1 == ">") { + pp->set_op(PMGDPropPred::Gt); + expiration_query_match = false; + } else if (pred1 == ">=") { + pp->set_op(PMGDPropPred::Ge); + expiration_query_match = false; + } else if (pred1 == "<") { + pp->set_op(PMGDPropPred::Lt); + } else if (pred1 == "<=") { + pp->set_op(PMGDPropPred::Le); + } else if (pred1 == "==") { + pp->set_op(PMGDPropPred::Eq); + } else if (pred1 == "!=") { + pp->set_op(PMGDPropPred::Ne); + expiration_query_match = false; } - else - { - PMGDProp* p = n->add_properties(); - set_property(p, it.key().asString(), *it); + + // ddm if query still matches - check to ensure that ti,e is in the past + if (expiration_query_match && expiration_iteration) { + if (predicate[1].asUInt64() >= + 1 + std::chrono::time_point_cast( + std::chrono::system_clock::now()) + .time_since_epoch() + .count()) { + expiration_query_match = false; + } } - } + } else { - // Check for expiration in config file - if(!expiration_query_match && _expiration_limit != DEFAULT_NODE_EXPIRATION) { - auto now = std::chrono::system_clock::now(); - Json::UInt64 creation_time = std::chrono::time_point_cast(now).time_since_epoch().count(); - Json::UInt64 expiration_time = creation_time + _expiration_limit; - PMGDProp* q = n->add_properties(); - set_property(q, "_creation", Json::Value(creation_time)); - q = n->add_properties(); - set_property(q, "_expiration", Json::Value(expiration_time)); - an->set_expiration_flag(true); - } + PMGDPropPred *pp = pb_constraints->add_predicates(); + pp->set_key(key); // assign the property predicate key - if(!constraints.isNull()) { - PMGDQueryNode *qn = an->mutable_query_node(); - qn->set_identifier(ref); // Use the same ref to cache if node exists. - PMGDQueryConstraints *qc = qn->mutable_constraints(); - qc->set_tag(tag); - qc->set_unique(true); - qc->set_p_op(PMGD::protobufs::And); - parse_query_constraints(constraints, qc); - PMGDQueryResultInfo *qr = qn->mutable_results(); - qr->set_r_type(PMGD::protobufs::NodeID); // Since PMGD returns ids. - } + PMGDProp *p1 = pp->mutable_v1(); + set_property(p1, key, predicate[1]); - _cmds.push_back(cmdadd); -} + const std::string &pred1 = predicate[0].asString(); -void PMGDQuery::UpdateNode(int ref, - const std::string& tag, - const Json::Value& props, - const Json::Value& remove_props, - const Json::Value& constraints, - bool unique) -{ - _readonly = false; - - PMGDCmd* cmdupdate = new PMGDCmd(); - cmdupdate->set_cmd_id(PMGDCmd::UpdateNode); - cmdupdate->set_cmd_grp_id(_current_group_id); - PMGD::protobufs::UpdateNode *un = cmdupdate->mutable_update_node(); - un->set_identifier(ref); - - for (auto it = props.begin(); it != props.end(); ++it) { - PMGDProp* p = un->add_properties(); - set_property(p, it.key().asString(), *it); - } + PMGDProp *p2 = pp->mutable_v2(); + set_property(p2, key, predicate[3]); + + const std::string &pred2 = predicate[2].asString(); - for (auto it = remove_props.begin(); it != remove_props.end(); it++) { - std::string *r_key= un->add_remove_props(); - *r_key = (*it).asString(); + if (pred1 == ">" && pred2 == "<") + pp->set_op(PMGDPropPred::GtLt); + else if (pred1 == ">=" && pred2 == "<") + pp->set_op(PMGDPropPred::GeLt); + else if (pred1 == ">" && pred2 == "<=") + pp->set_op(PMGDPropPred::GtLe); + else if (pred1 == ">=" && pred2 == "<=") + pp->set_op(PMGDPropPred::GeLe); + } } - if(!constraints.isNull()) { - PMGDQueryNode *qn = un->mutable_query_node(); - qn->set_identifier(ref < 0 ? get_available_reference() : ref); - PMGDQueryConstraints *qc = qn->mutable_constraints(); - qc->set_tag(tag); - qc->set_unique(unique); - qc->set_p_op(PMGD::protobufs::And); - parse_query_constraints(constraints, qc); - PMGDQueryResultInfo *qr = qn->mutable_results(); - qr->set_r_type(PMGD::protobufs::NodeID); // Since PMGD returns ids. + if (expiration_query_match || deletion_query_match) { + final_purge_query = true; } + } + return final_purge_query; +} - _cmds.push_back(cmdupdate); +void PMGDQuery::get_response_type(const Json::Value &res, + PMGDQueryResultInfo *qn) { + for (auto it = res.begin(); it != res.end(); it++) { + std::string *r_key = qn->add_response_keys(); + *r_key = (*it).asString(); + } } -void PMGDQuery::AddEdge(int ident, - int src, int dst, - const std::string& tag, - const Json::Value& props) -{ - _readonly = false; - - PMGDCmd* cmdedge = new PMGDCmd(); - cmdedge->set_cmd_grp_id(_current_group_id); - cmdedge->set_cmd_id(PMGDCmd::AddEdge); - PMGD::protobufs::AddEdge *ae = cmdedge->mutable_add_edge(); - ae->set_identifier(ident); - - PMGD::protobufs::Edge *e = ae->mutable_edge(); - e->set_tag(tag); - e->set_src(src); - e->set_dst(dst); - - for (auto it = props.begin(); it != props.end(); ++it) { - PMGDProp* p = e->add_properties(); - set_property(p, it.key().asString(), *it); +void PMGDQuery::parse_query_results(const Json::Value &results, + PMGDQueryResultInfo *qn) { + for (auto it = results.begin(); it != results.end(); it++) { + const std::string &key = it.key().asString(); + + if (key == "list") { + qn->set_r_type(PMGD::protobufs::List); + get_response_type(*it, qn); + } else if (key == "count") { + qn->set_r_type(PMGD::protobufs::Count); + } else if (key == "sum") { + qn->set_r_type(PMGD::protobufs::Sum); + get_response_type(*it, qn); + } else if (key == "sort") { + qn->set_sort(true); + std::string *sort_key = qn->mutable_sort_key(); + + if ((*it).isObject()) { + *sort_key = (*it)["key"].asString(); + if ((*it).isMember("order")) { + qn->set_descending((*it)["order"] == "descending" ? true : false); + } else { + // Default is False (i.e. result in ascending order) + qn->set_descending(false); + } + } else { + *sort_key = (*it).asString(); + qn->set_descending(false); + } + } else if (key == "limit") { + int limit = (*it).asUInt(); + qn->set_limit(limit); + } else if (key == "average") { + qn->set_r_type(PMGD::protobufs::Average); + get_response_type(*it, qn); } - - _cmds.push_back(cmdedge); + } } -void PMGDQuery::UpdateEdge(int ref, int src_ref, int dest_ref, - const std::string& tag, - const Json::Value& props, - const Json::Value& remove_props, - const Json::Value& constraints, - bool unique) -{ - _readonly = false; - - PMGDCmd* cmdupdate = new PMGDCmd(); - cmdupdate->set_cmd_id(PMGDCmd::UpdateEdge); - cmdupdate->set_cmd_grp_id(_current_group_id); - PMGD::protobufs::UpdateEdge *ue = cmdupdate->mutable_update_edge(); - ue->set_identifier(ref); - - for (auto it = props.begin(); it != props.end(); ++it) { - PMGDProp* p = ue->add_properties(); - set_property(p, it.key().asString(), *it); +void PMGDQuery::AddNode(int ref, const std::string &tag, + const Json::Value &props, + const Json::Value &constraints) { + _readonly = false; + bool expiration_query_match = false; + + PMGDCmd *cmdadd = new PMGDCmd(); + cmdadd->set_cmd_id(PMGDCmd::AddNode); + cmdadd->set_cmd_grp_id(_current_group_id); + PMGD::protobufs::AddNode *an = cmdadd->mutable_add_node(); + an->set_identifier(ref); + + PMGD::protobufs::Node *n = an->mutable_node(); + n->set_tag(tag); + + for (auto it = props.begin(); it != props.end(); ++it) { + // add a extra properties in the event that special keyword _expiration is + // present in properties + if (std::string(it.key().asString()).compare("_expiration") == 0) { + auto now = std::chrono::system_clock::now(); + Json::UInt64 creation_time = + std::chrono::time_point_cast(now) + .time_since_epoch() + .count(); + Json::UInt64 expiration_time = creation_time + it->asUInt64(); + PMGDProp *q = n->add_properties(); + set_property(q, "_creation", Json::Value(creation_time)); + q = n->add_properties(); + set_property(q, "_expiration", Json::Value(expiration_time)); + expiration_query_match = true; + an->set_expiration_flag(true); + } else { + PMGDProp *p = n->add_properties(); + set_property(p, it.key().asString(), *it); } + } + + // Check for expiration in config file + if (!expiration_query_match && _expiration_limit != DEFAULT_NODE_EXPIRATION) { + auto now = std::chrono::system_clock::now(); + Json::UInt64 creation_time = + std::chrono::time_point_cast(now) + .time_since_epoch() + .count(); + Json::UInt64 expiration_time = creation_time + _expiration_limit; + PMGDProp *q = n->add_properties(); + set_property(q, "_creation", Json::Value(creation_time)); + q = n->add_properties(); + set_property(q, "_expiration", Json::Value(expiration_time)); + an->set_expiration_flag(true); + } + + if (!constraints.isNull()) { + PMGDQueryNode *qn = an->mutable_query_node(); + qn->set_identifier(ref); // Use the same ref to cache if node exists. + PMGDQueryConstraints *qc = qn->mutable_constraints(); + qc->set_tag(tag); + qc->set_unique(true); + qc->set_p_op(PMGD::protobufs::And); + parse_query_constraints(constraints, qc); + PMGDQueryResultInfo *qr = qn->mutable_results(); + qr->set_r_type(PMGD::protobufs::NodeID); // Since PMGD returns ids. + } - for (auto it = remove_props.begin(); it != remove_props.end(); it++) { - std::string *r_key= ue->add_remove_props(); - *r_key = (*it).asString(); - } + _cmds.push_back(cmdadd); +} - if(!constraints.isNull()) { - PMGDQueryEdge *qe = ue->mutable_query_edge(); - qe->set_identifier(ref < 0 ? get_available_reference() : ref); - qe->set_src_node_id(src_ref); - qe->set_dest_node_id(dest_ref); - PMGDQueryConstraints *qc = qe->mutable_constraints(); - qc->set_tag(tag); - qc->set_unique(unique); - qc->set_p_op(PMGD::protobufs::And); - parse_query_constraints(constraints, qc); - PMGDQueryResultInfo *qr = qe->mutable_results(); - qr->set_r_type(PMGD::protobufs::EdgeID); // Since PMGD returns ids. - } +void PMGDQuery::UpdateNode(int ref, const std::string &tag, + const Json::Value &props, + const Json::Value &remove_props, + const Json::Value &constraints, bool unique) { + _readonly = false; + + PMGDCmd *cmdupdate = new PMGDCmd(); + cmdupdate->set_cmd_id(PMGDCmd::UpdateNode); + cmdupdate->set_cmd_grp_id(_current_group_id); + PMGD::protobufs::UpdateNode *un = cmdupdate->mutable_update_node(); + un->set_identifier(ref); + + for (auto it = props.begin(); it != props.end(); ++it) { + PMGDProp *p = un->add_properties(); + set_property(p, it.key().asString(), *it); + } + + for (auto it = remove_props.begin(); it != remove_props.end(); it++) { + std::string *r_key = un->add_remove_props(); + *r_key = (*it).asString(); + } + + if (!constraints.isNull()) { + PMGDQueryNode *qn = un->mutable_query_node(); + qn->set_identifier(ref < 0 ? get_available_reference() : ref); + PMGDQueryConstraints *qc = qn->mutable_constraints(); + qc->set_tag(tag); + qc->set_unique(unique); + qc->set_p_op(PMGD::protobufs::And); + parse_query_constraints(constraints, qc); + PMGDQueryResultInfo *qr = qn->mutable_results(); + qr->set_r_type(PMGD::protobufs::NodeID); // Since PMGD returns ids. + } - _cmds.push_back(cmdupdate); + _cmds.push_back(cmdupdate); } -void PMGDQuery::QueryNode(int ref, - const std::string& tag, - const Json::Value& link, - const Json::Value& constraints, - const Json::Value& results, - bool unique, - bool intermediate_query) -{ - PMGDCmd* cmdquery = new PMGDCmd(); - cmdquery->set_cmd_id(PMGDCmd::QueryNode); - cmdquery->set_cmd_grp_id(_current_group_id); - - PMGDQueryNode *qn = cmdquery->mutable_query_node(); - qn->set_identifier(ref); +void PMGDQuery::AddEdge(int ident, int src, int dst, const std::string &tag, + const Json::Value &props) { + _readonly = false; - PMGDQueryConstraints *qc = qn->mutable_constraints(); + PMGDCmd *cmdedge = new PMGDCmd(); + cmdedge->set_cmd_grp_id(_current_group_id); + cmdedge->set_cmd_id(PMGDCmd::AddEdge); + PMGD::protobufs::AddEdge *ae = cmdedge->mutable_add_edge(); + ae->set_identifier(ident); + + PMGD::protobufs::Edge *e = ae->mutable_edge(); + e->set_tag(tag); + e->set_src(src); + e->set_dst(dst); + + for (auto it = props.begin(); it != props.end(); ++it) { + PMGDProp *p = e->add_properties(); + set_property(p, it.key().asString(), *it); + } + + _cmds.push_back(cmdedge); +} + +void PMGDQuery::UpdateEdge(int ref, int src_ref, int dest_ref, + const std::string &tag, const Json::Value &props, + const Json::Value &remove_props, + const Json::Value &constraints, bool unique) { + _readonly = false; + + PMGDCmd *cmdupdate = new PMGDCmd(); + cmdupdate->set_cmd_id(PMGDCmd::UpdateEdge); + cmdupdate->set_cmd_grp_id(_current_group_id); + PMGD::protobufs::UpdateEdge *ue = cmdupdate->mutable_update_edge(); + ue->set_identifier(ref); + + for (auto it = props.begin(); it != props.end(); ++it) { + PMGDProp *p = ue->add_properties(); + set_property(p, it.key().asString(), *it); + } + + for (auto it = remove_props.begin(); it != remove_props.end(); it++) { + std::string *r_key = ue->add_remove_props(); + *r_key = (*it).asString(); + } + + if (!constraints.isNull()) { + PMGDQueryEdge *qe = ue->mutable_query_edge(); + qe->set_identifier(ref < 0 ? get_available_reference() : ref); + qe->set_src_node_id(src_ref); + qe->set_dest_node_id(dest_ref); + PMGDQueryConstraints *qc = qe->mutable_constraints(); qc->set_tag(tag); qc->set_unique(unique); + qc->set_p_op(PMGD::protobufs::And); + parse_query_constraints(constraints, qc); + PMGDQueryResultInfo *qr = qe->mutable_results(); + qr->set_r_type(PMGD::protobufs::EdgeID); // Since PMGD returns ids. + } - if (!link.isNull()) { - add_link(link, qn); - } + _cmds.push_back(cmdupdate); +} - // TODO: We always assume AND, we need to change that - qc->set_p_op(PMGD::protobufs::And); - _resultdeletion = false; - if (!constraints.isNull()) - { - - bool force_purge = parse_query_constraints(constraints, qc, true); - if(force_purge && !intermediate_query) - { - _resultdeletion = true; - } +void PMGDQuery::QueryNode(int ref, const std::string &tag, + const Json::Value &link, + const Json::Value &constraints, + const Json::Value &results, bool unique, + bool intermediate_query) { + PMGDCmd *cmdquery = new PMGDCmd(); + cmdquery->set_cmd_id(PMGDCmd::QueryNode); + cmdquery->set_cmd_grp_id(_current_group_id); + + PMGDQueryNode *qn = cmdquery->mutable_query_node(); + qn->set_identifier(ref); + + PMGDQueryConstraints *qc = qn->mutable_constraints(); + qc->set_tag(tag); + qc->set_unique(unique); + + if (!link.isNull()) { + add_link(link, qn); + } + + // TODO: We always assume AND, we need to change that + qc->set_p_op(PMGD::protobufs::And); + _resultdeletion = false; + if (!constraints.isNull()) { + + bool force_purge = parse_query_constraints(constraints, qc, true); + if (force_purge && !intermediate_query) { + _resultdeletion = true; } + } - PMGDQueryResultInfo *qr = qn->mutable_results(); - if (!results.isNull()) - parse_query_results(results, qr); + PMGDQueryResultInfo *qr = qn->mutable_results(); + if (!results.isNull()) + parse_query_results(results, qr); - _cmds.push_back(cmdquery); + _cmds.push_back(cmdquery); } void PMGDQuery::QueryEdge(int ref, int src_ref, int dest_ref, - const std::string& tag, - const Json::Value& constraints, - const Json::Value& results, - bool unique) -{ - PMGDCmd* cmdquery = new PMGDCmd(); - cmdquery->set_cmd_id(PMGDCmd::QueryEdge); - cmdquery->set_cmd_grp_id(_current_group_id); + const std::string &tag, + const Json::Value &constraints, + const Json::Value &results, bool unique) { + PMGDCmd *cmdquery = new PMGDCmd(); + cmdquery->set_cmd_id(PMGDCmd::QueryEdge); + cmdquery->set_cmd_grp_id(_current_group_id); - PMGDQueryEdge *qn = cmdquery->mutable_query_edge(); + PMGDQueryEdge *qn = cmdquery->mutable_query_edge(); - qn->set_identifier(ref); - qn->set_src_node_id(src_ref); - qn->set_dest_node_id(dest_ref); + qn->set_identifier(ref); + qn->set_src_node_id(src_ref); + qn->set_dest_node_id(dest_ref); - PMGDQueryConstraints *qc = qn->mutable_constraints(); - qc->set_tag(tag); - qc->set_unique(unique); + PMGDQueryConstraints *qc = qn->mutable_constraints(); + qc->set_tag(tag); + qc->set_unique(unique); - // TODO: We always assume AND, we need to change that - qc->set_p_op(PMGD::protobufs::And); - if (!constraints.isNull()) - parse_query_constraints(constraints, qc); + // TODO: We always assume AND, we need to change that + qc->set_p_op(PMGD::protobufs::And); + if (!constraints.isNull()) + parse_query_constraints(constraints, qc); - PMGDQueryResultInfo *qr = qn->mutable_results(); - if (!results.isNull()) - parse_query_results(results, qr); + PMGDQueryResultInfo *qr = qn->mutable_results(); + if (!results.isNull()) + parse_query_results(results, qr); - _cmds.push_back(cmdquery); + _cmds.push_back(cmdquery); } -void PMGDQuery::DeleteExpired() -{ - _readonly = false; - - PMGDCmd* cmddel = new PMGDCmd(); - cmddel->set_cmd_id(PMGDCmd::DeleteExpired); - cmddel->set_cmd_grp_id(_current_group_id); - _cmds.push_back(cmddel); +void PMGDQuery::DeleteExpired() { + _readonly = false; + PMGDCmd *cmddel = new PMGDCmd(); + cmddel->set_cmd_id(PMGDCmd::DeleteExpired); + cmddel->set_cmd_grp_id(_current_group_id); + _cmds.push_back(cmddel); } diff --git a/src/PMGDQuery.h b/src/PMGDQuery.h index 7729ff61..71d8e233 100644 --- a/src/PMGDQuery.h +++ b/src/PMGDQuery.h @@ -37,101 +37,83 @@ #include #include - namespace VDMS { - /* This class takes care of the transaction and conversion - from Protobuf data structures used by PMGD to Json structures - used by the QueryHandler - */ - class PMGDQuery - { - int _expiration_limit; - std::vector _cmds; - unsigned _current_group_id; - PMGDQueryHandler& _pmgd_qh; - unsigned _current_ref; - bool _readonly; // Stays true unless some write cmd sets it to false. - bool _resultdeletion; // Indicates whether the results should be deleted - bool _resultexpiration; //Indicates whether the result should be stored in expiration_queue - //This takes place only during an add where the _expiration flag is true - - - Json::Value _json_responses; - - void set_property(PMGDProp* p, const std::string& key, - const Json::Value& val); - void add_link(const Json::Value& link, PMGDQueryNode* qn); - - template - bool parse_query_constraints(const Json::Value& constraints, T* qc, bool purge_query=false); - - void parse_query_results(const Json::Value& result_type, - PMGDQueryResultInfo* qr); - - void get_response_type(const Json::Value& res, PMGDQueryResultInfo* qn); - - Json::Value parse_response(PMGDCmdResponse* response); - - void set_value(const std::string& key, const PMGDProp& p, - Json::Value& prop); - - Json::Value construct_error_response(PMGDCmdResponse* response); - - public: - PMGDQuery(PMGDQueryHandler& pmgd_qh); - ~PMGDQuery(); - - unsigned add_group() { return ++_current_group_id; } - unsigned current_group() { return _current_group_id; } - unsigned get_available_reference() { return _current_ref++; } - - Json::Value& run(bool autodelete_init = false); - - //This is a reference to avoid copies - Json::Value& get_json_responses() {return _json_responses;} - - PMGDQueryHandler& get_pmgd_qh() {return _pmgd_qh;} - - // If constraints is not null, this becomes a conditional AddNode - void AddNode(int ref, - const std::string& tag, - const Json::Value& props, - const Json::Value& constraints); - - void UpdateNode(int ref, - const std::string& tag, - const Json::Value& props, - const Json::Value& remove_props, - const Json::Value& constraints, - bool unique); - - void AddEdge(int ident, - int src, int dst, - const std::string& tag, - const Json::Value& props); - - void UpdateEdge(int ref, int src_ref, int dest_ref, - const std::string& tag, - const Json::Value& props, - const Json::Value& remove_props, - const Json::Value& constraints, - bool unique); - - void QueryNode(int ref, - const std::string& tag, - const Json::Value& link, - const Json::Value& constraints, - const Json::Value& results, - bool unique = false, - bool intermediate_query = false); - - void QueryEdge(int ref, int src_ref, int dest_ref, - const std::string& tag, - const Json::Value& constraints, - const Json::Value& results, - bool unique = false); - - void DeleteExpired(); - }; -} +/* This class takes care of the transaction and conversion + from Protobuf data structures used by PMGD to Json structures + used by the QueryHandler +*/ +class PMGDQuery { + int _expiration_limit; + std::vector _cmds; + unsigned _current_group_id; + PMGDQueryHandler &_pmgd_qh; + unsigned _current_ref; + bool _readonly; // Stays true unless some write cmd sets it to false. + bool _resultdeletion; // Indicates whether the results should be deleted + bool _resultexpiration; // Indicates whether the result should be stored in + // expiration_queue This takes place only during an + // add where the _expiration flag is true + + Json::Value _json_responses; + + void set_property(PMGDProp *p, const std::string &key, + const Json::Value &val); + void add_link(const Json::Value &link, PMGDQueryNode *qn); + + template + bool parse_query_constraints(const Json::Value &constraints, T *qc, + bool purge_query = false); + + void parse_query_results(const Json::Value &result_type, + PMGDQueryResultInfo *qr); + + void get_response_type(const Json::Value &res, PMGDQueryResultInfo *qn); + + Json::Value parse_response(PMGDCmdResponse *response); + + void set_value(const std::string &key, const PMGDProp &p, Json::Value &prop); + + Json::Value construct_error_response(PMGDCmdResponse *response); + +public: + PMGDQuery(PMGDQueryHandler &pmgd_qh); + ~PMGDQuery(); + + unsigned add_group() { return ++_current_group_id; } + unsigned current_group() { return _current_group_id; } + unsigned get_available_reference() { return _current_ref++; } + + Json::Value &run(bool autodelete_init = false); + + // This is a reference to avoid copies + Json::Value &get_json_responses() { return _json_responses; } + + PMGDQueryHandler &get_pmgd_qh() { return _pmgd_qh; } + + // If constraints is not null, this becomes a conditional AddNode + void AddNode(int ref, const std::string &tag, const Json::Value &props, + const Json::Value &constraints); + + void UpdateNode(int ref, const std::string &tag, const Json::Value &props, + const Json::Value &remove_props, + const Json::Value &constraints, bool unique); + + void AddEdge(int ident, int src, int dst, const std::string &tag, + const Json::Value &props); + + void UpdateEdge(int ref, int src_ref, int dest_ref, const std::string &tag, + const Json::Value &props, const Json::Value &remove_props, + const Json::Value &constraints, bool unique); + + void QueryNode(int ref, const std::string &tag, const Json::Value &link, + const Json::Value &constraints, const Json::Value &results, + bool unique = false, bool intermediate_query = false); + + void QueryEdge(int ref, int src_ref, int dest_ref, const std::string &tag, + const Json::Value &constraints, const Json::Value &results, + bool unique = false); + + void DeleteExpired(); +}; +} // namespace VDMS diff --git a/src/PMGDQueryHandler.cc b/src/PMGDQueryHandler.cc index 078c562f..888dddde 100644 --- a/src/PMGDQueryHandler.cc +++ b/src/PMGDQueryHandler.cc @@ -29,12 +29,12 @@ * */ -#include -#include "VDMSConfig.h" #include "PMGDQueryHandler.h" -#include "util.h" // PMGD util #include "PMGDIterators.h" +#include "VDMSConfig.h" #include "defines.h" +#include "util.h" // PMGD util +#include // TODO In the complete version of VDMS, this file will live // within PMGD which would replace the PMGD namespace. Some of @@ -43,1030 +43,1003 @@ using namespace PMGD; using namespace VDMS; PMGD::Graph *PMGDQueryHandler::_db; -std::list PMGDQueryHandler::_expiration_timestamp_queue; +std::list PMGDQueryHandler::_expiration_timestamp_queue; std::vector PMGDQueryHandler::_cleanup_filename_list; -void PMGDQueryHandler::init() -{ - std::string dbname = VDMSConfig::instance()->get_path_pmgd(); - int nalloc = VDMSConfig::instance()-> - get_int_value(PARAM_PMGD_NUM_ALLOCATORS, DEFAULT_PMGD_NUM_ALLOCATORS); - - PMGD::Graph::Config config; - config.num_allocators = nalloc; - - // TODO: Include allocators timeouts params as parameters for VDMS. - // These parameters can be loaded everytime VDMS is run. - // We need PMGD to support these as config params before we can do it here. - - // Create a db - _db = new PMGD::Graph(dbname.c_str(), PMGD::Graph::Create, &config); -} +void PMGDQueryHandler::init() { + std::string dbname = VDMSConfig::instance()->get_path_pmgd(); + int nalloc = VDMSConfig::instance()->get_int_value( + PARAM_PMGD_NUM_ALLOCATORS, DEFAULT_PMGD_NUM_ALLOCATORS); -void PMGDQueryHandler::destroy() -{ - if (_db) { - delete _db; - _db = NULL; - } -} + PMGD::Graph::Config config; + config.num_allocators = nalloc; -std::vector - PMGDQueryHandler::process_queries(const PMGDCmds &cmds, - int num_groups, bool readonly, bool resultdeletion, bool autodelete_init) -{ - std::vector responses(num_groups); - int retry_count = 0; - while(retry_count < PMGD_QUERY_RETRY_LIMIT) - { - if(_tx == NULL) - { - retry_count = PMGD_QUERY_RETRY_LIMIT; //exit retry loop - } - else - { - std::this_thread::sleep_for(std::chrono::milliseconds(20 * retry_count)); //backoff but for a onger time each try - retry_count++; - } - } - assert(_tx == NULL); + // TODO: Include allocators timeouts params as parameters for VDMS. + // These parameters can be loaded everytime VDMS is run. + // We need PMGD to support these as config params before we can do it here. - // Assuming one query handler handles one TX at a time. - _readonly = readonly; - _resultdeletion = resultdeletion; - _autodelete_init = autodelete_init; - if(_resultdeletion) - { - _readonly = false; // change flag so database can be written - } + // Create a db + _db = new PMGD::Graph(dbname.c_str(), PMGD::Graph::Create, &config); +} - for (const auto cmd : cmds) { - PMGDCmdResponse *response = new PMGDCmdResponse(); - response->set_node_edge(true); // most queries are node related - if (process_query(cmd, response) < 0) { - error_cleanup(responses, response); - break; // Goto cleanup site. - } - PMGDCmdResponses &resp_v = responses[cmd->cmd_grp_id()]; - resp_v.push_back(response); - } +void PMGDQueryHandler::destroy() { + if (_db) { + delete _db; + _db = NULL; + } +} - // Delete the Reusable iterators here. - for (auto it = _cached_nodes.begin(); it != _cached_nodes.end(); ++it) { - if (it->second != NULL) - delete it->second; +std::vector +PMGDQueryHandler::process_queries(const PMGDCmds &cmds, int num_groups, + bool readonly, bool resultdeletion, + bool autodelete_init) { + std::vector responses(num_groups); + int retry_count = 0; + while (retry_count < PMGD_QUERY_RETRY_LIMIT) { + if (_tx == NULL) { + retry_count = PMGD_QUERY_RETRY_LIMIT; // exit retry loop + } else { + std::this_thread::sleep_for(std::chrono::milliseconds( + 20 * retry_count)); // backoff but for a longer time each try + retry_count++; } - _cached_nodes.clear(); - if (_tx != NULL) { - delete _tx; - _tx = NULL; + } + assert(_tx == NULL); + + // Assuming one query handler handles one TX at a time. + _readonly = readonly; + _resultdeletion = resultdeletion; + _autodelete_init = autodelete_init; + if (_resultdeletion) { + _readonly = false; // change flag so database can be written + } + + for (const auto cmd : cmds) { + PMGDCmdResponse *response = new PMGDCmdResponse(); + response->set_node_edge(true); // most queries are node related + if (process_query(cmd, response) < 0) { + error_cleanup(responses, response); + break; // Goto cleanup site. } - - return responses; + PMGDCmdResponses &resp_v = responses[cmd->cmd_grp_id()]; + resp_v.push_back(response); + } + + // Delete the Reusable iterators here. + for (auto it = _cached_nodes.begin(); it != _cached_nodes.end(); ++it) { + if (it->second != NULL) + delete it->second; + } + _cached_nodes.clear(); + if (_tx != NULL) { + delete _tx; + _tx = NULL; + } + + return responses; } void PMGDQueryHandler::error_cleanup(std::vector &responses, - PMGDCmdResponse *last_resp) -{ - int num_groups = responses.size(); - for (unsigned i = 0; i < num_groups; ++i) { - unsigned size = responses[i].size(); - for (unsigned j = 0; j < size; ++j) { - if (responses[i][j] != NULL) - delete responses[i][j]; - } - responses[i].clear(); + PMGDCmdResponse *last_resp) { + int num_groups = responses.size(); + for (unsigned i = 0; i < num_groups; ++i) { + unsigned size = responses[i].size(); + for (unsigned j = 0; j < size; ++j) { + if (responses[i][j] != NULL) + delete responses[i][j]; } - responses.clear(); - - // Since we have shortened the container, this reference will still remain - // valid. So we can reuse the 0th spot. - last_resp->set_cmd_grp_id(0); - PMGDCmdResponses resp_v1; - resp_v1.push_back(last_resp); - responses.push_back(resp_v1); + responses[i].clear(); + } + responses.clear(); + + // Since we have shortened the container, this reference will still remain + // valid. So we can reuse the 0th spot. + last_resp->set_cmd_grp_id(0); + PMGDCmdResponses resp_v1; + resp_v1.push_back(last_resp); + responses.push_back(resp_v1); } int PMGDQueryHandler::process_query(const PMGDCmd *cmd, - PMGDCmdResponse *response, bool autodelete_init) -{ - - int retval = 0; - PMGD::protobufs::Node* an; - - try { - int code = cmd->cmd_id(); - response->set_cmd_grp_id(cmd->cmd_grp_id()); - switch (code) { - case PMGDCmd::TxBegin: - { - int tx_options = _readonly ? Transaction::ReadOnly : Transaction::ReadWrite; - _tx = new Transaction(*_db, tx_options); - set_response(response, protobufs::TX, PMGDCmdResponse::Success); - break; - } - case PMGDCmd::TxCommit: - { - _tx->commit(); - set_response(response, protobufs::TX, PMGDCmdResponse::Success); - break; - } - case PMGDCmd::TxAbort: - { - set_response(response, protobufs::TX, PMGDCmdResponse::Abort, - "Abort called"); - retval = -1; - break; - } - case PMGDCmd::AddNode: - retval = add_node(cmd->add_node(), response); - break; - case PMGDCmd::AddEdge: - retval = add_edge(cmd->add_edge(), response); - break; - case PMGDCmd::QueryNode: - retval = query_node(cmd->query_node(), response, autodelete_init); - break; - case PMGDCmd::QueryEdge: - retval = query_edge(cmd->query_edge(), response); - break; - case PMGDCmd::UpdateNode: - update_node(cmd->update_node(), response); - break; - case PMGDCmd::UpdateEdge: - update_edge(cmd->update_edge(), response); - break; - case PMGDCmd::DeleteExpired: - retval = delete_expired_nodes(); - break; - } + PMGDCmdResponse *response, + bool autodelete_init) { + + int retval = 0; + PMGD::protobufs::Node *an; + + try { + int code = cmd->cmd_id(); + response->set_cmd_grp_id(cmd->cmd_grp_id()); + switch (code) { + case PMGDCmd::TxBegin: { + int tx_options = + _readonly ? Transaction::ReadOnly : Transaction::ReadWrite; + _tx = new Transaction(*_db, tx_options); + set_response(response, protobufs::TX, PMGDCmdResponse::Success); + break; } - catch (Exception e) { - set_response(response, PMGDCmdResponse::Exception, - e.name + std::string(": ") + e.msg); - retval = -1; + case PMGDCmd::TxCommit: { + _tx->commit(); + set_response(response, protobufs::TX, PMGDCmdResponse::Success); + break; } - - return retval; -} - -int PMGDQueryHandler::add_node(const protobufs::AddNode &cn, - PMGDCmdResponse *response) -{ - Json::UInt64 expiration_time; - long id = cn.identifier(); - if (id >= 0 && _cached_nodes.find(id) != _cached_nodes.end()) { - set_response(response, PMGDCmdResponse::Error, "Reuse of _ref value"); - return -1; + case PMGDCmd::TxAbort: { + set_response(response, protobufs::TX, PMGDCmdResponse::Abort, + "Abort called"); + retval = -1; + break; } - - if (cn.has_query_node()) { - query_node(cn.query_node(), response); - - // If we found the node we needed and it is unique, then this - // is the expected response. Just change the error code to exists - // as expected by an add_node return instead of Success as done - // in usual query_node. If we were supposed to cache - // the result, it should be done already. - if (response->r_type() == protobufs::NodeID && - response->error_code() == PMGDCmdResponse::Success) { - response->set_error_code(PMGDCmdResponse::Exists); - return 0; - } - - // The only situation where we would have to take further - // action is if the iterator was empty. And if there was some - // error like !unique, then we need to return the response as is. - if (response->error_code() != PMGDCmdResponse::Empty) - return -1; + case PMGDCmd::AddNode: + retval = add_node(cmd->add_node(), response); + break; + case PMGDCmd::AddEdge: + retval = add_edge(cmd->add_edge(), response); + break; + case PMGDCmd::QueryNode: + retval = query_node(cmd->query_node(), response, autodelete_init); + break; + case PMGDCmd::QueryEdge: + retval = query_edge(cmd->query_edge(), response); + break; + case PMGDCmd::UpdateNode: + update_node(cmd->update_node(), response); + break; + case PMGDCmd::UpdateEdge: + update_edge(cmd->update_edge(), response); + break; + case PMGDCmd::DeleteExpired: + retval = delete_expired_nodes(); + break; } + } catch (Exception e) { + set_response(response, PMGDCmdResponse::Exception, + e.name + std::string(": ") + e.msg); + retval = -1; + } - // Since the node wasn't found, now add it. - StringID sid(cn.node().tag().c_str()); - Node &n = _db->add_node(sid); - - if (id >= 0) - _cached_nodes[id] = new ReusableNodeIterator(&n); + return retval; +} - for (int i = 0; i < cn.node().properties_size(); ++i) { - const PMGDProp &p = cn.node().properties(i); - set_property(n, p); - if(cn.expiration_flag()) //Get the expiration time while iterating through the properties - { - if(p.key() == "_expiration") - { - expiration_time = (Json::UInt64) p.int_value(); - } - } +int PMGDQueryHandler::add_node(const protobufs::AddNode &cn, + PMGDCmdResponse *response) { + Json::UInt64 expiration_time; + long id = cn.identifier(); + if (id >= 0 && _cached_nodes.find(id) != _cached_nodes.end()) { + set_response(response, PMGDCmdResponse::Error, "Reuse of _ref value"); + return -1; + } + + if (cn.has_query_node()) { + query_node(cn.query_node(), response); + + // If we found the node we needed and it is unique, then this + // is the expected response. Just change the error code to exists + // as expected by an add_node return instead of Success as done + // in usual query_node. If we were supposed to cache + // the result, it should be done already. + if (response->r_type() == protobufs::NodeID && + response->error_code() == PMGDCmdResponse::Success) { + response->set_error_code(PMGDCmdResponse::Exists); + return 0; } - //add to deletion priority queue - if(cn.expiration_flag()) + // The only situation where we would have to take further + // action is if the iterator was empty. And if there was some + // error like !unique, then we need to return the response as is. + if (response->error_code() != PMGDCmdResponse::Empty) + return -1; + } + + // Since the node wasn't found, now add it. + StringID sid(cn.node().tag().c_str()); + Node &n = _db->add_node(sid); + + if (id >= 0) + _cached_nodes[id] = new ReusableNodeIterator(&n); + + for (int i = 0; i < cn.node().properties_size(); ++i) { + const PMGDProp &p = cn.node().properties(i); + set_property(n, p); + if (cn.expiration_flag()) // Get the expiration time while iterating through + // the properties { - AutoDeleteNode* tmpDeleteNode = new AutoDeleteNode(expiration_time, &n); - insert_into_queue(&_expiration_timestamp_queue, tmpDeleteNode); + if (p.key() == "_expiration") { + expiration_time = (Json::UInt64)p.int_value(); + } } + } - set_response(response, protobufs::NodeID, PMGDCmdResponse::Success); - - // TODO: Partition code goes here - // For now, fill in the single system node id - response->set_op_int_value(_db->get_id(n)); - return 0; -} - -int PMGDQueryHandler::update_node(const protobufs::UpdateNode &un, - protobufs::CommandResponse *response) -{ - long id = un.identifier(); - bool query = un.has_query_node(); + // add to deletion priority queue + if (cn.expiration_flag()) { + AutoDeleteNode *tmpDeleteNode = new AutoDeleteNode(expiration_time, &n); + insert_into_queue(&_expiration_timestamp_queue, tmpDeleteNode); + } - auto it = _cached_nodes.end(); - - // If both _ref and query are defined, _ref will have priority. - if (id >= 0) - it = _cached_nodes.find(id); - - if (it == _cached_nodes.end()) { - if (!query) { - set_response(response, PMGDCmdResponse::Error, "Undefined _ref value used in update"); - return -1; - } - else { - query_node(un.query_node(), response); - if (response->error_code() != PMGDCmdResponse::Success) - return -1; - long qn_id = un.query_node().identifier(); - if (qn_id >= 0) - it = _cached_nodes.find(qn_id); - else { - set_response(response, PMGDCmdResponse::Error, "Undefined _ref value used in update"); - return -1; - } - } - } + set_response(response, protobufs::NodeID, PMGDCmdResponse::Success); - auto nit = it->second; - long updated = 0; - for ( ; *nit; nit->next()) { - Node &n = **nit; - updated++; - for (int i = 0; i < un.properties_size(); ++i) { - const protobufs::Property &p = un.properties(i); - set_property(n, p); - } - for (int i = 0; i < un.remove_props_size(); ++i) - n.remove_property(un.remove_props(i).c_str()); - } - nit->reset(); - set_response(response, protobufs::Count, PMGDCmdResponse::Success); - response->set_op_int_value(updated); - return 0; + // TODO: Partition code goes here + // For now, fill in the single system node id + response->set_op_int_value(_db->get_id(n)); + return 0; } -int PMGDQueryHandler::add_edge(const protobufs::AddEdge &ce, - PMGDCmdResponse *response) -{ - response->set_node_edge(false); - long id = ce.identifier(); - if (id >= 0 && _cached_edges.find(id) != _cached_edges.end()) { - set_response(response, PMGDCmdResponse::Error, "Reuse of _ref value"); +int PMGDQueryHandler::update_node(const protobufs::UpdateNode &un, + protobufs::CommandResponse *response) { + long id = un.identifier(); + bool query = un.has_query_node(); + + auto it = _cached_nodes.end(); + + // If both _ref and query are defined, _ref will have priority. + if (id >= 0) + it = _cached_nodes.find(id); + + if (it == _cached_nodes.end()) { + if (!query) { + set_response(response, PMGDCmdResponse::Error, + "Undefined _ref value used in update"); + return -1; + } else { + query_node(un.query_node(), response); + if (response->error_code() != PMGDCmdResponse::Success) return -1; - } - - // Presumably this node gets placed here. - StringID sid(ce.edge().tag().c_str()); - - // Assumes there could be multiple. - ReusableNodeIterator *srcni, *dstni; - - // Since _ref is optional, need to make sure the map has the - // right reference. - auto srcit = _cached_nodes.find(ce.edge().src()); - auto dstit = _cached_nodes.find(ce.edge().dst()); - if (srcit != _cached_nodes.end() && dstit != _cached_nodes.end()) { - srcni = srcit->second; - dstni = dstit->second; - } - else { + long qn_id = un.query_node().identifier(); + if (qn_id >= 0) + it = _cached_nodes.find(qn_id); + else { set_response(response, PMGDCmdResponse::Error, - "Source/destination node references not found"); + "Undefined _ref value used in update"); return -1; + } } - - if (srcni == NULL || dstni == NULL || !bool(*srcni) || !bool(*dstni)) { - set_response(response, PMGDCmdResponse::Empty, - "Empty node iterators for adding edge"); - return -1; + } + + auto nit = it->second; + long updated = 0; + for (; *nit; nit->next()) { + Node &n = **nit; + updated++; + for (int i = 0; i < un.properties_size(); ++i) { + const protobufs::Property &p = un.properties(i); + set_property(n, p); } + for (int i = 0; i < un.remove_props_size(); ++i) + n.remove_property(un.remove_props(i).c_str()); + } + nit->reset(); + set_response(response, protobufs::Count, PMGDCmdResponse::Success); + response->set_op_int_value(updated); + return 0; +} - ReusableEdgeIterator *rei = NULL; - if (id >= 0) - rei = new ReusableEdgeIterator(); - - long eid = 0; - // TODO: Partition code goes here - for ( ; *srcni; srcni->next()) { - Node &src = **srcni; - for ( ; *dstni; dstni->next()) { - Node &dst = **dstni; - Edge &e = _db->add_edge(src, dst, sid); - if (id >= 0) - rei->add(&e); - - for (int i = 0; i < ce.edge().properties_size(); ++i) { - const PMGDProp &p = ce.edge().properties(i); - set_property(e, p); - } - - eid = _db->get_id(e); - } - dstni->reset(); +int PMGDQueryHandler::add_edge(const protobufs::AddEdge &ce, + PMGDCmdResponse *response) { + response->set_node_edge(false); + long id = ce.identifier(); + if (id >= 0 && _cached_edges.find(id) != _cached_edges.end()) { + set_response(response, PMGDCmdResponse::Error, "Reuse of _ref value"); + return -1; + } + + // Presumably this node gets placed here. + StringID sid(ce.edge().tag().c_str()); + + // Assumes there could be multiple. + ReusableNodeIterator *srcni, *dstni; + + // Since _ref is optional, need to make sure the map has the + // right reference. + auto srcit = _cached_nodes.find(ce.edge().src()); + auto dstit = _cached_nodes.find(ce.edge().dst()); + if (srcit != _cached_nodes.end() && dstit != _cached_nodes.end()) { + srcni = srcit->second; + dstni = dstit->second; + } else { + set_response(response, PMGDCmdResponse::Error, + "Source/destination node references not found"); + return -1; + } + + if (srcni == NULL || dstni == NULL || !bool(*srcni) || !bool(*dstni)) { + set_response(response, PMGDCmdResponse::Empty, + "Empty node iterators for adding edge"); + return -1; + } + + ReusableEdgeIterator *rei = NULL; + if (id >= 0) + rei = new ReusableEdgeIterator(); + + long eid = 0; + // TODO: Partition code goes here + for (; *srcni; srcni->next()) { + Node &src = **srcni; + for (; *dstni; dstni->next()) { + Node &dst = **dstni; + Edge &e = _db->add_edge(src, dst, sid); + if (id >= 0) + rei->add(&e); + + for (int i = 0; i < ce.edge().properties_size(); ++i) { + const PMGDProp &p = ce.edge().properties(i); + set_property(e, p); + } + + eid = _db->get_id(e); } - srcni->reset(); + dstni->reset(); + } + srcni->reset(); - if (id >= 0) { - rei->reset(); // Since we add at tail. - _cached_edges[id] = rei; - } + if (id >= 0) { + rei->reset(); // Since we add at tail. + _cached_edges[id] = rei; + } - set_response(response, protobufs::EdgeID, PMGDCmdResponse::Success); + set_response(response, protobufs::EdgeID, PMGDCmdResponse::Success); - // ID of the last edge added - response->set_op_int_value(eid); - return 0; + // ID of the last edge added + response->set_op_int_value(eid); + return 0; } int PMGDQueryHandler::update_edge(const protobufs::UpdateEdge &ue, - PMGDCmdResponse *response) -{ - long id = ue.identifier(); - bool query = ue.has_query_edge(); - - auto it = _cached_edges.end(); - - if (id >= 0) - it = _cached_edges.find(id); - - if (it == _cached_edges.end()) { - if (!query) { - set_response(response, PMGDCmdResponse::Error, "Undefined _ref value used in update"); - return -1; - } - else { - query_edge(ue.query_edge(), response); - if (response->error_code() != PMGDCmdResponse::Success) - return -1; - long qe_id = ue.query_edge().identifier(); - if (qe_id >= 0) - it = _cached_edges.find(qe_id); - else { - set_response(response, PMGDCmdResponse::Error, "Undefined _ref value used in update"); - return -1; - } - } + PMGDCmdResponse *response) { + long id = ue.identifier(); + bool query = ue.has_query_edge(); + + auto it = _cached_edges.end(); + + if (id >= 0) + it = _cached_edges.find(id); + + if (it == _cached_edges.end()) { + if (!query) { + set_response(response, PMGDCmdResponse::Error, + "Undefined _ref value used in update"); + return -1; + } else { + query_edge(ue.query_edge(), response); + if (response->error_code() != PMGDCmdResponse::Success) + return -1; + long qe_id = ue.query_edge().identifier(); + if (qe_id >= 0) + it = _cached_edges.find(qe_id); + else { + set_response(response, PMGDCmdResponse::Error, + "Undefined _ref value used in update"); + return -1; + } } - - auto eit = it->second; - long updated = 0; - for ( ; *eit; eit->next()) { - Edge &e = **eit; - updated++; - for (int i = 0; i < ue.properties_size(); ++i) { - const protobufs::Property &p = ue.properties(i); - set_property(e, p); - } - for (int i = 0; i < ue.remove_props_size(); ++i) - // TODO: If many nodes/edges are being updated, - // it would be advantageous - // to get the StringIDs for the properties in advance instead of - // converting each property name to a StringID - // every time it is used. - e.remove_property(ue.remove_props(i).c_str()); + } + + auto eit = it->second; + long updated = 0; + for (; *eit; eit->next()) { + Edge &e = **eit; + updated++; + for (int i = 0; i < ue.properties_size(); ++i) { + const protobufs::Property &p = ue.properties(i); + set_property(e, p); } - eit->reset(); - set_response(response, protobufs::Count, PMGDCmdResponse::Success); - response->set_op_int_value(updated); - return 0; - + for (int i = 0; i < ue.remove_props_size(); ++i) + // TODO: If many nodes/edges are being updated, + // it would be advantageous + // to get the StringIDs for the properties in advance instead of + // converting each property name to a StringID + // every time it is used. + e.remove_property(ue.remove_props(i).c_str()); + } + eit->reset(); + set_response(response, protobufs::Count, PMGDCmdResponse::Success); + response->set_op_int_value(updated); + return 0; } template -void PMGDQueryHandler::set_property(Element &e, const PMGDProp &p) -{ - switch(p.type()) { - case PMGDProp::BooleanType: - e.set_property(p.key().c_str(), p.bool_value()); - break; - case PMGDProp::IntegerType: - e.set_property(p.key().c_str(), (long long)p.int_value()); - break; - case PMGDProp::StringType: - e.set_property(p.key().c_str(), p.string_value()); - break; - case PMGDProp::FloatType: - e.set_property(p.key().c_str(), p.float_value()); - break; - case PMGDProp::TimeType: - { - struct tm tm_e; - int hr, min; - unsigned long usec; - string_to_tm(p.time_value(), &tm_e, &usec, &hr, &min); - Time t_e(&tm_e, usec, hr, min); // time diff - e.set_property(p.key().c_str(), t_e); - break; - } - case PMGDProp::BlobType: - e.set_property(p.key().c_str(), p.blob_value()); - } +void PMGDQueryHandler::set_property(Element &e, const PMGDProp &p) { + switch (p.type()) { + case PMGDProp::BooleanType: + e.set_property(p.key().c_str(), p.bool_value()); + break; + case PMGDProp::IntegerType: + e.set_property(p.key().c_str(), (long long)p.int_value()); + break; + case PMGDProp::StringType: + e.set_property(p.key().c_str(), p.string_value()); + break; + case PMGDProp::FloatType: + e.set_property(p.key().c_str(), p.float_value()); + break; + case PMGDProp::TimeType: { + struct tm tm_e; + int hr, min; + unsigned long usec; + string_to_tm(p.time_value(), &tm_e, &usec, &hr, &min); + Time t_e(&tm_e, usec, hr, min); // time diff + e.set_property(p.key().c_str(), t_e); + break; + } + case PMGDProp::BlobType: + e.set_property(p.key().c_str(), p.blob_value()); + } } int PMGDQueryHandler::query_node(const protobufs::QueryNode &qn, - PMGDCmdResponse *response, bool autodelete_init) -{ - ReusableNodeIterator *start_ni = NULL; - PMGD::Direction dir; - StringID edge_tag; - const PMGDQueryConstraints &qc = qn.constraints(); - const PMGDQueryResultInfo &qr = qn.results(); - long id = qn.identifier(); - if (id >= 0 && _cached_nodes.find(id) != _cached_nodes.end()) { - set_response(response, PMGDCmdResponse::Error, - "Reuse of _ref value"); - return -1; - } - - bool has_link = qn.has_link(); - if (has_link) { // case where link is used. - const protobufs::LinkInfo &link = qn.link(); - - if (link.nb_unique()) { - // TODO Add support for unique neighbors across iterators - set_response(response, PMGDCmdResponse::Error, - "Non-repeated neighbors not supported"); - return -1; - } - - long start_id = link.start_identifier(); - auto start = _cached_nodes.find(start_id); - if (start == _cached_nodes.end()) { - set_response(response, PMGDCmdResponse::Error, - "Undefined _ref value used in link"); - return -1; - } - start_ni = start->second; - - dir = (PMGD::Direction)link.dir(); - edge_tag = (link.edgetag_oneof_case() == protobufs::LinkInfo::kETagid) - ? StringID(link.e_tagid()) - : StringID(link.e_tag().c_str()); + PMGDCmdResponse *response, + bool autodelete_init) { + ReusableNodeIterator *start_ni = NULL; + PMGD::Direction dir; + StringID edge_tag; + const PMGDQueryConstraints &qc = qn.constraints(); + const PMGDQueryResultInfo &qr = qn.results(); + long id = qn.identifier(); + if (id >= 0 && _cached_nodes.find(id) != _cached_nodes.end()) { + set_response(response, PMGDCmdResponse::Error, "Reuse of _ref value"); + return -1; + } + + bool has_link = qn.has_link(); + if (has_link) { // case where link is used. + const protobufs::LinkInfo &link = qn.link(); + + if (link.nb_unique()) { + // TODO Add support for unique neighbors across iterators + set_response(response, PMGDCmdResponse::Error, + "Non-repeated neighbors not supported"); + return -1; } - StringID search_node_tag = (qc.tag_oneof_case() == PMGDQueryConstraints::kTagid) - ? StringID(qc.tagid()) - : StringID(qc.tag().c_str()); - - SearchExpression search(*_db, search_node_tag, - qn.constraints().p_op() == protobufs::Or); - - for (int i = 0; i < qc.predicates_size(); ++i) { - const PMGDPropPred &p_pp = qc.predicates(i); - PropertyPredicate j_pp = construct_search_term(p_pp); - search.add_node_predicate(j_pp); - } - - if (has_link) { // Check for edges constraints - for (int i = 0; i < qn.link().predicates_size(); ++i) { - const PMGDPropPred &p_pp = qn.link().predicates(i); - PropertyPredicate j_pp = construct_search_term(p_pp); - search.add_edge_predicate(j_pp); - } - } - - PMGD::NodeIterator ni = has_link ? - PMGD::NodeIterator(new MultiNeighborIteratorImpl(start_ni, search, dir, edge_tag)) - : search.eval_nodes(); - if (!bool(ni) && id >= 0) { - set_response(response, PMGDCmdResponse::Empty, - "Null search iterator"); - if (has_link) - start_ni->reset(); - return -1; - } - - // Set these in case there is no results block. - set_response(response, qr.r_type(), PMGDCmdResponse::Success); - - // TODO: Also, this triggers a copy of the SearchExpression object - // via the SearchExpressionIterator class, which might be slow, - // especially with a lot of property constraints. Might need another - // way for it. - if (!(id >= 0 || qc.unique() || qr.sort())) { - // If not reusable - build_results(ni, qr, response); - - // Make sure the starting iterator is reset for later use. - if (has_link) - start_ni->reset(); - return 0; - } - - ReusableNodeIterator *tni = new ReusableNodeIterator(ni); - - if (qc.unique()) { - tni->next(); - if (bool(*tni)) { // Not unique and that is an error here. - set_response(response, PMGDCmdResponse::NotUnique, - "Query response not unique"); - if (has_link) - start_ni->reset(); - delete tni; - return -1; - } - tni->reset(); + long start_id = link.start_identifier(); + auto start = _cached_nodes.find(start_id); + if (start == _cached_nodes.end()) { + set_response(response, PMGDCmdResponse::Error, + "Undefined _ref value used in link"); + return -1; } - - if (qr.sort()) - tni->sort(qr.sort_key().c_str(), qr.descending()); - - if (qr.r_type() != protobufs::Cached) - build_results(*tni, qr, response); - - if (id >= 0) { - // We have to traverse the current iterator fully, so we can - // reset start_ni. - if (has_link) - tni->traverse_all(); - tni->reset(); - _cached_nodes[id] = tni; + start_ni = start->second; + + dir = (PMGD::Direction)link.dir(); + edge_tag = (link.edgetag_oneof_case() == protobufs::LinkInfo::kETagid) + ? StringID(link.e_tagid()) + : StringID(link.e_tag().c_str()); + } + + StringID search_node_tag = + (qc.tag_oneof_case() == PMGDQueryConstraints::kTagid) + ? StringID(qc.tagid()) + : StringID(qc.tag().c_str()); + + SearchExpression search(*_db, search_node_tag, + qn.constraints().p_op() == protobufs::Or); + + for (int i = 0; i < qc.predicates_size(); ++i) { + const PMGDPropPred &p_pp = qc.predicates(i); + PropertyPredicate j_pp = construct_search_term(p_pp); + search.add_node_predicate(j_pp); + } + + if (has_link) { // Check for edges constraints + for (int i = 0; i < qn.link().predicates_size(); ++i) { + const PMGDPropPred &p_pp = qn.link().predicates(i); + PropertyPredicate j_pp = construct_search_term(p_pp); + search.add_edge_predicate(j_pp); } - else - delete tni; - - // If there is a link, we have to make sure the start_ni can be reset. + } + + PMGD::NodeIterator ni = + has_link ? PMGD::NodeIterator(new MultiNeighborIteratorImpl( + start_ni, search, dir, edge_tag)) + : search.eval_nodes(); + if (!bool(ni) && id >= 0) { + set_response(response, PMGDCmdResponse::Empty, "Null search iterator"); if (has_link) - start_ni->reset(); - + start_ni->reset(); + return -1; + } + + // Set these in case there is no results block. + set_response(response, qr.r_type(), PMGDCmdResponse::Success); + + // TODO: Also, this triggers a copy of the SearchExpression object + // via the SearchExpressionIterator class, which might be slow, + // especially with a lot of property constraints. Might need another + // way for it. + if (!(id >= 0 || qc.unique() || qr.sort())) { + // If not reusable + build_results(ni, qr, response); + + // Make sure the starting iterator is reset for later use. + if (has_link) + start_ni->reset(); return 0; -} + } -int PMGDQueryHandler::query_edge(const protobufs::QueryEdge &qe, - PMGDCmdResponse *response) -{ - ReusableNodeIterator *start_ni = NULL; - PMGD::Direction dir; - const PMGDQueryConstraints &qc = qe.constraints(); - const PMGDQueryResultInfo &qr = qe.results(); - response->set_node_edge(false); - - if (qc.p_op() == protobufs::Or) { - set_response(response, PMGDCmdResponse::Error, - "Or operation not implemented"); - return -1; - } - - long id = qe.identifier(); - if (id >= 0 && _cached_edges.find(id) != _cached_edges.end()) { - set_response(response, PMGDCmdResponse::Error, - "Reuse of _ref value"); - return -1; - } - - // See if we need to match edges based on some starting or - // ending nodes. - long src_id = qe.src_node_id(); - ReusableNodeIterator *src_ni = NULL; - if (src_id >= 0) { - auto it = _cached_nodes.find(src_id); - if (it != _cached_nodes.end()) - src_ni = it->second; - } - long dest_id = qe.dest_node_id(); - ReusableNodeIterator *dest_ni = NULL; - if (dest_id >= 0) { - auto it = _cached_nodes.find(dest_id); - if (it != _cached_nodes.end()) - dest_ni = it->second; - } - - StringID search_edge_tag = (qc.tag_oneof_case() == PMGDQueryConstraints::kTagid) - ? StringID(qc.tagid()) - : StringID(qc.tag().c_str()); - - SearchExpression search(*_db, search_edge_tag, false); - - for (int i = 0; i < qc.predicates_size(); ++i) { - const PMGDPropPred &p_pp = qc.predicates(i); - PropertyPredicate j_pp = construct_search_term(p_pp); - search.add_node_predicate(j_pp); - } + ReusableNodeIterator *tni = new ReusableNodeIterator(ni); - EdgeIterator ei = PMGD::EdgeIterator(new NodeEdgeIteratorImpl(search, src_ni, dest_ni)); - if (!bool(ei) && id >= 0) { - set_response(response, PMGDCmdResponse::Empty, - "Null search iterator"); - // Make sure the src and dest Node iterators are resettled. - if (src_ni != NULL) src_ni->reset(); - if (dest_ni != NULL) dest_ni->reset(); - return -1; + if (qc.unique()) { + tni->next(); + if (bool(*tni)) { // Not unique and that is an error here. + set_response(response, PMGDCmdResponse::NotUnique, + "Query response not unique"); + if (has_link) + start_ni->reset(); + delete tni; + return -1; } + tni->reset(); + } - // Set these in case there is no results block. - set_response(response, qr.r_type(), PMGDCmdResponse::Success); - - if (!(id >= 0 || qc.unique() || qr.sort())) { - // If not reusable - build_results(ei, qr, response); + if (qr.sort()) + tni->sort(qr.sort_key().c_str(), qr.descending()); - // Make sure the src and dest Node iterators are resettled. - if (src_ni != NULL) src_ni->reset(); - if (dest_ni != NULL) dest_ni->reset(); + if (qr.r_type() != protobufs::Cached) + build_results(*tni, qr, response); - return 0; - } - - ReusableEdgeIterator *tei = new ReusableEdgeIterator(ei); - - if (qc.unique()) { - tei->next(); - if (bool(*tei)) { // Not unique and that is an error here. - set_response(response, PMGDCmdResponse::NotUnique, - "Query response not unique"); - delete tei; - if (src_ni != NULL) src_ni->reset(); - if (dest_ni != NULL) dest_ni->reset(); - return -1; - } - tei->reset(); - } + if (id >= 0) { + // We have to traverse the current iterator fully, so we can + // reset start_ni. + if (has_link) + tni->traverse_all(); + tni->reset(); + _cached_nodes[id] = tni; + } else + delete tni; - if (qr.sort()) - tei->sort(qr.sort_key().c_str(), qr.descending()); + // If there is a link, we have to make sure the start_ni can be reset. + if (has_link) + start_ni->reset(); - if (qr.r_type() != protobufs::Cached) - build_results(*tei, qr, response); + return 0; +} - if (id >= 0) { - tei->traverse_all(); - tei->reset(); - _cached_edges[id] = tei; - } - else - delete tei; +int PMGDQueryHandler::query_edge(const protobufs::QueryEdge &qe, + PMGDCmdResponse *response) { + ReusableNodeIterator *start_ni = NULL; + PMGD::Direction dir; + const PMGDQueryConstraints &qc = qe.constraints(); + const PMGDQueryResultInfo &qr = qe.results(); + response->set_node_edge(false); + + if (qc.p_op() == protobufs::Or) { + set_response(response, PMGDCmdResponse::Error, + "Or operation not implemented"); + return -1; + } + + long id = qe.identifier(); + if (id >= 0 && _cached_edges.find(id) != _cached_edges.end()) { + set_response(response, PMGDCmdResponse::Error, "Reuse of _ref value"); + return -1; + } + + // See if we need to match edges based on some starting or + // ending nodes. + long src_id = qe.src_node_id(); + ReusableNodeIterator *src_ni = NULL; + if (src_id >= 0) { + auto it = _cached_nodes.find(src_id); + if (it != _cached_nodes.end()) + src_ni = it->second; + } + long dest_id = qe.dest_node_id(); + ReusableNodeIterator *dest_ni = NULL; + if (dest_id >= 0) { + auto it = _cached_nodes.find(dest_id); + if (it != _cached_nodes.end()) + dest_ni = it->second; + } + + StringID search_edge_tag = + (qc.tag_oneof_case() == PMGDQueryConstraints::kTagid) + ? StringID(qc.tagid()) + : StringID(qc.tag().c_str()); + + SearchExpression search(*_db, search_edge_tag, false); + + for (int i = 0; i < qc.predicates_size(); ++i) { + const PMGDPropPred &p_pp = qc.predicates(i); + PropertyPredicate j_pp = construct_search_term(p_pp); + search.add_node_predicate(j_pp); + } + + EdgeIterator ei = + PMGD::EdgeIterator(new NodeEdgeIteratorImpl(search, src_ni, dest_ni)); + if (!bool(ei) && id >= 0) { + set_response(response, PMGDCmdResponse::Empty, "Null search iterator"); + // Make sure the src and dest Node iterators are resettled. + if (src_ni != NULL) + src_ni->reset(); + if (dest_ni != NULL) + dest_ni->reset(); + return -1; + } + + // Set these in case there is no results block. + set_response(response, qr.r_type(), PMGDCmdResponse::Success); + + if (!(id >= 0 || qc.unique() || qr.sort())) { + // If not reusable + build_results(ei, qr, response); + + // Make sure the src and dest Node iterators are resettled. + if (src_ni != NULL) + src_ni->reset(); + if (dest_ni != NULL) + dest_ni->reset(); - if (src_ni != NULL) src_ni->reset(); - if (dest_ni != NULL) dest_ni->reset(); return 0; + } + + ReusableEdgeIterator *tei = new ReusableEdgeIterator(ei); + + if (qc.unique()) { + tei->next(); + if (bool(*tei)) { // Not unique and that is an error here. + set_response(response, PMGDCmdResponse::NotUnique, + "Query response not unique"); + delete tei; + if (src_ni != NULL) + src_ni->reset(); + if (dest_ni != NULL) + dest_ni->reset(); + return -1; + } + tei->reset(); + } + + if (qr.sort()) + tei->sort(qr.sort_key().c_str(), qr.descending()); + + if (qr.r_type() != protobufs::Cached) + build_results(*tei, qr, response); + + if (id >= 0) { + tei->traverse_all(); + tei->reset(); + _cached_edges[id] = tei; + } else + delete tei; + + if (src_ni != NULL) + src_ni->reset(); + if (dest_ni != NULL) + dest_ni->reset(); + return 0; } -PropertyPredicate PMGDQueryHandler::construct_search_term(const PMGDPropPred &p_pp) -{ - StringID key = (p_pp.key_oneof_case() == 2) ? StringID(p_pp.keyid()) : StringID(p_pp.key().c_str()); - - // Assumes exact match between enum values - // TODO Maybe have some way of verifying certain such assumptions at start? - PropertyPredicate::Op op = (PropertyPredicate::Op)p_pp.op(); - if (op == PropertyPredicate::DontCare) - return PropertyPredicate(key); - if (op < PropertyPredicate::GeLe) - return PropertyPredicate(key, op, construct_search_property(p_pp.v1())); - return PropertyPredicate(key, op, construct_search_property(p_pp.v1()), - construct_search_property(p_pp.v2())); +PropertyPredicate +PMGDQueryHandler::construct_search_term(const PMGDPropPred &p_pp) { + StringID key = (p_pp.key_oneof_case() == 2) ? StringID(p_pp.keyid()) + : StringID(p_pp.key().c_str()); + + // Assumes exact match between enum values + // TODO Maybe have some way of verifying certain such assumptions at start? + PropertyPredicate::Op op = (PropertyPredicate::Op)p_pp.op(); + if (op == PropertyPredicate::DontCare) + return PropertyPredicate(key); + if (op < PropertyPredicate::GeLe) + return PropertyPredicate(key, op, construct_search_property(p_pp.v1())); + return PropertyPredicate(key, op, construct_search_property(p_pp.v1()), + construct_search_property(p_pp.v2())); } -Property PMGDQueryHandler::construct_search_property(const PMGDProp &p) -{ - switch(p.type()) { - case PMGDProp::BooleanType: - return Property(p.bool_value()); - case PMGDProp::IntegerType: - return Property((long long)p.int_value()); - case PMGDProp::StringType: - return Property(p.string_value()); - case PMGDProp::FloatType: - return Property(p.float_value()); - case PMGDProp::TimeType: - { - struct tm tm_e; - int hr, min; - unsigned long usec; - string_to_tm(p.time_value(), &tm_e, &usec, &hr, &min); - Time t_e(&tm_e, usec, hr, min); // time diff - return Property(t_e); - } - case PMGDProp::BlobType: - // We throw here to avoid extra work when going through - // multiple levels of calls. - throw PMGDException(PropertyTypeInvalid, "Search on blob property not permitted"); - } - return 0; +Property PMGDQueryHandler::construct_search_property(const PMGDProp &p) { + switch (p.type()) { + case PMGDProp::BooleanType: + return Property(p.bool_value()); + case PMGDProp::IntegerType: + return Property((long long)p.int_value()); + case PMGDProp::StringType: + return Property(p.string_value()); + case PMGDProp::FloatType: + return Property(p.float_value()); + case PMGDProp::TimeType: { + struct tm tm_e; + int hr, min; + unsigned long usec; + string_to_tm(p.time_value(), &tm_e, &usec, &hr, &min); + Time t_e(&tm_e, usec, hr, min); // time diff + return Property(t_e); + } + case PMGDProp::BlobType: + // We throw here to avoid extra work when going through + // multiple levels of calls. + throw PMGDException(PropertyTypeInvalid, + "Search on blob property not permitted"); + } + return 0; } namespace VDMS { - template - void PMGDQueryHandler::build_results(PMGD::NodeIterator &ni, - const protobufs::ResultInfo &qn, - PMGDCmdResponse *response); - template - void PMGDQueryHandler::build_results( - PMGDQueryHandler::ReusableNodeIterator &ni, - const protobufs::ResultInfo &qn, - PMGDCmdResponse *response); - template - void PMGDQueryHandler::build_results( - PMGD::EdgeIterator &ni, - const protobufs::ResultInfo &qn, - PMGDCmdResponse *response); -}; +template void PMGDQueryHandler::build_results( + PMGD::NodeIterator &ni, const protobufs::ResultInfo &qn, + PMGDCmdResponse *response); +template void +PMGDQueryHandler::build_results( + PMGDQueryHandler::ReusableNodeIterator &ni, const protobufs::ResultInfo &qn, + PMGDCmdResponse *response); +template void PMGDQueryHandler::build_results( + PMGD::EdgeIterator &ni, const protobufs::ResultInfo &qn, + PMGDCmdResponse *response); +}; // namespace VDMS template void PMGDQueryHandler::build_results(Iterator &ni, - const protobufs::ResultInfo &qn, - PMGDCmdResponse *response) -{ - bool avg = false; - size_t limit = qn.limit() > 0 ? qn.limit() : std::numeric_limits::max(); - size_t count = 0; - switch(qn.r_type()) { - case protobufs::List: - { - std::vector keyids; - for (int i = 0; i < qn.response_keys_size(); ++i) - keyids.push_back(StringID(qn.response_keys(i).c_str())); - - auto& rmap = *(response->mutable_prop_values()); - for (; ni; ni.next()) { - for (int i = 0; i < keyids.size(); ++i) { - Property j_p; - PMGDPropList &list = rmap[qn.response_keys(i)]; - PMGDProp *p_p = list.add_values(); - if (!ni->check_property(keyids[i], j_p)) { - construct_missing_property(p_p); - continue; - } - construct_protobuf_property(j_p, p_p); - } - if(_resultdeletion && !(ni->get_tag() ==VDMS_DESC_SET_TAG) ) // DescriptorSets should be ignored - they are returned with Descriptors - { - delete_by_value((&_expiration_timestamp_queue), (void*)(&(*ni))); - Property img_prop; - if(ni->check_property(VDMS_IM_PATH_PROP, img_prop)) //delete image if present - { - _cleanup_filename_list.push_back(img_prop.string_value()); - } - Property vid_prop; - if(ni->check_property(VDMS_VID_PATH_PROP, vid_prop)) //delete image if present - { - _cleanup_filename_list.push_back(vid_prop.string_value()); - } - Property blob_prop; - if( ni->check_property(VDMS_EN_BLOB_PATH_PROP, blob_prop)) //delete image if present - { - _cleanup_filename_list.push_back(blob_prop.string_value()); - } - _db->remove(*ni); - } - if(_autodelete_init) - { - uint64_t tmp_timestamp = (uint64_t) ni->get_property("_expiration").int_value(); - AutoDeleteNode* tmpNode = new AutoDeleteNode(Json::UInt64(tmp_timestamp), &(*ni)); - insert_into_queue(&_expiration_timestamp_queue, tmpNode); - } - count++; - if (count >= limit) - break; + const protobufs::ResultInfo &qn, + PMGDCmdResponse *response) { + bool avg = false; + size_t limit = + qn.limit() > 0 ? qn.limit() : std::numeric_limits::max(); + size_t count = 0; + switch (qn.r_type()) { + case protobufs::List: { + std::vector keyids; + for (int i = 0; i < qn.response_keys_size(); ++i) + keyids.push_back(StringID(qn.response_keys(i).c_str())); + + auto &rmap = *(response->mutable_prop_values()); + for (; ni; ni.next()) { + for (int i = 0; i < keyids.size(); ++i) { + Property j_p; + PMGDPropList &list = rmap[qn.response_keys(i)]; + PMGDProp *p_p = list.add_values(); + if (!ni->check_property(keyids[i], j_p)) { + construct_missing_property(p_p); + continue; } - response->set_op_int_value(count); - break; - } - case protobufs::Count: - { - for (; ni; ni.next()) - count++; - response->set_op_int_value(count); - break; - } - // Next two assume that the property requested is either Int or Float. - // Also, only looks at the first property specified. - case protobufs::Average: - avg = true; - case protobufs::Sum: - { - // Since the iterator can be null if no _ref is used, make sure - // it has elements before proceeding, else return. - if (!bool(ni)) { - if (avg) - response->set_op_float_value(0.0); - else - response->set_op_int_value(0); - break; - } - - // We currently only use the first property key even if multiple - // are provided. And we can assume that the syntax checker makes - // sure of getting one for sure. - StringID keyid(qn.response_keys(0).c_str()); - if (ni->get_property(keyid).type() == PropertyType::Integer) { - size_t sum = 0; - for (; ni; ni.next()) { - sum += ni->get_property(keyid).int_value(); - count++; - if (count >= limit) - break; - } - if (avg) - response->set_op_float_value((double)sum / count); - else - response->set_op_int_value(sum); + construct_protobuf_property(j_p, p_p); + } + if (_resultdeletion && + !(ni->get_tag() == + VDMS_DESC_SET_TAG)) // DescriptorSets should be ignored - they are + // returned with Descriptors + { + delete_by_value((&_expiration_timestamp_queue), (void *)(&(*ni))); + Property img_prop; + if (ni->check_property(VDMS_IM_PATH_PROP, + img_prop)) // delete image if present + { + _cleanup_filename_list.push_back(img_prop.string_value()); } - else if (ni->get_property(keyid).type() == PropertyType::Float) { - double sum = 0.0; - for (; ni; ni.next()) { - sum += ni->get_property(keyid).float_value(); - count++; - if (count >= limit) - break; - } - if (avg) - response->set_op_float_value(sum / count); - else - response->set_op_float_value(sum); + Property vid_prop; + if (ni->check_property(VDMS_VID_PATH_PROP, + vid_prop)) // delete image if present + { + _cleanup_filename_list.push_back(vid_prop.string_value()); } - else { - set_response(response, PMGDCmdResponse::Error, - "Wrong first property for sum/average"); + Property blob_prop; + if (ni->check_property(VDMS_EN_BLOB_PATH_PROP, + blob_prop)) // delete image if present + { + _cleanup_filename_list.push_back(blob_prop.string_value()); } + _db->remove(*ni); + } + if (_autodelete_init) { + uint64_t tmp_timestamp = + (uint64_t)ni->get_property("_expiration").int_value(); + AutoDeleteNode *tmpNode = + new AutoDeleteNode(Json::UInt64(tmp_timestamp), &(*ni)); + insert_into_queue(&_expiration_timestamp_queue, tmpNode); + } + count++; + if (count >= limit) break; } - case protobufs::NodeID: - { - // Makes sense only when unique was used. Otherwise it sets the - // int value to the global id of the last node in the iterator. - for (; ni; ni.next()) - response->set_op_int_value(ni->get_id()); - break; - } - default: - set_response(response, PMGDCmdResponse::Error, - "Unknown operation type for query"); + response->set_op_int_value(count); + break; + } + case protobufs::Count: { + for (; ni; ni.next()) + count++; + response->set_op_int_value(count); + break; + } + // Next two assume that the property requested is either Int or Float. + // Also, only looks at the first property specified. + case protobufs::Average: + avg = true; + case protobufs::Sum: { + // Since the iterator can be null if no _ref is used, make sure + // it has elements before proceeding, else return. + if (!bool(ni)) { + if (avg) + response->set_op_float_value(0.0); + else + response->set_op_int_value(0); + break; } -} -void PMGDQueryHandler::construct_protobuf_property(const Property &j_p, PMGDProp *p_p) -{ - // Assumes matching enum values! - p_p->set_type((PMGDProp::PropertyType)j_p.type()); - switch(j_p.type()) { - case PropertyType::Boolean: - p_p->set_bool_value(j_p.bool_value()); - break; - case PropertyType::Integer: - p_p->set_int_value(j_p.int_value()); - break; - case PropertyType::String: - p_p->set_string_value(j_p.string_value()); - break; - case PropertyType::Float: - p_p->set_float_value(j_p.float_value()); - break; - case PropertyType::Time: - p_p->set_time_value(time_to_string(j_p.time_value())); - break; - case PropertyType::Blob: - p_p->set_blob_value(j_p.blob_value().value, j_p.blob_value().size); + // We currently only use the first property key even if multiple + // are provided. And we can assume that the syntax checker makes + // sure of getting one for sure. + StringID keyid(qn.response_keys(0).c_str()); + if (ni->get_property(keyid).type() == PropertyType::Integer) { + size_t sum = 0; + for (; ni; ni.next()) { + sum += ni->get_property(keyid).int_value(); + count++; + if (count >= limit) + break; + } + if (avg) + response->set_op_float_value((double)sum / count); + else + response->set_op_int_value(sum); + } else if (ni->get_property(keyid).type() == PropertyType::Float) { + double sum = 0.0; + for (; ni; ni.next()) { + sum += ni->get_property(keyid).float_value(); + count++; + if (count >= limit) + break; + } + if (avg) + response->set_op_float_value(sum / count); + else + response->set_op_float_value(sum); + } else { + set_response(response, PMGDCmdResponse::Error, + "Wrong first property for sum/average"); } + break; + } + case protobufs::NodeID: { + // Makes sense only when unique was used. Otherwise it sets the + // int value to the global id of the last node in the iterator. + for (; ni; ni.next()) + response->set_op_int_value(ni->get_id()); + break; + } + default: + set_response(response, PMGDCmdResponse::Error, + "Unknown operation type for query"); + } } -void PMGDQueryHandler::construct_missing_property(PMGDProp *p_p) -{ - // Assumes matching enum values! - p_p->set_type(PMGDProp::StringType); - p_p->set_string_value("Missing property"); +void PMGDQueryHandler::construct_protobuf_property(const Property &j_p, + PMGDProp *p_p) { + // Assumes matching enum values! + p_p->set_type((PMGDProp::PropertyType)j_p.type()); + switch (j_p.type()) { + case PropertyType::Boolean: + p_p->set_bool_value(j_p.bool_value()); + break; + case PropertyType::Integer: + p_p->set_int_value(j_p.int_value()); + break; + case PropertyType::String: + p_p->set_string_value(j_p.string_value()); + break; + case PropertyType::Float: + p_p->set_float_value(j_p.float_value()); + break; + case PropertyType::Time: + p_p->set_time_value(time_to_string(j_p.time_value())); + break; + case PropertyType::Blob: + p_p->set_blob_value(j_p.blob_value().value, j_p.blob_value().size); + } } -int PMGDQueryHandler::delete_expired_nodes() -{ - AutoDeleteNode* tmp_node; - Json::UInt64 current_timestamp = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); - Json::UInt64 this_timestamp = 0; - - //Continue to loop until queue is empty or we find timestamp greater than current time - while(this_timestamp < current_timestamp && !_expiration_timestamp_queue.empty()) - { - tmp_node = _expiration_timestamp_queue.front(); - this_timestamp = tmp_node->GetExpirationTimestamp(); - if(this_timestamp < current_timestamp) - { - Property img_prop; - PMGD::Node* tmp_node_node = (PMGD::Node*) tmp_node->GetNode(); - if( tmp_node_node->check_property(VDMS_IM_PATH_PROP, img_prop)) //delete image if present - { - remove(img_prop.string_value().c_str()); - } - Property vid_prop; - if( tmp_node_node->check_property(VDMS_VID_PATH_PROP, vid_prop)) //delete image if present - { - remove(vid_prop.string_value().c_str()); - } - Property blob_prop; - if( tmp_node_node->check_property(VDMS_EN_BLOB_PATH_PROP, blob_prop)) //delete image if present - { - remove(blob_prop.string_value().c_str()); - } - - - _db->remove(*((PMGD::Node*)(tmp_node->GetNode()))); //can assume Node since expiration only implemented for nodes - _expiration_timestamp_queue.pop_front(); - if(!_expiration_timestamp_queue.empty()) - { - tmp_node = _expiration_timestamp_queue.front(); - this_timestamp = tmp_node->GetExpirationTimestamp(); - } - } - } - return 0; +void PMGDQueryHandler::construct_missing_property(PMGDProp *p_p) { + // Assumes matching enum values! + p_p->set_type(PMGDProp::StringType); + p_p->set_string_value("Missing property"); } -void PMGDQueryHandler::cleanup_files() -{ - cleanup_pmgd_files(&_cleanup_filename_list); +int PMGDQueryHandler::delete_expired_nodes() { + AutoDeleteNode *tmp_node; + Json::UInt64 current_timestamp = + std::chrono::time_point_cast( + std::chrono::system_clock::now()) + .time_since_epoch() + .count(); + Json::UInt64 this_timestamp = 0; + + // Continue to loop until queue is empty or we find timestamp greater than + // current time + while (this_timestamp < current_timestamp && + !_expiration_timestamp_queue.empty()) { + tmp_node = _expiration_timestamp_queue.front(); + this_timestamp = tmp_node->GetExpirationTimestamp(); + if (this_timestamp < current_timestamp) { + Property img_prop; + PMGD::Node *tmp_node_node = (PMGD::Node *)tmp_node->GetNode(); + if (tmp_node_node->check_property(VDMS_IM_PATH_PROP, + img_prop)) // delete image if present + { + remove(img_prop.string_value().c_str()); + } + Property vid_prop; + if (tmp_node_node->check_property(VDMS_VID_PATH_PROP, + vid_prop)) // delete image if present + { + remove(vid_prop.string_value().c_str()); + } + Property blob_prop; + if (tmp_node_node->check_property(VDMS_EN_BLOB_PATH_PROP, + blob_prop)) // delete image if present + { + remove(blob_prop.string_value().c_str()); + } + + _db->remove(*( + (PMGD::Node *)(tmp_node + ->GetNode()))); // can assume Node since expiration + // only implemented for nodes + _expiration_timestamp_queue.pop_front(); + if (!_expiration_timestamp_queue.empty()) { + tmp_node = _expiration_timestamp_queue.front(); + this_timestamp = tmp_node->GetExpirationTimestamp(); + } + } + } + return 0; } -void insert_into_queue(std::list* queue, AutoDeleteNode* new_element) -{ - bool insert_flag; - long new_timestamp = new_element->GetExpirationTimestamp(); - - if(queue->empty()) - { - queue->push_front(new_element); - } - else - { - //We assume new entries will have a higher timestamp so start at back of queue and move forward - std::list::iterator it = queue->end(); - it--; - std::list::iterator begin = queue->begin(); - insert_flag = false; +void PMGDQueryHandler::cleanup_files() { + cleanup_pmgd_files(&_cleanup_filename_list); +} - if(new_timestamp >= queue->back()->GetExpirationTimestamp()) - { - queue->push_back(new_element); +void insert_into_queue(std::list *queue, + AutoDeleteNode *new_element) { + bool insert_flag; + long new_timestamp = new_element->GetExpirationTimestamp(); + + if (queue->empty()) { + queue->push_front(new_element); + } else { + // We assume new entries will have a higher timestamp so start at back of + // queue and move forward + std::list::iterator it = queue->end(); + it--; + std::list::iterator begin = queue->begin(); + insert_flag = false; + + if (new_timestamp >= queue->back()->GetExpirationTimestamp()) { + queue->push_back(new_element); + } else { + while (it != begin && insert_flag == false) { + if ((*it)->GetExpirationTimestamp() < new_timestamp) { + queue->insert(std::next(it), new_element); + insert_flag = true; } - else - { - while(it != begin && insert_flag == false) - { - if( (*it)->GetExpirationTimestamp() < new_timestamp) - { - queue->insert(std::next(it), new_element); - insert_flag = true; - } - it--; - } - if(insert_flag == false) - { - if(new_timestamp < (*begin)->GetExpirationTimestamp()) - { - queue->push_front(new_element); - } - else - { - it = begin; - it++; - queue->insert(it, new_element); - } - - } + it--; + } + if (insert_flag == false) { + if (new_timestamp < (*begin)->GetExpirationTimestamp()) { + queue->push_front(new_element); + } else { + it = begin; + it++; + queue->insert(it, new_element); } + } } + } } -void delete_by_value(std::list* queue, void* p_delete_node) -{ - bool delete_flag; - std::list::iterator it = queue->begin(); - std::list::iterator end = queue->end(); - delete_flag = false; - - while(it != end && delete_flag == false) - { - if(((*it)->GetNode()) == (p_delete_node)) - { - queue->erase(it); - delete_flag = true; - } - it++; +void delete_by_value(std::list *queue, void *p_delete_node) { + bool delete_flag; + std::list::iterator it = queue->begin(); + std::list::iterator end = queue->end(); + delete_flag = false; + + while (it != end && delete_flag == false) { + if (((*it)->GetNode()) == (p_delete_node)) { + queue->erase(it); + delete_flag = true; } + it++; + } } -void cleanup_pmgd_files(std::vector* p_cleanup_list) -{ - std::vector::iterator it = p_cleanup_list->begin(); - while(it != p_cleanup_list->end()) - { - remove((*it).c_str()); - it++; - } +void cleanup_pmgd_files(std::vector *p_cleanup_list) { + std::vector::iterator it = p_cleanup_list->begin(); + while (it != p_cleanup_list->end()) { + remove((*it).c_str()); + it++; + } } diff --git a/src/PMGDQueryHandler.h b/src/PMGDQueryHandler.h index 233eb399..f4ae6d4c 100644 --- a/src/PMGDQueryHandler.h +++ b/src/PMGDQueryHandler.h @@ -31,132 +31,144 @@ #pragma once +#include #include +#include #include #include -#include -#include -#include "pmgdMessages.pb.h" // Protobuff implementation -#include "pmgd.h" #include "AutoDeleteNode.h" +#include "pmgd.h" +#include "pmgdMessages.pb.h" // Protobuff implementation #define PMGD_QUERY_RETRY_LIMIT 10 namespace VDMS { - // Instance created per worker thread to handle all transactions on a given - // connection. - - typedef PMGD::protobufs::Command PMGDCmd; - typedef PMGD::protobufs::PropertyPredicate PMGDPropPred; - typedef PMGD::protobufs::PropertyList PMGDPropList; - typedef PMGD::protobufs::Property PMGDProp; - typedef PMGD::protobufs::Constraints PMGDQueryConstraints; - typedef PMGD::protobufs::ResultInfo PMGDQueryResultInfo; - typedef PMGD::protobufs::QueryNode PMGDQueryNode; - typedef PMGD::protobufs::QueryEdge PMGDQueryEdge; - typedef PMGD::protobufs::CommandResponse PMGDCmdResponse; - typedef PMGD::protobufs::ResponseType PMGDRespType; - typedef PMGDCmdResponse::ErrorCode PMGDCmdErrorCode; - - typedef std::vector PMGDCmds; - typedef std::vector PMGDCmdResponses; - - class PMGDQueryHandler - { - template - class ReusableIterator; - - typedef ReusableIterator ReusableNodeIterator; - typedef ReusableIterator ReusableEdgeIterator; - - class MultiNeighborIteratorImpl; - - // Until we have a separate PMGD server this db lives here - static PMGD::Graph *_db; - static std::list _expiration_timestamp_queue; - static std::vector _cleanup_filename_list; //files cannot be deleted until after blobs are added - - PMGD::Transaction *_tx; - bool _readonly; // Variable changes per TX based on process_queries parameter. - bool _resultdeletion; //Variable that indicates whether results of query should be - bool _autodelete_init; // Varibale that indicates whether we need to add nodes from query into deletion_queue - // deleted after result is complete - - // Map an integer ID to a NodeIterator (reset at the end of each transaction). - // This works for Adds and Queries. We assume that the client or - // the request server code will always add a ref to the AddNode - // call or a query call. That is what is the key in the map. - // Add calls typically don't result in a NodeIterator. But we make - // one to keep the code uniform. In a chained query, there is no way - // of finding out if the reference is for an AddNode or a QueryNode - // and rather than searching multiple maps, we keep it uniform here. - std::unordered_map _cached_nodes; - std::unordered_map _cached_edges; - - int process_query(const PMGDCmd *cmd, PMGDCmdResponse *response, bool autodelete_init = false); - void error_cleanup(std::vector &responses, PMGDCmdResponse *last_resp); - int add_node(const PMGD::protobufs::AddNode &cn, PMGDCmdResponse *response); - int update_node(const PMGD::protobufs::UpdateNode &un, PMGDCmdResponse *response); - int add_edge(const PMGD::protobufs::AddEdge &ce, PMGDCmdResponse *response); - int update_edge(const PMGD::protobufs::UpdateEdge &ue, PMGDCmdResponse *response); - template void set_property(Element &e, const PMGDProp&p); - int query_node(const PMGDQueryNode &qn, PMGDCmdResponse *response, bool autodelete_init = false); - int query_edge(const PMGDQueryEdge &qe, PMGDCmdResponse *response); - PMGD::PropertyPredicate construct_search_term(const PMGDPropPred &p_pp); - PMGD::Property construct_search_property(const PMGDProp&p); - template void build_results(Iterator &ni, - const PMGDQueryResultInfo &qn, - PMGDCmdResponse *response); - void construct_protobuf_property(const PMGD::Property &j_p, PMGDProp*p_p); - void construct_missing_property(PMGDProp *p_p); - - void set_response(PMGDCmdResponse *response, PMGDCmdErrorCode error_code, - std::string error_msg) - { - response->set_error_code(error_code); - response->set_error_msg(error_msg); - } - - void set_response(PMGDCmdResponse *response, PMGDRespType type, - PMGDCmdErrorCode error_code) - { - response->set_r_type(type); - response->set_error_code(error_code); - } - - void set_response(PMGDCmdResponse *response, PMGDRespType type, - PMGDCmdErrorCode error_code, std::string error_msg) - { - response->set_r_type(type); - response->set_error_code(error_code); - response->set_error_msg(error_msg); - } - - int delete_expired_nodes(); - public: - class NodeEdgeIteratorImpl; - static void init(); - static void destroy(); - PMGDQueryHandler() { _tx = NULL; _readonly = true; - _autodelete_init = false; _resultdeletion = false; } - - // The vector here can contain just one JL command but will be surrounded by - // TX begin and end. So just expose one call to the QueryHandler for - // the request server. - // The return vector contains an ordered list of query id with - // group of commands that correspond to that query. - // Pass the number of queries here since that could be different - // than the number of commands. - // Ensure that the cmd_grp_id, that is the query number are in increasing - // order and account for the TxBegin and TxEnd in numbering. - std::vector process_queries(const PMGDCmds &cmds, - int num_groups, bool readonly, bool resultdeletion=false, bool autodelete_init = false); - void cleanup_files(); - }; - -}; // end VDMS namespace - -void insert_into_queue(std::list* queue, AutoDeleteNode* new_element); -void delete_by_value(std::list* queue, void* p_delete_node); -void cleanup_pmgd_files(std::vector* p_cleanup_list); +// Instance created per worker thread to handle all transactions on a given +// connection. + +typedef PMGD::protobufs::Command PMGDCmd; +typedef PMGD::protobufs::PropertyPredicate PMGDPropPred; +typedef PMGD::protobufs::PropertyList PMGDPropList; +typedef PMGD::protobufs::Property PMGDProp; +typedef PMGD::protobufs::Constraints PMGDQueryConstraints; +typedef PMGD::protobufs::ResultInfo PMGDQueryResultInfo; +typedef PMGD::protobufs::QueryNode PMGDQueryNode; +typedef PMGD::protobufs::QueryEdge PMGDQueryEdge; +typedef PMGD::protobufs::CommandResponse PMGDCmdResponse; +typedef PMGD::protobufs::ResponseType PMGDRespType; +typedef PMGDCmdResponse::ErrorCode PMGDCmdErrorCode; + +typedef std::vector PMGDCmds; +typedef std::vector PMGDCmdResponses; + +class PMGDQueryHandler { + template class ReusableIterator; + + typedef ReusableIterator ReusableNodeIterator; + typedef ReusableIterator ReusableEdgeIterator; + + class MultiNeighborIteratorImpl; + + // Until we have a separate PMGD server this db lives here + static PMGD::Graph *_db; + static std::list _expiration_timestamp_queue; + static std::vector + _cleanup_filename_list; // files cannot be deleted until after blobs are + // added + + PMGD::Transaction *_tx; + bool _readonly; // Variable changes per TX based on process_queries parameter. + bool _resultdeletion; // Variable that indicates whether results of query + // should be + bool _autodelete_init; // Varibale that indicates whether we need to add nodes + // from query into deletion_queue + // deleted after result is complete + + // Map an integer ID to a NodeIterator (reset at the end of each transaction). + // This works for Adds and Queries. We assume that the client or + // the request server code will always add a ref to the AddNode + // call or a query call. That is what is the key in the map. + // Add calls typically don't result in a NodeIterator. But we make + // one to keep the code uniform. In a chained query, there is no way + // of finding out if the reference is for an AddNode or a QueryNode + // and rather than searching multiple maps, we keep it uniform here. + std::unordered_map _cached_nodes; + std::unordered_map _cached_edges; + + int process_query(const PMGDCmd *cmd, PMGDCmdResponse *response, + bool autodelete_init = false); + void error_cleanup(std::vector &responses, + PMGDCmdResponse *last_resp); + int add_node(const PMGD::protobufs::AddNode &cn, PMGDCmdResponse *response); + int update_node(const PMGD::protobufs::UpdateNode &un, + PMGDCmdResponse *response); + int add_edge(const PMGD::protobufs::AddEdge &ce, PMGDCmdResponse *response); + int update_edge(const PMGD::protobufs::UpdateEdge &ue, + PMGDCmdResponse *response); + template void set_property(Element &e, const PMGDProp &p); + int query_node(const PMGDQueryNode &qn, PMGDCmdResponse *response, + bool autodelete_init = false); + int query_edge(const PMGDQueryEdge &qe, PMGDCmdResponse *response); + PMGD::PropertyPredicate construct_search_term(const PMGDPropPred &p_pp); + PMGD::Property construct_search_property(const PMGDProp &p); + template + void build_results(Iterator &ni, const PMGDQueryResultInfo &qn, + PMGDCmdResponse *response); + void construct_protobuf_property(const PMGD::Property &j_p, PMGDProp *p_p); + void construct_missing_property(PMGDProp *p_p); + + void set_response(PMGDCmdResponse *response, PMGDCmdErrorCode error_code, + std::string error_msg) { + response->set_error_code(error_code); + response->set_error_msg(error_msg); + } + + void set_response(PMGDCmdResponse *response, PMGDRespType type, + PMGDCmdErrorCode error_code) { + response->set_r_type(type); + response->set_error_code(error_code); + } + + void set_response(PMGDCmdResponse *response, PMGDRespType type, + PMGDCmdErrorCode error_code, std::string error_msg) { + response->set_r_type(type); + response->set_error_code(error_code); + response->set_error_msg(error_msg); + } + + int delete_expired_nodes(); + +public: + class NodeEdgeIteratorImpl; + static void init(); + static void destroy(); + PMGDQueryHandler() { + _tx = NULL; + _readonly = true; + _autodelete_init = false; + _resultdeletion = false; + } + + // The vector here can contain just one JL command but will be surrounded by + // TX begin and end. So just expose one call to the QueryHandler for + // the request server. + // The return vector contains an ordered list of query id with + // group of commands that correspond to that query. + // Pass the number of queries here since that could be different + // than the number of commands. + // Ensure that the cmd_grp_id, that is the query number are in increasing + // order and account for the TxBegin and TxEnd in numbering. + std::vector process_queries(const PMGDCmds &cmds, + int num_groups, bool readonly, + bool resultdeletion = false, + bool autodelete_init = false); + void cleanup_files(); +}; + +}; // namespace VDMS + +void insert_into_queue(std::list *queue, + AutoDeleteNode *new_element); +void delete_by_value(std::list *queue, void *p_delete_node); +void cleanup_pmgd_files(std::vector *p_cleanup_list); diff --git a/src/QueryHandler.cc b/src/QueryHandler.cc index 229a2ab9..8a05bf91 100644 --- a/src/QueryHandler.cc +++ b/src/QueryHandler.cc @@ -29,16 +29,16 @@ * */ -#include -#include -#include #include "QueryHandler.h" +#include +#include +#include -#include "ImageCommand.h" -#include "DescriptorsCommand.h" +#include "BlobCommand.h" #include "BoundingBoxCommand.h" +#include "DescriptorsCommand.h" +#include "ImageCommand.h" #include "VideoCommand.h" -#include "BlobCommand.h" #include "ExceptionsCommand.h" @@ -50,496 +50,527 @@ #include "APISchema.h" #include #include -#include #include +#include using namespace VDMS; std::unordered_map QueryHandler::_rs_cmds; -valijson::Schema* QueryHandler::_schema = new valijson::Schema; - -void QueryHandler::init() -{ - DescriptorsManager::init(); - - _rs_cmds["AddEntity"] = new AddEntity(); - _rs_cmds["UpdateEntity"] = new UpdateEntity(); - _rs_cmds["FindEntity"] = new FindEntity(); - - _rs_cmds["AddConnection"] = new AddConnection(); - _rs_cmds["UpdateConnection"] = new UpdateConnection(); - _rs_cmds["FindConnection"] = new FindConnection(); - - _rs_cmds["AddImage"] = new AddImage(); - _rs_cmds["UpdateImage"] = new UpdateImage(); - _rs_cmds["FindImage"] = new FindImage(); - _rs_cmds["DeleteExpired"] = new DeleteExpired(); - - _rs_cmds["AddDescriptorSet"] = new AddDescriptorSet(); - _rs_cmds["AddDescriptor"] = new AddDescriptor(); - _rs_cmds["FindDescriptor"] = new FindDescriptor(); - _rs_cmds["ClassifyDescriptor"] = new ClassifyDescriptor(); - - _rs_cmds["AddBoundingBox"] = new AddBoundingBox(); - _rs_cmds["UpdateBoundingBox"] = new UpdateBoundingBox(); - _rs_cmds["FindBoundingBox"] = new FindBoundingBox(); - - _rs_cmds["AddVideo"] = new AddVideo(); - _rs_cmds["UpdateVideo"] = new UpdateVideo(); - _rs_cmds["FindVideo"] = new FindVideo(); - _rs_cmds["FindFrames"] = new FindFrames(); - - _rs_cmds["AddBlob"] = new AddBlob(); - _rs_cmds["UpdateBlob"] = new UpdateBlob(); - _rs_cmds["FindBlob"] = new FindBlob(); - - // Load the string containing the schema (api_schema/APISchema.h) - Json::Reader reader; - Json::Value api_schema; - bool parseSuccess = reader.parse(schema_json.c_str(), api_schema); - if (!parseSuccess) { - std::cerr << "Failed to parse API reference schema." << std::endl; - std::cerr << "PANIC! Aborting." << std::endl; - exit(0); - } - - // Parse the json schema into an internal schema format - valijson::SchemaParser parser; - valijson::adapters::JsonCppAdapter schemaDocumentAdapter(api_schema); - try { - parser.populateSchema(schemaDocumentAdapter, *_schema); - } - catch (std::exception &e) { - std::cerr << "Failed to load schema: " << e.what() << std::endl; - std::cerr << "PANIC! Aborting." << std::endl; - exit(0); - } +valijson::Schema *QueryHandler::_schema = new valijson::Schema; + +void QueryHandler::init() { + DescriptorsManager::init(); + + _rs_cmds["AddEntity"] = new AddEntity(); + _rs_cmds["UpdateEntity"] = new UpdateEntity(); + _rs_cmds["FindEntity"] = new FindEntity(); + + _rs_cmds["AddConnection"] = new AddConnection(); + _rs_cmds["UpdateConnection"] = new UpdateConnection(); + _rs_cmds["FindConnection"] = new FindConnection(); + + _rs_cmds["AddImage"] = new AddImage(); + _rs_cmds["UpdateImage"] = new UpdateImage(); + _rs_cmds["FindImage"] = new FindImage(); + _rs_cmds["DeleteExpired"] = new DeleteExpired(); + + _rs_cmds["AddDescriptorSet"] = new AddDescriptorSet(); + _rs_cmds["AddDescriptor"] = new AddDescriptor(); + _rs_cmds["FindDescriptor"] = new FindDescriptor(); + _rs_cmds["ClassifyDescriptor"] = new ClassifyDescriptor(); + + _rs_cmds["AddBoundingBox"] = new AddBoundingBox(); + _rs_cmds["UpdateBoundingBox"] = new UpdateBoundingBox(); + _rs_cmds["FindBoundingBox"] = new FindBoundingBox(); + + _rs_cmds["AddVideo"] = new AddVideo(); + _rs_cmds["UpdateVideo"] = new UpdateVideo(); + _rs_cmds["FindVideo"] = new FindVideo(); + _rs_cmds["FindFrames"] = new FindFrames(); + + _rs_cmds["AddBlob"] = new AddBlob(); + _rs_cmds["UpdateBlob"] = new UpdateBlob(); + _rs_cmds["FindBlob"] = new FindBlob(); + + // Load the string containing the schema (api_schema/APISchema.h) + Json::Reader reader; + Json::Value api_schema; + bool parseSuccess = reader.parse(schema_json.c_str(), api_schema); + if (!parseSuccess) { + std::cerr << "Failed to parse API reference schema." << std::endl; + std::cerr << "PANIC! Aborting." << std::endl; + exit(0); + } + + // Parse the json schema into an internal schema format + valijson::SchemaParser parser; + valijson::adapters::JsonCppAdapter schemaDocumentAdapter(api_schema); + try { + parser.populateSchema(schemaDocumentAdapter, *_schema); + } catch (std::exception &e) { + std::cerr << "Failed to load schema: " << e.what() << std::endl; + std::cerr << "PANIC! Aborting." << std::endl; + exit(0); + } } QueryHandler::QueryHandler() - : _pmgd_qh(), - _validator(valijson::Validator::kWeakTypes), - _autodelete_init(false), - _autoreplicate_init(false) + : _pmgd_qh(), _validator(valijson::Validator::kWeakTypes), + _autodelete_init(false), _autoreplicate_init(false) #ifdef CHRONO_TIMING - ,ch_tx_total("ch_tx_total") - ,ch_tx_query("ch_tx_query") - ,ch_tx_send("ch_tx_send") + , + ch_tx_total("ch_tx_total"), ch_tx_query("ch_tx_query"), + ch_tx_send("ch_tx_send") #endif { } -void QueryHandler::process_connection(comm::Connection *c) -{ - QueryMessage msgs(c); - - try { - while (true) { - protobufs::queryMessage response; - protobufs::queryMessage query = msgs.get_query(); - CHRONO_TIC(ch_tx_total); - - CHRONO_TIC(ch_tx_query); - process_query(query, response); - CHRONO_TAC(ch_tx_query); - - CHRONO_TIC(ch_tx_send); - msgs.send_response(response); - CHRONO_TAC(ch_tx_send); - - CHRONO_TAC(ch_tx_total); - CHRONO_PRINT_LAST_MS(ch_tx_total); - CHRONO_PRINT_LAST_MS(ch_tx_query); - CHRONO_PRINT_LAST_MS(ch_tx_send); - } - } catch (comm::ExceptionComm e) { - print_exception(e); +void QueryHandler::process_connection(comm::Connection *c) { + QueryMessage msgs(c); + + try { + while (true) { + protobufs::queryMessage response; + protobufs::queryMessage query = msgs.get_query(); + CHRONO_TIC(ch_tx_total); + + CHRONO_TIC(ch_tx_query); + process_query(query, response); + CHRONO_TAC(ch_tx_query); + + CHRONO_TIC(ch_tx_send); + msgs.send_response(response); + CHRONO_TAC(ch_tx_send); + + CHRONO_TAC(ch_tx_total); + CHRONO_PRINT_LAST_MS(ch_tx_total); + CHRONO_PRINT_LAST_MS(ch_tx_query); + CHRONO_PRINT_LAST_MS(ch_tx_send); } + } catch (comm::ExceptionComm e) { + print_exception(e); + } } -bool QueryHandler::syntax_checker(const Json::Value& root, Json::Value& error) -{ - valijson::ValidationResults results; - valijson::adapters::JsonCppAdapter user_query(root); - if (!_validator.validate(*_schema, user_query, &results)) { - std::cerr << "API validation failed for:" << std::endl; - std::cerr << root.toStyledString() << std::endl; - - // Will attempt to find the simple error - // To avoid valijson dump - for (int j = 0; j < root.size(); j++) { - const Json::Value& query = root[j]; - if (query.getMemberNames().size() != 1) { - error["info"] = "Error: Only one command per element allowed"; - return false; - } - - const std::string cmd_str = query.getMemberNames()[0]; - auto it = _rs_cmds.find(cmd_str); - if (it == _rs_cmds.end()) { - error["info"] = cmd_str + ": Command not found!"; - return false; - } - } +bool QueryHandler::syntax_checker(const Json::Value &root, Json::Value &error) { + valijson::ValidationResults results; + valijson::adapters::JsonCppAdapter user_query(root); + if (!_validator.validate(*_schema, user_query, &results)) { + std::cerr << "API validation failed for:" << std::endl; + std::cerr << root.toStyledString() << std::endl; + + // Will attempt to find the simple error + // To avoid valijson dump + for (int j = 0; j < root.size(); j++) { + const Json::Value &query = root[j]; + if (query.getMemberNames().size() != 1) { + error["info"] = "Error: Only one command per element allowed"; + return false; + } - valijson::ValidationResults::Error va_error; - unsigned int errorNum = 1; - std::stringstream str_error; - while (results.popError(va_error)) { - std::string context; - std::vector::iterator itr = va_error.context.begin(); - for (; itr != va_error.context.end(); itr++) { - context += *itr; - } - - str_error << "Error #" << errorNum << std::endl - << " context: " << context << std::endl - << " desc: " << va_error.description << std::endl; - ++errorNum; - } - std::cerr << str_error.str(); - error["info"] = str_error.str(); + const std::string cmd_str = query.getMemberNames()[0]; + auto it = _rs_cmds.find(cmd_str); + if (it == _rs_cmds.end()) { + error["info"] = cmd_str + ": Command not found!"; return false; + } } - for (auto& cmdTop : root) { - const std::string cmd_str = cmdTop.getMemberNames()[0]; - auto& cmd = cmdTop[cmd_str]; - if (cmd.isMember("constraints")) { - for (auto & member : cmd["constraints"].getMemberNames()) { - if (!cmd["constraints"][member].isArray()) { - error["info"] = "Constraint for property '" + member + - "' must be an array"; - return false; - } - auto size = cmd["constraints"][member].size(); - if (size != 2 && size != 4) { - error["info"] = "Constraint for property '" + member + - "' must be an array of size 2 or 4"; - return false; - } - } + valijson::ValidationResults::Error va_error; + unsigned int errorNum = 1; + std::stringstream str_error; + while (results.popError(va_error)) { + std::string context; + std::vector::iterator itr = va_error.context.begin(); + for (; itr != va_error.context.end(); itr++) { + context += *itr; + } + + str_error << "Error #" << errorNum << std::endl + << " context: " << context << std::endl + << " desc: " << va_error.description << std::endl; + ++errorNum; + } + std::cerr << str_error.str(); + error["info"] = str_error.str(); + return false; + } + + for (auto &cmdTop : root) { + const std::string cmd_str = cmdTop.getMemberNames()[0]; + auto &cmd = cmdTop[cmd_str]; + if (cmd.isMember("constraints")) { + for (auto &member : cmd["constraints"].getMemberNames()) { + if (!cmd["constraints"][member].isArray()) { + error["info"] = + "Constraint for property '" + member + "' must be an array"; + return false; } + auto size = cmd["constraints"][member].size(); + if (size != 2 && size != 4) { + error["info"] = "Constraint for property '" + member + + "' must be an array of size 2 or 4"; + return false; + } + } } + } - return true; + return true; } -int QueryHandler::parse_commands(const protobufs::queryMessage& proto_query, - Json::Value& root) -{ - Json::Reader reader; - const std::string commands = proto_query.json(); - - try { - bool parseSuccess = reader.parse(commands.c_str(), root); +int QueryHandler::parse_commands(const protobufs::queryMessage &proto_query, + Json::Value &root) { + Json::Reader reader; + const std::string commands = proto_query.json(); - if (!parseSuccess) { - root["info"] = "Error parsing the query, ill formed JSON"; - root["status"] = RSCommand::Error; - return -1; - } + try { + bool parseSuccess = reader.parse(commands.c_str(), root); - Json::Value error; - if (!syntax_checker(root, error)) { - root = error; - root["status"] = RSCommand::Error; - return -1; - } + if (!parseSuccess) { + root["info"] = "Error parsing the query, ill formed JSON"; + root["status"] = RSCommand::Error; + return -1; + } - unsigned blob_counter = 0; - for (int j = 0; j < root.size(); j++) { - const Json::Value& query = root[j]; - assert(query.getMemberNames().size() == 1); - std::string cmd = query.getMemberNames()[0]; + Json::Value error; + if (!syntax_checker(root, error)) { + root = error; + root["status"] = RSCommand::Error; + return -1; + } - if (_rs_cmds[cmd]->need_blob(query)) { - blob_counter++; - } - } + unsigned blob_counter = 0; + for (int j = 0; j < root.size(); j++) { + const Json::Value &query = root[j]; + assert(query.getMemberNames().size() == 1); + std::string cmd = query.getMemberNames()[0]; - if (blob_counter != proto_query.blobs().size()) { - root = error; - root["info"] = std::string("Expected blobs: " + - std::to_string(blob_counter) + - ". Received blobs: " + - std::to_string(proto_query.blobs().size())); - root["status"] = RSCommand::Error; - std::cerr << "Not enough blobs!" << std::endl; - return -1; - } + if (_rs_cmds[cmd]->need_blob(query)) { + blob_counter++; + } + } - } catch (Json::Exception const&) { - root["info"] = "Json Exception at Parsing"; - root["status"] = RSCommand::Error; - return -1; + if (blob_counter != proto_query.blobs().size()) { + root = error; + root["info"] = std::string( + "Expected blobs: " + std::to_string(blob_counter) + + ". Received blobs: " + std::to_string(proto_query.blobs().size())); + root["status"] = RSCommand::Error; + std::cerr << "Not enough blobs!" << std::endl; + return -1; } - return 0; + } catch (Json::Exception const &) { + root["info"] = "Json Exception at Parsing"; + root["status"] = RSCommand::Error; + return -1; + } + + return 0; } // TODO create a better mechanism to cleanup queries that // includes feature vectors and user-defined blobs // For now, we do it for videos/images as a starting point. -void QueryHandler::cleanup_query(const std::vector& images, - const std::vector& videos) -{ - for (auto& img_path : images) { - VCL::Image img(img_path); - img.delete_image(); - } - - for (auto& vid_path : videos) { - VCL::Video vid(vid_path); - vid.delete_video(); - } +void QueryHandler::cleanup_query(const std::vector &images, + const std::vector &videos) { + for (auto &img_path : images) { + VCL::Image img(img_path); + img.delete_image(); + } + + for (auto &vid_path : videos) { + VCL::Video vid(vid_path); + vid.delete_video(); + } } -void QueryHandler::process_query(protobufs::queryMessage& proto_query, - protobufs::queryMessage& proto_res) -{ - Json::FastWriter fastWriter; - - Json::Value root; - Json::Value exception_error; - std::stringstream error_msg; - auto exception_handler = [&]() { - // When exception is catched, we return the message. - std::cerr << "Failed Query: " << std::endl; - std::cerr << root << std::endl; - std::cerr << error_msg.str(); - std::cerr << "End Failed Query: " << std::endl; - exception_error["info"] = error_msg.str(); - exception_error["status"] = RSCommand::Error; - Json::Value response; - response.append(exception_error); - proto_res.set_json(fastWriter.write(response)); +void QueryHandler::process_query(protobufs::queryMessage &proto_query, + protobufs::queryMessage &proto_res) { + Json::FastWriter fastWriter; + + Json::Value root; + Json::Value exception_error; + std::stringstream error_msg; + auto exception_handler = [&]() { + // When exception is catched, we return the message. + std::cerr << "Failed Query: " << std::endl; + std::cerr << root << std::endl; + std::cerr << error_msg.str(); + std::cerr << "End Failed Query: " << std::endl; + exception_error["info"] = error_msg.str(); + exception_error["status"] = RSCommand::Error; + Json::Value response; + response.append(exception_error); + proto_res.set_json(fastWriter.write(response)); + }; + + try { + Json::Value json_responses; + + Json::Value cmd_result; + Json::Value cmd_current; + std::vector images_log; + std::vector videos_log; + std::vector construct_results; + + auto error = [&](Json::Value &res, Json::Value &failed_command) { + cleanup_query(images_log, videos_log); + res["FailedCommand"] = failed_command; + json_responses.clear(); + json_responses.append(res); + proto_res.clear_blobs(); + proto_res.set_json(fastWriter.write(json_responses)); + Json::StyledWriter w; + std::cerr << w.write(json_responses); }; - try { - Json::Value json_responses; - - Json::Value cmd_result; - Json::Value cmd_current; - std::vector images_log; - std::vector videos_log; - std::vector construct_results; - - auto error = [&](Json::Value& res, Json::Value& failed_command) - { - cleanup_query(images_log, videos_log); - res["FailedCommand"] = failed_command; - json_responses.clear(); - json_responses.append(res); - proto_res.clear_blobs(); - proto_res.set_json(fastWriter.write(json_responses)); - Json::StyledWriter w; - std::cerr << w.write(json_responses); - }; - - if (parse_commands(proto_query, root) != 0) { - cmd_current = "Transaction"; - error(root, cmd_current); - return; - } - - PMGDQuery pmgd_query(_pmgd_qh); - int blob_count = 0; - - //iterate over the list of the queries - for (int j = 0; j < root.size(); j++) { - const Json::Value& query = root[j]; - std::string cmd = query.getMemberNames()[0]; - - int group_count = pmgd_query.add_group(); - - RSCommand* rscmd = _rs_cmds[cmd]; + if (parse_commands(proto_query, root) != 0) { + cmd_current = "Transaction"; + error(root, cmd_current); + return; + } - const std::string& blob = rscmd->need_blob(query) ? - proto_query.blobs(blob_count++) : ""; + PMGDQuery pmgd_query(_pmgd_qh); + int blob_count = 0; - int ret_code = rscmd->construct_protobuf(pmgd_query, query, blob, - group_count, cmd_result); + // iterate over the list of the queries + for (int j = 0; j < root.size(); j++) { + const Json::Value &query = root[j]; + std::string cmd = query.getMemberNames()[0]; - if (cmd_result.isMember("image_added")) { - images_log.push_back(cmd_result["image_added"].asString()); - } - if (cmd_result.isMember("video_added")) { - videos_log.push_back(cmd_result["video_added"].asString()); - } + int group_count = pmgd_query.add_group(); - if (ret_code != 0) { - error(cmd_result, root[j]); - return; - } + RSCommand *rscmd = _rs_cmds[cmd]; - construct_results.push_back(cmd_result); - } + const std::string &blob = + rscmd->need_blob(query) ? proto_query.blobs(blob_count++) : ""; - Json::Value& tx_responses = pmgd_query.run(_autodelete_init); + int ret_code = rscmd->construct_protobuf(pmgd_query, query, blob, + group_count, cmd_result); - if (!tx_responses.isArray() || tx_responses.size() != root.size()) { - Json::StyledWriter writer; - std::cerr << "PMGD Response:" << std::endl; - std::cerr << writer.write(tx_responses) << std::endl; + if (cmd_result.isMember("image_added")) { + images_log.push_back(cmd_result["image_added"].asString()); + } + if (cmd_result.isMember("video_added")) { + videos_log.push_back(cmd_result["video_added"].asString()); + } - std::string tx_error_msg("Failed PMGD Transaction"); - if (!tx_responses.isArray() && tx_responses.isMember("info")) { - tx_error_msg += ": " + tx_responses["info"].asString(); - } + if (ret_code != 0) { + error(cmd_result, root[j]); + return; + } - cmd_result["status"] = RSCommand::Error; - cmd_result["info"] = tx_error_msg; + construct_results.push_back(cmd_result); + } - cmd_current = "Transaction"; - error(cmd_result, cmd_current); + Json::Value &tx_responses = pmgd_query.run(_autodelete_init); + + if (!tx_responses.isArray() || tx_responses.size() != root.size()) { + Json::StyledWriter writer; + std::cerr << "PMGD Response:" << std::endl; + std::cerr << writer.write(tx_responses) << std::endl; + + std::string tx_error_msg("Failed PMGD Transaction"); + if (!tx_responses.isArray() && tx_responses.isMember("info")) { + tx_error_msg += ": " + tx_responses["info"].asString(); + } + + cmd_result["status"] = RSCommand::Error; + cmd_result["info"] = tx_error_msg; + + cmd_current = "Transaction"; + error(cmd_result, cmd_current); + return; + } else { + blob_count = 0; + for (int j = 0; j < root.size(); j++) { + Json::Value &query = root[j]; + std::string cmd = query.getMemberNames()[0]; + + RSCommand *rscmd = _rs_cmds[cmd]; + + const std::string &blob = + rscmd->need_blob(query) ? proto_query.blobs(blob_count++) : ""; + + query["cp_result"] = construct_results[j]; + cmd_result = + rscmd->construct_responses(tx_responses[j], query, proto_res, blob); + + // This is for error handling + if (cmd_result.isMember("status")) { + int status = cmd_result["status"].asInt(); + if (status != RSCommand::Success || status != RSCommand::Empty || + status != RSCommand::Exists) { + error(cmd_result, root[j]); return; + } } - else { - blob_count = 0; - for (int j = 0; j < root.size(); j++) { - Json::Value& query = root[j]; - std::string cmd = query.getMemberNames()[0]; - - RSCommand* rscmd = _rs_cmds[cmd]; - - const std::string& blob = rscmd->need_blob(query) ? - proto_query.blobs(blob_count++) : ""; - - query["cp_result"] = construct_results[j]; - cmd_result = rscmd->construct_responses( - tx_responses[j], - query, proto_res, blob); - - // This is for error handling - if (cmd_result.isMember("status")) { - int status = cmd_result["status"].asInt(); - if (status != RSCommand::Success || - status != RSCommand::Empty || - status != RSCommand::Exists) - { - error(cmd_result, root[j]); - return; - } - } - json_responses.append(cmd_result); - } - } - - proto_res.set_json(fastWriter.write(json_responses)); - _pmgd_qh.cleanup_files(); - - } catch (VCL::Exception& e) { - print_exception(e); - error_msg << "Internal Server Error: VCL Exception at QH" << std::endl; - exception_handler(); - } catch (PMGD::Exception& e) { - print_exception(e); - error_msg << "Internal Server Error: PMGD Exception at QH" - << std::endl; - exception_handler(); - } catch (ExceptionCommand& e) { - print_exception(e); - error_msg << "Internal Server Error: Command Exception at QH" - << std::endl; - exception_handler(); - } catch (Json::Exception const& e) { - // In case of error on the last fastWriter - error_msg << "Internal Server Error: Json Exception: " - << e.what() << std::endl; - exception_handler(); - } catch (google::protobuf::FatalException& e) { - // Need to be carefull with this, may lead to memory leak. - // Protoubuf is not exception safe. - error_msg << "Internal Server Error: Protobuf Exception: " - << e.what() << std::endl; - exception_handler(); - } catch (const std::invalid_argument& e) { - error_msg << "FATAL: Invalid argument: " << e.what() << std::endl; - exception_handler(); - } catch (const std::exception& e) { - error_msg << "std Exception: " << e.what() << std::endl; - exception_handler(); - } catch (...) { - error_msg << "Unknown Exception" << std::endl; - exception_handler(); + json_responses.append(cmd_result); + } } + proto_res.set_json(fastWriter.write(json_responses)); + _pmgd_qh.cleanup_files(); + + } catch (VCL::Exception &e) { + print_exception(e); + error_msg << "Internal Server Error: VCL Exception at QH" << std::endl; + exception_handler(); + } catch (PMGD::Exception &e) { + print_exception(e); + error_msg << "Internal Server Error: PMGD Exception at QH" << std::endl; + exception_handler(); + } catch (ExceptionCommand &e) { + print_exception(e); + error_msg << "Internal Server Error: Command Exception at QH" << std::endl; + exception_handler(); + } catch (Json::Exception const &e) { + // In case of error on the last fastWriter + error_msg << "Internal Server Error: Json Exception: " << e.what() + << std::endl; + exception_handler(); + } catch (google::protobuf::FatalException &e) { + // Need to be carefull with this, may lead to memory leak. + // Protoubuf is not exception safe. + error_msg << "Internal Server Error: Protobuf Exception: " << e.what() + << std::endl; + exception_handler(); + } catch (const std::invalid_argument &e) { + error_msg << "FATAL: Invalid argument: " << e.what() << std::endl; + exception_handler(); + } catch (const std::exception &e) { + error_msg << "std Exception: " << e.what() << std::endl; + exception_handler(); + } catch (...) { + error_msg << "Unknown Exception" << std::endl; + exception_handler(); + } } -void QueryHandler::reset_autoreplicate_init_flag() -{ - _autoreplicate_init = true; -} -void QueryHandler::set_autoreplicate_init_flag( ) -{ - _autoreplicate_init = false; -} -void QueryHandler::regualar_run_autoreplicate( std::string& backup_path, std::string& db_path, int& server_port) -{ - std::string command = "bsdtar cvfz "; - std::string name; - std::ostringstream oss; - Json::Value config_file; - std::ofstream file_id; - name.clear(); - auto t = std::time(nullptr); - auto tm = *std::localtime(&t); - oss< 0) { + config_file["autodelete_interval"] = + replicate_settings + .autodelete_interval; // expired data removed daily (86400 secs) + } + + if (replicate_settings.expiration_time > 0) { + config_file["expiration_time"] = replicate_settings.expiration_time; + } + + config_file["more-info"] = "github.com/IntelLabs/vdms"; + + if (!replicate_settings.replication_time.empty()) { + config_file["autoreplicate_time"] = replicate_settings.replication_time; + } + + if (!replicate_settings.autoreplication_unit.empty()) { + config_file["unit"] = replicate_settings.autoreplication_unit; + } + + if (replicate_settings.autoreplicate_interval > 0) { + config_file["autoreplicate_interval"] = + replicate_settings.autoreplicate_interval; + } + + if (replicate_settings.max_simultaneous_clients > 0) { + config_file["max_simultaneous_clients"] = + replicate_settings.max_simultaneous_clients; + } + + if (!replicate_settings.backup_flag.empty()) { + config_file["backup_flag"] = replicate_settings.backup_flag; + } + if (!replicate_settings.backup_flag.empty()) { + config_file["backup_path"] = replicate_settings.backup_path; + } + if (!replicate_settings.backup_flag.empty()) { + config_file["images_path"] = replicate_settings.images_path; + } + if (!replicate_settings.backup_flag.empty()) { + config_file["blobs_path"] = replicate_settings.blobs_path; + } + if (!replicate_settings.backup_flag.empty()) { + config_file["descriptor_path"] = replicate_settings.descriptor_path; + } + if (!replicate_settings.backup_flag.empty()) { + config_file["pmgd_num_allocators"] = replicate_settings.pmgd_num_allocators; + } + std::cout << config_file << std::endl; + // write the configuration file + std::string config_file_name = full_name + ".json"; + file_id.open(config_file_name.c_str(), std::ios::out); + file_id << config_file << std::endl; + file_id.close(); + + command = "bsdtar cvfz "; + oss.str(std::string()); + name.clear(); + config_file.clear(); } -void QueryHandler::reset_autodelete_init_flag() -{ - _autodelete_init = false; +void QueryHandler::reset_autoreplicate_init_flag() { + _autoreplicate_init = true; } - -void QueryHandler::set_autodelete_init_flag() -{ - _autodelete_init = true; +void QueryHandler::set_autoreplicate_init_flag() { + _autoreplicate_init = false; } - -void QueryHandler::regualar_run_autodelete() -{ - std::string* json_string = new std::string("[{\"DeleteExpired\": {\"results\": {\"list\": [\"_expiration\"]}}}]"); - protobufs::queryMessage response; - protobufs::queryMessage query; - query.set_json(json_string->c_str()); - process_query(query, response); - delete json_string; +void QueryHandler::reset_autodelete_init_flag() { _autodelete_init = false; } + +void QueryHandler::set_autodelete_init_flag() { _autodelete_init = true; } + +void QueryHandler::regualar_run_autodelete() { + std::string *json_string = new std::string( + "[{\"DeleteExpired\": {\"results\": {\"list\": [\"_expiration\"]}}}]"); + protobufs::queryMessage response; + protobufs::queryMessage query; + query.set_json(json_string->c_str()); + process_query(query, response); + delete json_string; } -void QueryHandler::build_autodelete_queue() -{ - std::string* json_string = new std::string("[{\"FindImage\": {\"results\": {\"list\": [\"_expiration\"]}, \"constraints\": {\"_expiration\": [\">\", 0]}}}, {\"FindVideo\": {\"results\": {\"list\": [\"_expiration\"]}, \"constraints\": {\"_expiration\": [\">\", 0]}}}], {\"FindFrames\": {\"results\": {\"list\": [\"_expiration\"]}, \"constraints\": {\"_expiration\": [\">\", 0]}}}], {\"FindDescriptor\": {\"results\": {\"list\": [\"_expiration\"]}, \"constraints\": {\"_expiration\": [\">\", 0]}}}], {\"FindEntity\": {\"results\": {\"list\": [\"_expiration\"]}, \"constraints\": {\"_expiration\": [\">\", 0]}}}"); - protobufs::queryMessage response; - protobufs::queryMessage query; - query.set_json(json_string->c_str()); - process_query(query, response); - delete json_string; -} \ No newline at end of file +void QueryHandler::build_autodelete_queue() { + std::string *json_string = new std::string( + "[{\"FindImage\": {\"results\": {\"list\": [\"_expiration\"]}, " + "\"constraints\": {\"_expiration\": [\">\", 0]}}}, {\"FindVideo\": " + "{\"results\": {\"list\": [\"_expiration\"]}, \"constraints\": " + "{\"_expiration\": [\">\", 0]}}}], {\"FindFrames\": {\"results\": " + "{\"list\": [\"_expiration\"]}, \"constraints\": {\"_expiration\": " + "[\">\", 0]}}}], {\"FindDescriptor\": {\"results\": {\"list\": " + "[\"_expiration\"]}, \"constraints\": {\"_expiration\": [\">\", 0]}}}], " + "{\"FindEntity\": {\"results\": {\"list\": [\"_expiration\"]}, " + "\"constraints\": {\"_expiration\": [\">\", 0]}}}"); + protobufs::queryMessage response; + protobufs::queryMessage query; + query.set_json(json_string->c_str()); + process_query(query, response); + delete json_string; +} diff --git a/src/QueryHandler.h b/src/QueryHandler.h index 08fcdbaa..c4ac440b 100644 --- a/src/QueryHandler.h +++ b/src/QueryHandler.h @@ -30,14 +30,14 @@ */ #pragma once -#include #include -#include +#include #include +#include #include "PMGDQueryHandler.h" // to provide the database connection #include "RSCommand.h" -#include "comm/Connection.h" +#include "Server.h" #include "chrono/Chrono.h" // Json parsing files @@ -49,50 +49,47 @@ namespace VDMS { typedef ::google::protobuf::RepeatedPtrField BlobArray; - // Instance created per worker thread to handle all transactions on a given - // connection. - class QueryHandler - { - friend class QueryHandlerTester; - - static std::unordered_map _rs_cmds; - PMGDQueryHandler _pmgd_qh; - bool _autodelete_init; - bool _autoreplicate_init; - - bool syntax_checker(const Json::Value &root, Json::Value& error); - int parse_commands(const protobufs::queryMessage& proto_query, - Json::Value& root); - void cleanup_query(const std::vector& images, - const std::vector& videos); - - void process_query(protobufs::queryMessage& proto_query, - protobufs::queryMessage& response); - - // valijson - valijson::Validator _validator; - static valijson::Schema* _schema; - - #ifdef CHRONO_TIMING - ChronoCpu ch_tx_total; - ChronoCpu ch_tx_query; - ChronoCpu ch_tx_send; - #endif - - - public: - static void init(); - - QueryHandler(); - - void process_connection(comm::Connection *c); - void reset_autodelete_init_flag(); - void set_autodelete_init_flag(); - void regualar_run_autodelete(); - void build_autodelete_queue(); - void set_autoreplicate_init_flag(); - void reset_autoreplicate_init_flag(); - void regualar_run_autoreplicate(std::string&, std::string&, int&); - - }; -} +// Instance created per worker thread to handle all transactions on a given +// connection. +class QueryHandler { + friend class QueryHandlerTester; + + static std::unordered_map _rs_cmds; + PMGDQueryHandler _pmgd_qh; + bool _autodelete_init; + bool _autoreplicate_init; + + bool syntax_checker(const Json::Value &root, Json::Value &error); + int parse_commands(const protobufs::queryMessage &proto_query, + Json::Value &root); + void cleanup_query(const std::vector &images, + const std::vector &videos); + + void process_query(protobufs::queryMessage &proto_query, + protobufs::queryMessage &response); + + // valijson + valijson::Validator _validator; + static valijson::Schema *_schema; + +#ifdef CHRONO_TIMING + ChronoCpu ch_tx_total; + ChronoCpu ch_tx_query; + ChronoCpu ch_tx_send; +#endif + +public: + static void init(); + + QueryHandler(); + + void process_connection(comm::Connection *c); + void reset_autodelete_init_flag(); + void set_autodelete_init_flag(); + void regualar_run_autodelete(); + void build_autodelete_queue(); + void set_autoreplicate_init_flag(); + void reset_autoreplicate_init_flag(); + void regualar_run_autoreplicate(ReplicationConfig &); +}; +} // namespace VDMS diff --git a/src/QueryMessage.cc b/src/QueryMessage.cc index 4be489aa..2bc137e3 100644 --- a/src/QueryMessage.cc +++ b/src/QueryMessage.cc @@ -34,26 +34,22 @@ using namespace VDMS; -QueryMessage::QueryMessage(comm::Connection* conn): - _conn(conn) -{ - if (_conn == NULL) - throw ExceptionServer(NullConnection); +QueryMessage::QueryMessage(comm::Connection *conn) : _conn(conn) { + if (_conn == NULL) + throw ExceptionServer(NullConnection); } -protobufs::queryMessage QueryMessage::get_query() -{ - const std::basic_string& msg = _conn->recv_message(); +protobufs::queryMessage QueryMessage::get_query() { + const std::basic_string &msg = _conn->recv_message(); - protobufs::queryMessage cmd; - cmd.ParseFromArray((const void*)msg.data(), msg.length()); + protobufs::queryMessage cmd; + cmd.ParseFromArray((const void *)msg.data(), msg.length()); - return cmd; + return cmd; } -void QueryMessage::send_response(protobufs::queryMessage cmd) -{ - std::basic_string msg(cmd.ByteSize(),0); - cmd.SerializeToArray((void*)msg.data(), msg.length()); - _conn->send_message(msg.data(), msg.length()); +void QueryMessage::send_response(protobufs::queryMessage cmd) { + std::basic_string msg(cmd.ByteSize(), 0); + cmd.SerializeToArray((void *)msg.data(), msg.length()); + _conn->send_message(msg.data(), msg.length()); } diff --git a/src/QueryMessage.h b/src/QueryMessage.h index 42c896d5..78820914 100644 --- a/src/QueryMessage.h +++ b/src/QueryMessage.h @@ -35,14 +35,13 @@ #include "queryMessage.pb.h" namespace VDMS { - class QueryMessage - { - comm::Connection* _conn; +class QueryMessage { + comm::Connection *_conn; - public: - QueryMessage(comm::Connection* conn); +public: + QueryMessage(comm::Connection *conn); - protobufs::queryMessage get_query(); - void send_response(protobufs::queryMessage cmd); - }; + protobufs::queryMessage get_query(); + void send_response(protobufs::queryMessage cmd); }; +}; // namespace VDMS diff --git a/src/RSCommand.cc b/src/RSCommand.cc index 290595eb..7acee5a7 100644 --- a/src/RSCommand.cc +++ b/src/RSCommand.cc @@ -30,403 +30,325 @@ * */ -#include -#include #include +#include #include +#include -#include "QueryHandler.h" #include "ExceptionsCommand.h" +#include "QueryHandler.h" #include "VDMSConfig.h" -#include "vcl/VCL.h" #include "defines.h" +#include "vcl/VCL.h" using namespace VDMS; -RSCommand::RSCommand(const std::string& cmd_name): - _cmd_name(cmd_name) -{ +RSCommand::RSCommand(const std::string &cmd_name) : _cmd_name(cmd_name) { + _use_aws_storage = VDMSConfig::instance()->get_aws_flag(); } -Json::Value RSCommand::construct_responses( - Json::Value& response, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string& blob) -{ - Json::Value ret; - ret[_cmd_name] = check_responses(response); +Json::Value RSCommand::construct_responses(Json::Value &response, + const Json::Value &json, + protobufs::queryMessage &query_res, + const std::string &blob) { + Json::Value ret; + ret[_cmd_name] = check_responses(response); - return ret; + return ret; } -Json::Value RSCommand::check_responses(Json::Value& responses) -{ - bool flag_error = false; - Json::Value ret; +Json::Value RSCommand::check_responses(Json::Value &responses) { + bool flag_error = false; + Json::Value ret; - if (responses.size() == 0) { - ret["status"] = RSCommand::Error; - ret["info"] = "No responses!"; - return ret; - } + if (responses.size() == 0) { + ret["status"] = RSCommand::Error; + ret["info"] = "No responses!"; + return ret; + } - for (auto& res : responses) { - if (res["status"] != PMGDCmdResponse::Success - && - res["status"] != PMGDCmdResponse::Exists) - { - flag_error = true; - break; - } + for (auto &res : responses) { + if (res["status"] != PMGDCmdResponse::Success && + res["status"] != PMGDCmdResponse::Exists) { + flag_error = true; + break; } + } - ret = responses[0]; + ret = responses[0]; - if (!flag_error) { - ret["status"] = RSCommand::Success; - } + if (!flag_error) { + ret["status"] = RSCommand::Success; + } - return ret; + return ret; } namespace VDMS { -template<> -int RSCommand::get_value(const Json::Value& json, const std::string& key, - int def) -{ - if (json.isMember(key)) - return json[key].asInt(); - - return def; +template <> +int RSCommand::get_value(const Json::Value &json, const std::string &key, + int def) { + if (json.isMember(key)) + return json[key].asInt(); + + return def; } -template<> -double RSCommand::get_value(const Json::Value& json, const std::string& key, - double def) -{ - if (json.isMember(key)) - return json[key].asDouble(); +template <> +double RSCommand::get_value(const Json::Value &json, const std::string &key, + double def) { + if (json.isMember(key)) + return json[key].asDouble(); - return def; + return def; } -template<> -bool RSCommand::get_value(const Json::Value& json, const std::string& key, - bool def) -{ - if (json.isMember(key)) - return json[key].asBool(); +template <> +bool RSCommand::get_value(const Json::Value &json, const std::string &key, + bool def) { + if (json.isMember(key)) + return json[key].asBool(); - return def; + return def; } -template<> -std::string RSCommand::get_value(const Json::Value& json, - const std::string& key, - std::string def) -{ - if (json.isMember(key)) - return json[key].asString(); +template <> +std::string RSCommand::get_value(const Json::Value &json, + const std::string &key, std::string def) { + if (json.isMember(key)) + return json[key].asString(); - return def; + return def; } -template<> -Json::Value RSCommand::get_value(const Json::Value& json, - const std::string& key, - Json::Value def) -{ - return json[key]; -} +template <> +Json::Value RSCommand::get_value(const Json::Value &json, + const std::string &key, Json::Value def) { + return json[key]; } - -void RSCommand::add_link(PMGDQuery& query, const Json::Value& link, - int node_ref, const std::string tag) -{ - // ref is guaranteed to exist at this point - int dst = get_value(link,"ref"); // Default is "out" - int src = node_ref; - if (link.isMember("direction") && link["direction"] == "in") { - src = dst; - dst = node_ref; - } - - query.AddEdge(-1, src, dst, - get_value(link, "class", tag), - link["properties"] - ); +} // namespace VDMS + +void RSCommand::add_link(PMGDQuery &query, const Json::Value &link, + int node_ref, const std::string tag) { + // ref is guaranteed to exist at this point + int dst = get_value(link, "ref"); // Default is "out" + int src = node_ref; + if (link.isMember("direction") && link["direction"] == "in") { + src = dst; + dst = node_ref; + } + + query.AddEdge(-1, src, dst, get_value(link, "class", tag), + link["properties"]); } //========= AddEntity definitions ========= -AddEntity::AddEntity() : RSCommand("AddEntity") -{ - _storage_blob = VDMSConfig::instance()->get_path_blobs(); +AddEntity::AddEntity() : RSCommand("AddEntity") { + _storage_blob = VDMSConfig::instance()->get_path_blobs(); } -bool AddEntity::need_blob(const Json::Value& jsoncmd) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - return get_value(cmd, "blob", false); +bool AddEntity::need_blob(const Json::Value &jsoncmd) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + return get_value(cmd, "blob", false); } -int AddEntity::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - bool link = cmd.isMember("link"); - - int node_ref = get_value(cmd, "_ref", - link ? query.get_available_reference() : -1); - - // Modifiyng the existing properties that the user gives - // is a good option to make the AddNode more simple. - // This is not ideal since we are manupulating with user's - // input, but for now it is an acceptable solution. - Json::Value props = get_value(cmd, "properties"); - - if (get_value(cmd, "blob", false)) { - std::ostringstream oss; - oss << std::hex << VCL::get_uint64(); - std::string file_name = _storage_blob + "/" + oss.str(); - - props[VDMS_EN_BLOB_PATH_PROP] = file_name; - - std::ofstream file; - file.open(file_name); - file << blob; - file.close(); - } +int AddEntity::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + bool link = cmd.isMember("link"); - query.AddNode( - node_ref, - get_value(cmd, "class"), - props, - cmd["constraints"] - ); + int node_ref = + get_value(cmd, "_ref", link ? query.get_available_reference() : -1); - if (link) { - add_link(query, cmd["link"], node_ref, VDMS_GENERIC_LINK); - } + // Modifiyng the existing properties that the user gives + // is a good option to make the AddNode more simple. + // This is not ideal since we are manupulating with user's + // input, but for now it is an acceptable solution. + Json::Value props = get_value(cmd, "properties"); + + if (get_value(cmd, "blob", false)) { + std::ostringstream oss; + oss << std::hex << VCL::get_uint64(); + std::string file_name = _storage_blob + "/" + oss.str(); + + props[VDMS_EN_BLOB_PATH_PROP] = file_name; + + std::ofstream file; + file.open(file_name); + file << blob; + file.close(); + } + + query.AddNode(node_ref, get_value(cmd, "class"), props, + cmd["constraints"]); - return 0; + if (link) { + add_link(query, cmd["link"], node_ref, VDMS_GENERIC_LINK); + } + + return 0; } //========= UpdateEntity definitions ========= -UpdateEntity::UpdateEntity() : RSCommand("UpdateEntity") -{ -} +UpdateEntity::UpdateEntity() : RSCommand("UpdateEntity") {} + +int UpdateEntity::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; -int UpdateEntity::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - query.UpdateNode( - get_value(cmd, "_ref", -1), - get_value(cmd, "class"), - cmd["properties"], - cmd["remove_props"], - cmd["constraints"], - get_value(cmd, "unique", false) - ); - - return 0; + query.UpdateNode(get_value(cmd, "_ref", -1), + get_value(cmd, "class"), cmd["properties"], + cmd["remove_props"], cmd["constraints"], + get_value(cmd, "unique", false)); + + return 0; } //========= AddConnection definitions ========= -AddConnection::AddConnection() : RSCommand("AddConnection") -{ -} +AddConnection::AddConnection() : RSCommand("AddConnection") {} + +int AddConnection::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; -int AddConnection::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - query.AddEdge( - get_value(cmd, "_ref", -1), - get_value(cmd, "ref1", -1), // src - get_value(cmd, "ref2", -1), // dst - get_value(cmd, "class"), // tag - cmd["properties"] - ); - - return 0; + query.AddEdge(get_value(cmd, "_ref", -1), + get_value(cmd, "ref1", -1), // src + get_value(cmd, "ref2", -1), // dst + get_value(cmd, "class"), // tag + cmd["properties"]); + + return 0; } //========= UpdateConnection definitions ========= -UpdateConnection::UpdateConnection() : RSCommand("UpdateConnection") -{ -} +UpdateConnection::UpdateConnection() : RSCommand("UpdateConnection") {} + +int UpdateConnection::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; -int UpdateConnection::construct_protobuf(PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - query.UpdateEdge( - get_value(cmd, "_ref", -1), - get_value(cmd, "ref1", -1), - get_value(cmd, "ref2", -1), - get_value(cmd, "class"), - cmd["properties"], - cmd["remove_props"], - cmd["constraints"], - get_value(cmd, "unique", false) - ); - - return 0; + query.UpdateEdge( + get_value(cmd, "_ref", -1), get_value(cmd, "ref1", -1), + get_value(cmd, "ref2", -1), get_value(cmd, "class"), + cmd["properties"], cmd["remove_props"], cmd["constraints"], + get_value(cmd, "unique", false)); + + return 0; } //========= FindEntity definitions ========= -FindEntity::FindEntity() : RSCommand("FindEntity") -{ -} +FindEntity::FindEntity() : RSCommand("FindEntity") {} -int FindEntity::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; +int FindEntity::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - Json::Value results = get_value(cmd, "results"); + Json::Value results = get_value(cmd, "results"); - if (get_value(results, "blob", false)){ - results["list"].append(VDMS_EN_BLOB_PATH_PROP); - } + if (get_value(results, "blob", false)) { + results["list"].append(VDMS_EN_BLOB_PATH_PROP); + } - query.QueryNode( - get_value(cmd, "_ref", -1), - get_value(cmd, "class"), - cmd["link"], - cmd["constraints"], - results, - get_value(cmd, "unique", false) - ); + query.QueryNode(get_value(cmd, "_ref", -1), + get_value(cmd, "class"), cmd["link"], + cmd["constraints"], results, + get_value(cmd, "unique", false)); - return 0; + return 0; } -Json::Value FindEntity::construct_responses( - Json::Value& response, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - assert(response.size() == 1); - - Json::Value ret; - Json::Value& findEnt = response[0]; - - const Json::Value& cmd = json[_cmd_name]; - - if (get_value(cmd["results"], "blob", false)) { - for (auto& ent : findEnt["entities"]) { - - if(ent.isMember(VDMS_EN_BLOB_PATH_PROP)) { - std::string blob_path = ent[VDMS_EN_BLOB_PATH_PROP].asString(); - ent.removeMember(VDMS_EN_BLOB_PATH_PROP); - - std::string* blob_str = query_res.add_blobs(); - std::ifstream t(blob_path); - t.seekg(0, std::ios::end); - size_t size = t.tellg(); - blob_str->resize(size); - t.seekg(0); - t.read((char*)blob_str->data(), size); - - // For those cases the entity does not have a blob. - // We need to indicate which entities have blobs. - ent["blob"] = true; - } - } +Json::Value FindEntity::construct_responses(Json::Value &response, + const Json::Value &json, + protobufs::queryMessage &query_res, + const std::string &blob) { + assert(response.size() == 1); + + Json::Value ret; + Json::Value &findEnt = response[0]; + + const Json::Value &cmd = json[_cmd_name]; + + if (get_value(cmd["results"], "blob", false)) { + for (auto &ent : findEnt["entities"]) { + + if (ent.isMember(VDMS_EN_BLOB_PATH_PROP)) { + std::string blob_path = ent[VDMS_EN_BLOB_PATH_PROP].asString(); + ent.removeMember(VDMS_EN_BLOB_PATH_PROP); + + std::string *blob_str = query_res.add_blobs(); + std::ifstream t(blob_path); + t.seekg(0, std::ios::end); + size_t size = t.tellg(); + blob_str->resize(size); + t.seekg(0); + t.read((char *)blob_str->data(), size); + + // For those cases the entity does not have a blob. + // We need to indicate which entities have blobs. + ent["blob"] = true; + } } + } - // This will change the response tree, - // but it is ok and avoids a copy - ret[_cmd_name].swap(findEnt); + // This will change the response tree, + // but it is ok and avoids a copy + ret[_cmd_name].swap(findEnt); - return ret; + return ret; } //========= DeleteExpired definitions ========= -DeleteExpired::DeleteExpired() : RSCommand("DeleteExpired") -{ -} +DeleteExpired::DeleteExpired() : RSCommand("DeleteExpired") {} -int DeleteExpired::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - query.DeleteExpired(); - return 0; +int DeleteExpired::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + query.DeleteExpired(); + return 0; } Json::Value DeleteExpired::construct_responses( - Json::Value& response, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - Json::Value ret; - Json::Value ret_internal; - ret_internal["status"] = RSCommand::Success; - ret_internal["info"] = "AutoDelete"; - ret["DeleteExpired"] = ret_internal; - return ret; + Json::Value &response, const Json::Value &json, + protobufs::queryMessage &query_res, const std::string &blob) { + Json::Value ret; + Json::Value ret_internal; + ret_internal["status"] = RSCommand::Success; + ret_internal["info"] = "AutoDelete"; + ret["DeleteExpired"] = ret_internal; + return ret; } //========= FindConnection definitions ========= -FindConnection::FindConnection() : RSCommand("FindConnection") -{ -} +FindConnection::FindConnection() : RSCommand("FindConnection") {} + +int FindConnection::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + + query.QueryEdge(get_value(cmd, "_ref", -1), + get_value(cmd, "ref1", -1), + get_value(cmd, "ref2", -1), + get_value(cmd, "class"), cmd["constraints"], + cmd["results"], get_value(cmd, "unique", false)); -int FindConnection::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - query.QueryEdge( - get_value(cmd, "_ref", -1), - get_value(cmd, "ref1", -1), - get_value(cmd, "ref2", -1), - get_value(cmd, "class"), - cmd["constraints"], - cmd["results"], - get_value(cmd, "unique", false) - ); - - return 0; + return 0; } diff --git a/src/RSCommand.h b/src/RSCommand.h index 133fc793..ef7e7945 100644 --- a/src/RSCommand.h +++ b/src/RSCommand.h @@ -30,10 +30,10 @@ */ #pragma once -#include -#include #include +#include #include +#include #include "PMGDQuery.h" #include "queryMessage.pb.h" @@ -44,144 +44,112 @@ namespace VDMS { // Helper classes for handling various JSON commands. - class RSCommand - { - protected: - - const std::string _cmd_name; - std::map _valid_params_map; - - template - T get_value(const Json::Value& json, const std::string& key, - T def = T()); - - void add_link(PMGDQuery& query, const Json::Value& link, - int node_ref, const std::string tag); - - virtual Json::Value check_responses(Json::Value& responses); - - public: - - enum ErrorCode { - Success = 0, - Error = -1, - Empty = 1, - Exists = 2, - NotUnique = 3 - }; - - RSCommand(const std::string& cmd_name); - - virtual bool need_blob(const Json::Value& cmd) { return false; } - - virtual int construct_protobuf( - PMGDQuery& query, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error) = 0; - - virtual Json::Value construct_responses( - Json::Value& json_responses, - const Json::Value& json, - protobufs::queryMessage &response, - const std::string &blob); - }; - - class AddEntity : public RSCommand - { - private: - std::string _storage_blob; - - public: - AddEntity(); - int construct_protobuf(PMGDQuery& query, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - bool need_blob(const Json::Value& jsoncmd); - }; - - class AddConnection : public RSCommand - { - public: - AddConnection(); - int construct_protobuf(PMGDQuery& query, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - }; - - class UpdateEntity : public RSCommand - { - public: - UpdateEntity(); - int construct_protobuf(PMGDQuery& query, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - }; - - class UpdateConnection : public RSCommand - { - public: - UpdateConnection(); - int construct_protobuf(PMGDQuery& query, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - }; - - class FindEntity : public RSCommand - { - public: - FindEntity(); - int construct_protobuf(PMGDQuery& query, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - Json::Value construct_responses( - Json::Value& json_responses, - const Json::Value& json, - protobufs::queryMessage &response, - const std::string &blob); - }; - - class DeleteExpired : public RSCommand - { - public: - DeleteExpired(); - int construct_protobuf(PMGDQuery& query, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - Json::Value construct_responses( - Json::Value& json_responses, - const Json::Value& json, - protobufs::queryMessage &response, - const std::string &blob); - }; - - class FindConnection : public RSCommand - { - public: - FindConnection(); - int construct_protobuf(PMGDQuery& query, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - }; +class RSCommand { +protected: + const std::string _cmd_name; + std::map _valid_params_map; + + template + T get_value(const Json::Value &json, const std::string &key, T def = T()); + + void add_link(PMGDQuery &query, const Json::Value &link, int node_ref, + const std::string tag); + + virtual Json::Value check_responses(Json::Value &responses); + +public: + enum ErrorCode { + Success = 0, + Error = -1, + Empty = 1, + Exists = 2, + NotUnique = 3 + }; + + bool _use_aws_storage; + + RSCommand(const std::string &cmd_name); + + virtual bool need_blob(const Json::Value &cmd) { return false; } + + virtual int construct_protobuf(PMGDQuery &query, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error) = 0; + + virtual Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; + +class AddEntity : public RSCommand { +private: + std::string _storage_blob; + +public: + AddEntity(); + int construct_protobuf(PMGDQuery &query, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + bool need_blob(const Json::Value &jsoncmd); +}; + +class AddConnection : public RSCommand { +public: + AddConnection(); + int construct_protobuf(PMGDQuery &query, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); +}; + +class UpdateEntity : public RSCommand { +public: + UpdateEntity(); + int construct_protobuf(PMGDQuery &query, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); +}; + +class UpdateConnection : public RSCommand { +public: + UpdateConnection(); + int construct_protobuf(PMGDQuery &query, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); +}; + +class FindEntity : public RSCommand { +public: + FindEntity(); + int construct_protobuf(PMGDQuery &query, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; + +class DeleteExpired : public RSCommand { +public: + DeleteExpired(); + int construct_protobuf(PMGDQuery &query, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; + +class FindConnection : public RSCommand { +public: + FindConnection(); + int construct_protobuf(PMGDQuery &query, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); +}; }; // namespace VDMS diff --git a/src/SearchExpression.cc b/src/SearchExpression.cc index 754a661e..85431aa9 100644 --- a/src/SearchExpression.cc +++ b/src/SearchExpression.cc @@ -30,275 +30,257 @@ */ #include "SearchExpression.h" -#include "pmgd.h" #include "neighbor.h" +#include "pmgd.h" using namespace VDMS; -class SearchExpression::NodeAndIteratorImpl : public PMGD::NodeIteratorImplIntf -{ - /// Reference to expression to evaluate - const SearchExpression _expr; - - /// Node iterator on the first property predicate - PMGD::NodeIterator mNodeIt; - - // Indicate where to start in the search expression vector - unsigned _start_at; - - // Indicate if it is a neighbor search - bool _neighbor; - - /// Advance to the next matching node - /// @returns true if we find a matching node - /// Precondition: mNodeIt points to the next possible node - /// candidate - bool _next() - { - for (; mNodeIt; mNodeIt.next()) { - if (_neighbor && (_expr.tag() != 0 && mNodeIt->get_tag() != _expr.tag()) ) - goto continueNodeIt; - for (std::size_t i = _start_at; i < _expr._node_predicates.size(); i++) { - PMGD::PropertyFilter pf(_expr._node_predicates.at(i)); - if (pf(*mNodeIt) == PMGD::DontPass) - goto continueNodeIt; - } - return true; - continueNodeIt:; - } - return false; +class SearchExpression::NodeAndIteratorImpl + : public PMGD::NodeIteratorImplIntf { + /// Reference to expression to evaluate + const SearchExpression _expr; + + /// Node iterator on the first property predicate + PMGD::NodeIterator mNodeIt; + + // Indicate where to start in the search expression vector + unsigned _start_at; + + // Indicate if it is a neighbor search + bool _neighbor; + + /// Advance to the next matching node + /// @returns true if we find a matching node + /// Precondition: mNodeIt points to the next possible node + /// candidate + bool _next() { + for (; mNodeIt; mNodeIt.next()) { + if (_neighbor && (_expr.tag() != 0 && mNodeIt->get_tag() != _expr.tag())) + goto continueNodeIt; + for (std::size_t i = _start_at; i < _expr._node_predicates.size(); i++) { + PMGD::PropertyFilter pf(_expr._node_predicates.at(i)); + if (pf(*mNodeIt) == PMGD::DontPass) + goto continueNodeIt; + } + return true; + continueNodeIt:; } + return false; + } public: - /// Construct an iterator given the search expression - /// - /// Postcondition: mNodeIt points to the first matching node, or - /// returns NULL. - NodeAndIteratorImpl(const SearchExpression &expr) - : _expr(expr), - mNodeIt(_expr._db.get_nodes(_expr.tag(), - (_expr._node_predicates.empty() ? PMGD::PropertyPredicate() - : _expr._node_predicates.at(0)))), - _neighbor(false) - { - _start_at = 1; - _next(); - } - - /// Construct an iterator given the search expression for neighbors - /// - /// Postcondition: mNodeIt points to the first matching node, or - /// returns NULL. - NodeAndIteratorImpl(const PMGD::Node &node, PMGD::Direction dir, - PMGD::StringID edgetag, bool unique, - const SearchExpression &neighbor_expr) - : _expr(neighbor_expr), - mNodeIt(get_neighbors(node, dir, edgetag, - _expr.get_edge_predicates(), unique)), - _neighbor(true) - { - _start_at = 0; - _next(); - } + /// Construct an iterator given the search expression + /// + /// Postcondition: mNodeIt points to the first matching node, or + /// returns NULL. + NodeAndIteratorImpl(const SearchExpression &expr) + : _expr(expr), mNodeIt(_expr._db.get_nodes( + _expr.tag(), (_expr._node_predicates.empty() + ? PMGD::PropertyPredicate() + : _expr._node_predicates.at(0)))), + _neighbor(false) { + _start_at = 1; + _next(); + } + + /// Construct an iterator given the search expression for neighbors + /// + /// Postcondition: mNodeIt points to the first matching node, or + /// returns NULL. + NodeAndIteratorImpl(const PMGD::Node &node, PMGD::Direction dir, + PMGD::StringID edgetag, bool unique, + const SearchExpression &neighbor_expr) + : _expr(neighbor_expr), + mNodeIt(get_neighbors(node, dir, edgetag, _expr.get_edge_predicates(), + unique)), + _neighbor(true) { + _start_at = 0; + _next(); + } + + operator bool() const { return bool(mNodeIt); } + + /// Advance to the next node + /// @returns true if such a next node exists + bool next() { + mNodeIt.next(); + return _next(); + } + + PMGD::Node *ref() { return &*mNodeIt; } +}; - operator bool() const { return bool(mNodeIt); } +class SearchExpression::NodeOrIteratorImpl : public PMGD::NodeIteratorImplIntf { + /// Reference to expression to evaluate + const SearchExpression _expr; - /// Advance to the next node - /// @returns true if such a next node exists - bool next() - { - mNodeIt.next(); - return _next(); - } + /// Node iterator on the first property predicate + PMGD::Node *_node; - PMGD::Node *ref() { return &*mNodeIt; } -}; + // Indicate where to start in the search expression vector + unsigned _idx; -class SearchExpression::NodeOrIteratorImpl : public PMGD::NodeIteratorImplIntf -{ - /// Reference to expression to evaluate - const SearchExpression _expr; - - /// Node iterator on the first property predicate - PMGD::Node* _node; - - // Indicate where to start in the search expression vector - unsigned _idx; - - // Indicate if it is a neighbor search - bool _neighbor; - - PMGD::NodeIterator _neighborIt; - - /// Advance to the next matching node - /// @returns true if we find a matching node - /// Precondition: _node points to the next possible node - /// candidate - bool _next() - { - while (_idx < _expr._node_predicates.size()) { - PMGD::NodeIterator ni = - _expr._db.get_nodes(_expr.tag(), - _expr._node_predicates.at(_idx++)); - - if (ni) { - _node = &*ni; - return true; - } - } + // Indicate if it is a neighbor search + bool _neighbor; - return false; - } + PMGD::NodeIterator _neighborIt; - bool _next_neighbor() - { - static int id = 0; - while (_neighborIt) { - for (const auto& pred : _expr._node_predicates) { - PMGD::PropertyFilter pf(pred); - if (pf(*_neighborIt) == PMGD::Pass) { - _node = &*_neighborIt; - return true; - } - } - - _neighborIt.next(); - } + /// Advance to the next matching node + /// @returns true if we find a matching node + /// Precondition: _node points to the next possible node + /// candidate + bool _next() { + while (_idx < _expr._node_predicates.size()) { + PMGD::NodeIterator ni = + _expr._db.get_nodes(_expr.tag(), _expr._node_predicates.at(_idx++)); - return false; + if (ni) { + _node = &*ni; + return true; + } } -public: - /// Construct an iterator given the search expression - /// - /// Postcondition: _node points to the first matching node, or - /// returns NULL. - NodeOrIteratorImpl(const SearchExpression &expr) - : _expr(expr), - _idx(0), - _neighbor(false), - _neighborIt(NULL) - { - _next(); - } + return false; + } + + bool _next_neighbor() { + static int id = 0; + while (_neighborIt) { + for (const auto &pred : _expr._node_predicates) { + PMGD::PropertyFilter pf(pred); + if (pf(*_neighborIt) == PMGD::Pass) { + _node = &*_neighborIt; + return true; + } + } - /// Construct an iterator given the search expression for neighbors - /// - /// Postcondition: _node points to the first matching node, or - /// returns NULL. - NodeOrIteratorImpl(const PMGD::Node &node, PMGD::Direction dir, - PMGD::StringID edgetag, bool unique, - const SearchExpression &neighbor_expr) - : _expr(neighbor_expr), - _neighborIt(get_neighbors(node, dir, edgetag, - _expr.get_edge_predicates(), unique)), - _neighbor(true) - { - _next_neighbor(); - _idx = 0; + _neighborIt.next(); } - operator bool() const { return bool(_node); } + return false; + } - /// Advance to the next node - /// @returns true if such a next node exists - bool next() - { - if (_neighbor) { - _neighborIt.next(); - return _next_neighbor(); - } - else { - return _next(); - } +public: + /// Construct an iterator given the search expression + /// + /// Postcondition: _node points to the first matching node, or + /// returns NULL. + NodeOrIteratorImpl(const SearchExpression &expr) + : _expr(expr), _idx(0), _neighbor(false), _neighborIt(NULL) { + _next(); + } + + /// Construct an iterator given the search expression for neighbors + /// + /// Postcondition: _node points to the first matching node, or + /// returns NULL. + NodeOrIteratorImpl(const PMGD::Node &node, PMGD::Direction dir, + PMGD::StringID edgetag, bool unique, + const SearchExpression &neighbor_expr) + : _expr(neighbor_expr), + _neighborIt(get_neighbors(node, dir, edgetag, + _expr.get_edge_predicates(), unique)), + _neighbor(true) { + _next_neighbor(); + _idx = 0; + } + + operator bool() const { return bool(_node); } + + /// Advance to the next node + /// @returns true if such a next node exists + bool next() { + if (_neighbor) { + _neighborIt.next(); + return _next_neighbor(); + } else { + return _next(); } + } - PMGD::Node *ref() { return _node; } + PMGD::Node *ref() { return _node; } }; // *** Could find a template way of combining Node and Edge iterator. -class SearchExpression::EdgeAndIteratorImpl : public PMGD::EdgeIteratorImplIntf -{ - /// Reference to expression to evaluate - const SearchExpression &_expr; - - /// Node iterator on the first property predicate - PMGD::EdgeIterator mEdgeIt; - - /// Advance to the next matching node - /// @returns true if we find a matching node - /// Precondition: mNodeIt points to the next possible node - /// candidate - bool _next() - { - for (; mEdgeIt; mEdgeIt.next()) { - for (std::size_t i = 1; i < _expr._node_predicates.size(); i++) { - PMGD::PropertyFilter pf(_expr._node_predicates.at(i)); - if (pf(*mEdgeIt) == PMGD::DontPass) - goto continueEdgeIt; - } - return true; - continueEdgeIt:; - } - return false; +class SearchExpression::EdgeAndIteratorImpl + : public PMGD::EdgeIteratorImplIntf { + /// Reference to expression to evaluate + const SearchExpression &_expr; + + /// Node iterator on the first property predicate + PMGD::EdgeIterator mEdgeIt; + + /// Advance to the next matching node + /// @returns true if we find a matching node + /// Precondition: mNodeIt points to the next possible node + /// candidate + bool _next() { + for (; mEdgeIt; mEdgeIt.next()) { + for (std::size_t i = 1; i < _expr._node_predicates.size(); i++) { + PMGD::PropertyFilter pf(_expr._node_predicates.at(i)); + if (pf(*mEdgeIt) == PMGD::DontPass) + goto continueEdgeIt; + } + return true; + continueEdgeIt:; } + return false; + } public: - /// Construct an iterator given the search expression - /// - /// Postcondition: mEdgeIt points to the first matching edge, or - /// returns NULL. - EdgeAndIteratorImpl(const SearchExpression &expr) - : _expr(expr), - mEdgeIt(_expr._db.get_edges(_expr.tag(), - (_expr._node_predicates.empty() ? PMGD::PropertyPredicate() - : _expr._node_predicates.at(0)))) - { - _next(); - } - - operator bool() const { return bool(mEdgeIt); } - - /// Advance to the next node - /// @returns true if such a next node exists - bool next() - { - mEdgeIt.next(); - return _next(); - } - - PMGD::EdgeRef *ref() { return &*mEdgeIt; } - PMGD::StringID get_tag() const { return mEdgeIt->get_tag(); } - PMGD::Node &get_source() const { return mEdgeIt->get_source(); } - PMGD::Node &get_destination() const { return mEdgeIt->get_destination(); } - PMGD::Edge *get_edge() const { return &static_cast(*mEdgeIt); } + /// Construct an iterator given the search expression + /// + /// Postcondition: mEdgeIt points to the first matching edge, or + /// returns NULL. + EdgeAndIteratorImpl(const SearchExpression &expr) + : _expr(expr), mEdgeIt(_expr._db.get_edges( + _expr.tag(), (_expr._node_predicates.empty() + ? PMGD::PropertyPredicate() + : _expr._node_predicates.at(0)))) { + _next(); + } + + operator bool() const { return bool(mEdgeIt); } + + /// Advance to the next node + /// @returns true if such a next node exists + bool next() { + mEdgeIt.next(); + return _next(); + } + + PMGD::EdgeRef *ref() { return &*mEdgeIt; } + PMGD::StringID get_tag() const { return mEdgeIt->get_tag(); } + PMGD::Node &get_source() const { return mEdgeIt->get_source(); } + PMGD::Node &get_destination() const { return mEdgeIt->get_destination(); } + PMGD::Edge *get_edge() const { return &static_cast(*mEdgeIt); } }; /// Evaluate the associated search expression /// @returns an iterator over the search expression -PMGD::NodeIterator SearchExpression::eval_nodes() -{ - if (_or) - return PMGD::NodeIterator(new NodeOrIteratorImpl(*this)); - else - return PMGD::NodeIterator(new NodeAndIteratorImpl(*this)); +PMGD::NodeIterator SearchExpression::eval_nodes() { + if (_or) + return PMGD::NodeIterator(new NodeOrIteratorImpl(*this)); + else + return PMGD::NodeIterator(new NodeAndIteratorImpl(*this)); } /// Evaluate the associated search expression on neighbors /// @returns an iterator over the search expression -PMGD::NodeIterator SearchExpression::eval_nodes - (const PMGD::Node &node, PMGD::Direction dir, - PMGD::StringID edgetag, bool unique) -{ - if (_or) - return PMGD::NodeIterator(new NodeOrIteratorImpl(node, dir, edgetag, unique, *this)); - else - return PMGD::NodeIterator(new NodeAndIteratorImpl(node, dir, edgetag, unique, *this)); +PMGD::NodeIterator SearchExpression::eval_nodes(const PMGD::Node &node, + PMGD::Direction dir, + PMGD::StringID edgetag, + bool unique) { + if (_or) + return PMGD::NodeIterator( + new NodeOrIteratorImpl(node, dir, edgetag, unique, *this)); + else + return PMGD::NodeIterator( + new NodeAndIteratorImpl(node, dir, edgetag, unique, *this)); } /// Evaluate the associated search expression /// @returns an iterator over the search expression -PMGD::EdgeIterator SearchExpression::eval_edges() -{ - return PMGD::EdgeIterator(new EdgeAndIteratorImpl(*this)); +PMGD::EdgeIterator SearchExpression::eval_edges() { + return PMGD::EdgeIterator(new EdgeAndIteratorImpl(*this)); } diff --git a/src/SearchExpression.h b/src/SearchExpression.h index 1cf788fd..151af8cc 100644 --- a/src/SearchExpression.h +++ b/src/SearchExpression.h @@ -31,8 +31,8 @@ #pragma once -#include #include "pmgd.h" +#include /// Search expression to query a PMGD Lake database /// @@ -46,55 +46,56 @@ /// Calling Eval() returns a node iterator. namespace VDMS { - class SearchExpression - { - PMGD::StringID _tag; +class SearchExpression { + PMGD::StringID _tag; - /// Opaque definition of a node iterator - class NodeAndIteratorImpl; - class NodeOrIteratorImpl; + /// Opaque definition of a node iterator + class NodeAndIteratorImpl; + class NodeOrIteratorImpl; - /// Opaque definition of an edge iterator - class EdgeAndIteratorImpl; + /// Opaque definition of an edge iterator + class EdgeAndIteratorImpl; - bool _or; + bool _or; - /// The conjunctions of property predicates - std::vector _node_predicates; + /// The conjunctions of property predicates + std::vector _node_predicates; - /// The conjunctions of property predicates for edges - std::vector _edge_predicates; + /// The conjunctions of property predicates for edges + std::vector _edge_predicates; - /// A pointer to the database - PMGD::Graph &_db; + /// A pointer to the database + PMGD::Graph &_db; - public: - /// Construction requires a handle to a database - SearchExpression(PMGD::Graph &db, PMGD::StringID tag, bool p_or) : - _db(db), _tag(tag), _or(p_or) {} +public: + /// Construction requires a handle to a database + SearchExpression(PMGD::Graph &db, PMGD::StringID tag, bool p_or) + : _db(db), _tag(tag), _or(p_or) {} - PMGD::Graph &db() const { return _db; } - const PMGD::StringID tag() const { return _tag; }; + PMGD::Graph &db() const { return _db; } + const PMGD::StringID tag() const { return _tag; }; - void add_node_predicate(PMGD::PropertyPredicate pp) { - _node_predicates.push_back(pp); } - const PMGD::PropertyPredicate &get_node_predicate(int i) const { - return _node_predicates.at(i); } - const size_t num_node_predicates() const { - return _node_predicates.size(); } + void add_node_predicate(PMGD::PropertyPredicate pp) { + _node_predicates.push_back(pp); + } + const PMGD::PropertyPredicate &get_node_predicate(int i) const { + return _node_predicates.at(i); + } + const size_t num_node_predicates() const { return _node_predicates.size(); } - void add_edge_predicate(PMGD::PropertyPredicate pp) { - _edge_predicates.push_back(pp); } - const std::vector& get_edge_predicates() const { - return _edge_predicates; } + void add_edge_predicate(PMGD::PropertyPredicate pp) { + _edge_predicates.push_back(pp); + } + const std::vector &get_edge_predicates() const { + return _edge_predicates; + } - PMGD::NodeIterator eval_nodes(); - PMGD::NodeIterator eval_nodes(const PMGD::Node &node, - PMGD::Direction dir = PMGD::Any, - PMGD::StringID edgetag = 0, - bool unique = true); + PMGD::NodeIterator eval_nodes(); + PMGD::NodeIterator eval_nodes(const PMGD::Node &node, + PMGD::Direction dir = PMGD::Any, + PMGD::StringID edgetag = 0, bool unique = true); - PMGD::EdgeIterator eval_edges(); - }; + PMGD::EdgeIterator eval_edges(); +}; -}; // end VDMS namespace +}; // namespace VDMS diff --git a/src/Server.cc b/src/Server.cc index 5ed07efc..4ea79dc0 100644 --- a/src/Server.cc +++ b/src/Server.cc @@ -29,22 +29,21 @@ * */ -#include /* system, NULL, EXIT_FAILURE */ +#include #include +#include /* system, NULL, EXIT_FAILURE */ #include -#include +#include "Exception.h" #include #include //to create the config file - #include "Server.h" #include "comm/Connection.h" -#include "Exception.h" -#include "VDMSConfig.h" -#include "QueryHandler.h" #include "DescriptorsManager.h" +#include "QueryHandler.h" +#include "VDMSConfig.h" #include "pmgdMessages.pb.h" // Protobuff implementation @@ -52,143 +51,194 @@ using namespace VDMS; bool Server::shutdown = false; -Server::Server(std::string config_file) -{ - VDMSConfig::init(config_file); - _server_port = VDMSConfig::instance() - ->get_int_value("port", DEFAULT_PORT); - _autodelete_interval = VDMSConfig::instance() - ->get_int_value("autodelete_interval_s", DEFAULT_AUTODELETE_INTERVAL); - _backup_flag = VDMSConfig::instance() - ->get_string_value("backup_flag", DEFAULT_AUTOREPLICATE_FLAG) ; - - _autoreplecate_interval = VDMSConfig::instance() - ->get_int_value("autoreplicate_interval", DEFAULT_AUTOREPLICATE_INTERVAL); - _replication_unit = VDMSConfig::instance() - ->get_string_value("unit", DEFAULT_AUTOREPLICATE_UNIT); - _backup_path = VDMSConfig::instance() - ->get_string_value("backup_path", DEFAULT_BACKUP_PATH); - _db_path = VDMSConfig::instance() - ->get_string_value("db_root_path", DEFAULT_DB_ROOT); - - PMGDQueryHandler::init(); - QueryHandler::init(); - - QueryHandler qh; - qh.set_autodelete_init_flag(); - qh.build_autodelete_queue(); //create priority queue of nodes with _expiration property - qh.regualar_run_autodelete(); // delete nodes that have expired since server previous closed - qh.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - - - // Verify that the version of the library that we linked against is - // compatible with the version of the headers we compiled against. - GOOGLE_PROTOBUF_VERIFY_VERSION; - - install_handler(); - - _cm = new CommunicationManager(); +Server::Server(std::string config_file) { + VDMSConfig::init(config_file); + _autoreplicate_settings.server_port = + VDMSConfig::instance()->get_int_value("port", DEFAULT_PORT); + + _autoreplicate_settings.max_simultaneous_clients = + VDMSConfig::instance()->get_int_value( + "max_simultaneous_clients", + 500); // Default from CommunicationManager.h + + _autoreplicate_settings.autodelete_interval = + VDMSConfig::instance()->get_int_value("autodelete_interval_s", + DEFAULT_AUTODELETE_INTERVAL); + _autoreplicate_settings.backup_flag = + VDMSConfig::instance()->get_string_value("backup_flag", + DEFAULT_AUTOREPLICATE_FLAG); + + _autoreplicate_settings.autoreplicate_interval = + VDMSConfig::instance()->get_int_value("autoreplicate_interval", + DEFAULT_AUTOREPLICATE_INTERVAL); + _autoreplicate_settings.autoreplication_unit = + VDMSConfig::instance()->get_string_value("unit", + DEFAULT_AUTOREPLICATE_UNIT); + + _autoreplicate_settings.replication_time = + VDMSConfig::instance()->get_string_value("replication_time", + DEFAULT_AUTOREPLICATE_UNIT); + _autoreplicate_settings.backup_path = + VDMSConfig::instance()->get_string_value("backup_path", + DEFAULT_BACKUP_PATH); + _autoreplicate_settings.db_path = + VDMSConfig::instance()->get_string_value("db_root_path", DEFAULT_DB_ROOT); + + PMGDQueryHandler::init(); + QueryHandler::init(); + + QueryHandler qh; + qh.set_autodelete_init_flag(); + qh.build_autodelete_queue(); // create priority queue of nodes with + // _expiration property + qh.regualar_run_autodelete(); // delete nodes that have expired since server + // previous closed + qh.reset_autodelete_init_flag(); // set flag to show autodelete queue has been + // initialized + + // Verify that the version of the library that we linked against is + // compatible with the version of the headers we compiled against. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + install_handler(); + + _cm = new CommunicationManager(); } -void Server::process_requests() -{ - comm::ConnServer *server; +void Server::process_requests() { + comm::ConnServer *server; + try { + server = new comm::ConnServer(_autoreplicate_settings.server_port); + } catch (comm::ExceptionComm e) { + print_exception(e); + delete server; + return; + } + + while (!shutdown) { try { - server = new comm::ConnServer(_server_port); + comm::Connection *conn_server = new comm::Connection(server->accept()); + _cm->add_connection(conn_server); } + catch (comm::ExceptionComm e) { - print_exception(e); - delete server; - return; + print_exception(e); } + } - while (!shutdown) { - try { - comm::Connection *conn_server = - new comm::Connection(server->accept()); - _cm->add_connection(conn_server); - + delete server; +} +void Server::untar_data(std::string &name) { - } - catch (comm::ExceptionComm e) { - print_exception(e); - } + std::string command = "tar -xvSf" + name; + system(command.c_str()); +} +void Server::auto_replicate_interval() { + long replication_period = 0; + QueryHandler qh; + + if (_autoreplicate_settings.backup_path.empty()) { + _autoreplicate_settings.backup_path = + _autoreplicate_settings.db_path; // set the default path to be db + } + + if (_autoreplicate_settings.autoreplicate_interval > 0) { + if (_autoreplicate_settings.autoreplication_unit.compare("h") == 0) { + replication_period = + _autoreplicate_settings.autoreplicate_interval * 60 * 60; + } else if (_autoreplicate_settings.autoreplication_unit.compare("m") == 0) { + replication_period = _autoreplicate_settings.autoreplicate_interval * 60; + } else { + replication_period = _autoreplicate_settings.autoreplicate_interval; } - - delete server; + } + if (replication_period <= 0) { + std::cout << "Error: auto-replication interval must be a positive number." + << std::endl; + return; + } + + while (!shutdown) { + // Sleep for the replication period + std::this_thread::sleep_for(std::chrono::seconds(replication_period)); + + // Execute the auto-replicate function + qh.regualar_run_autoreplicate(_autoreplicate_settings); + } } -void Server::untar_data(std::string& name){ +void Server::auto_replicate_data_exact_time() { + QueryHandler qh; + + std::istringstream iss(_autoreplicate_settings.replication_time); + std::string time; + char delimiter; + std::getline(iss, time); + + int hour, minute; + char period; + std::istringstream timeTokenIss(time); + timeTokenIss >> std::setw(2) >> hour >> delimiter >> std::setw(2) >> minute >> + period; // Extract hour, minute, and period + if (period == 'P') { + hour += 12; // Convert to 24-hour format + } + + while (!shutdown) { + // Get the current time + auto now = std::chrono::system_clock::now(); + auto now_time = std::chrono::system_clock::to_time_t(now); + struct std::tm *now_tm = std::localtime(&now_time); + + // Calculate the next replication time + std::tm replicate_tm = *now_tm; + replicate_tm.tm_hour = hour; // set the desired hour + replicate_tm.tm_min = minute; // set the desired minute + replicate_tm.tm_sec = 0; // set seconds to 0 + auto replicate_time = + std::chrono::system_clock::from_time_t(std::mktime(&replicate_tm)); + if (now > replicate_time) { + replicate_time += std::chrono::hours( + 24); // if the specified time has passed, set it for the next day + } - std::string command="tar -xvSf" + name; - system(command.c_str()); + // Sleep until the next replication time + auto duration = replicate_time - now; + std::this_thread::sleep_for(duration); + // Execute the auto-replicate function + qh.regualar_run_autoreplicate(_autoreplicate_settings); + } } -void Server::auto_replicate_data(){ - long replication_period = 0; +void Server::autodelete_expired_data() { + if (_autoreplicate_settings.autodelete_interval > + 0) // check to ensure valid autodelete_interval + { QueryHandler qh; - if(_backup_flag =="true"){ - if (_autoreplecate_interval >0 ){ - if (_replication_unit.compare("h") == 0){ - replication_period =_autoreplecate_interval*60*60; - } - else if (_replication_unit.compare("m") == 0) - replication_period =_autoreplecate_interval*60; - - else - replication_period= _autoreplecate_interval; - } - - if(_backup_path.empty()){ - _backup_path=_db_path; //set the defualt path to be db - } - - - if(replication_period > 0) //check to ensure valid autodelete_interval - { - - while(!shutdown) - { - sleep(replication_period); - qh.regualar_run_autoreplicate(_backup_path, _db_path, _server_port); - } - } - } -} - - -void Server::autodelete_expired_data() -{ - if(_autodelete_interval > 0) //check to ensure valid autodelete_interval - { - QueryHandler qh; - while(!shutdown) - { - sleep(_autodelete_interval); - qh.regualar_run_autodelete(); //delete data expired since startup - } + while (!shutdown) { + sleep(_autoreplicate_settings.autodelete_interval); + qh.regualar_run_autodelete(); // delete data expired since startup } + } } -void Server::install_handler() -{ - struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_handler = Server::sighandler; - if (sigaction(SIGINT, &action, 0) != 0) - throw ExceptionServer(SignalHandler); - if (sigaction(SIGTERM, &action, 0) != 0) - throw ExceptionServer(SignalHandler); - if (sigaction(SIGQUIT, &action, 0) != 0) - throw ExceptionServer(SignalHandler); +void Server::install_handler() { + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = Server::sighandler; + if (sigaction(SIGINT, &action, 0) != 0) + throw ExceptionServer(SignalHandler); + if (sigaction(SIGTERM, &action, 0) != 0) + throw ExceptionServer(SignalHandler); + if (sigaction(SIGQUIT, &action, 0) != 0) + throw ExceptionServer(SignalHandler); } -Server::~Server() -{ - _cm->shutdown(); - delete _cm; - PMGDQueryHandler::destroy(); - DescriptorsManager::instance()->flush(); - VDMSConfig::destroy(); +Server::~Server() { + _cm->shutdown(); + delete _cm; + PMGDQueryHandler::destroy(); + DescriptorsManager::instance()->flush(); + VDMSConfig::destroy(); } diff --git a/src/Server.h b/src/Server.h index 16148221..632353ec 100644 --- a/src/Server.h +++ b/src/Server.h @@ -33,53 +33,68 @@ #include -#include "pmgd.h" #include "CommunicationManager.h" +#include "pmgd.h" #include - namespace VDMS { - class Server - { - static const int DEFAULT_PORT = 55555; - static const int DEFAULT_AUTODELETE_INTERVAL = -1; - static const int DEFAULT_AUTOREPLICATE_INTERVAL = -1; - std::string DEFAULT_AUTOREPLICATE_UNIT ="s" ; - std::string DEFAULT_BACKUP_PATH ="."; - std::string DEFAULT_DB_ROOT ="db"; - std::string DEFAULT_AUTOREPLICATE_FLAG="false"; - - +struct ReplicationConfig { + std::string backup_path; + std::string db_path; + std::string replication_time; + std::string autoreplication_unit; + std::string backup_flag; + std::string images_path; + std::string descriptor_path; + std::string blobs_path; + int server_port; + int max_simultaneous_clients; + int autoreplicate_interval; + int autodelete_interval; + int expiration_time; + int pmgd_num_allocators; - CommunicationManager *_cm; - - // TODO: Partitioner here + ReplicationConfig() + : backup_path("."), db_path("db"), replication_time("-1"), + autoreplication_unit("s"), backup_flag("false"), + images_path("db/images"), descriptor_path("db/descriptors"), + blobs_path("db/blobs"), server_port(55555), + max_simultaneous_clients(10), autoreplicate_interval(-1), + autodelete_interval(-1), expiration_time(86400), + pmgd_num_allocators(5) { + // Additional initialization code if needed + } +}; +class Server { + static const int DEFAULT_PORT = 55555; + static const int DEFAULT_AUTODELETE_INTERVAL = -1; + static const int DEFAULT_AUTOREPLICATE_INTERVAL = -1; + std::string DEFAULT_AUTOREPLICATE_UNIT = "s"; + std::string DEFAULT_BACKUP_PATH = "."; + std::string DEFAULT_DB_ROOT = "db"; + std::string DEFAULT_AUTOREPLICATE_FLAG = "false"; - int _server_port; - int _autodelete_interval; - int _autoreplecate_interval; - std::string _replication_unit; - std::string _backup_path; - std::string _db_path; - std::string _backup_flag; - - bool _untar; + CommunicationManager *_cm; + ReplicationConfig _autoreplicate_settings; + bool _untar; - // Handle ^c - static bool shutdown; - void install_handler(); - static void sighandler(int signo) - { Server::shutdown = (signo == SIGINT) || - (signo == SIGTERM)|| - (signo == SIGQUIT); } + // Handle ^c + static bool shutdown; + void install_handler(); + static void sighandler(int signo) { + Server::shutdown = + (signo == SIGINT) || (signo == SIGTERM) || (signo == SIGQUIT); + } - public: - Server(std::string config_file); - void process_requests(); - void autodelete_expired_data(); - void auto_replicate_data(); - void untar_data(std::string&); - ~Server(); - }; +public: + Server(std::string config_file); + void process_requests(); + void autodelete_expired_data(); + void auto_replicate_interval(); + void auto_replicate_data_exact_time(); + void untar_data(std::string &); + ~Server(); }; + +}; // namespace VDMS diff --git a/src/VDMSConfig.cc b/src/VDMSConfig.cc index ee0171a5..9d6d442b 100644 --- a/src/VDMSConfig.cc +++ b/src/VDMSConfig.cc @@ -29,236 +29,235 @@ * */ -#include -#include #include #include +#include +#include -#include #include +#include #include #include #include "VDMSConfig.h" -#define DEFAULT_PATH_ROOT "db" -#define DEFAULT_PATH_PMGD "graph" -#define DEFAULT_PATH_IMAGES "images" -#define DEFAULT_PATH_JPG "jpg" -#define DEFAULT_PATH_PNG "png" -#define DEFAULT_PATH_TDB "tdb" -#define DEFAULT_PATH_BIN "bin" -#define DEFAULT_PATH_BLOBS "blobs" -#define DEFAULT_PATH_VIDEOS "videos" +#define DEFAULT_PATH_ROOT "db" +#define DEFAULT_PATH_PMGD "graph" +#define DEFAULT_PATH_IMAGES "images" +#define DEFAULT_PATH_JPG "jpg" +#define DEFAULT_PATH_PNG "png" +#define DEFAULT_PATH_TDB "tdb" +#define DEFAULT_PATH_BIN "bin" +#define DEFAULT_PATH_BLOBS "blobs" +#define DEFAULT_PATH_VIDEOS "videos" #define DEFAULT_PATH_DESCRIPTORS "descriptors" #define DEFAULT_PATH_TMP "tmp" +#define DEFAULT_STORAGE_TYPE "local" +#define DEFAULT_BUCKET_NAME "vdms_bucket" using namespace VDMS; -VDMSConfig* VDMSConfig::cfg; +VDMSConfig *VDMSConfig::cfg; -bool VDMSConfig::init(std::string config_file) -{ - if(cfg) - return false; +bool VDMSConfig::init(std::string config_file) { + if (cfg) + return false; - cfg = new VDMSConfig(config_file); - return true; + cfg = new VDMSConfig(config_file); + return true; } -void VDMSConfig::destroy() -{ - if (cfg) { - delete cfg; - cfg = NULL; - } +void VDMSConfig::destroy() { + if (cfg) { + delete cfg; + cfg = NULL; + } } -VDMSConfig* VDMSConfig::instance() -{ - if(cfg) - return cfg; +VDMSConfig *VDMSConfig::instance() { + if (cfg) + return cfg; - std::cout << "ERROR: Config not init" << std::endl; - return NULL; + std::cout << "ERROR: Config not init" << std::endl; + return NULL; } -VDMSConfig::VDMSConfig(std::string config_file) -{ - Json::Reader reader; - std::ifstream file(config_file); - - bool parsingSuccessful = reader.parse(file, json_config); - - if (!parsingSuccessful){ - std::cout << "Error parsing config file." << std::endl; - std::cout << "Exiting..." << std::endl; - exit(0); - } +VDMSConfig::VDMSConfig(std::string config_file) { + Json::Reader reader; + std::ifstream file(config_file); - build_dirs(); -} + bool parsingSuccessful = reader.parse(file, json_config); -int VDMSConfig::get_int_value(std::string val, int def) -{ - return json_config.get(val, def).asInt(); -} + if (!parsingSuccessful) { + std::cout << "Error parsing config file." << std::endl; + std::cout << "Exiting..." << std::endl; + exit(0); + } -std::string VDMSConfig::get_string_value(std::string val, std::string def) -{ - return json_config.get(val, def).asString(); + build_dirs(); } +int VDMSConfig::get_int_value(std::string val, int def) { + return json_config.get(val, def).asInt(); +} -//This is a function that createa a directory structure with DIRECTORY_LAYERS levels with each layer with DIRECTORIES_PER_LAYER ^ n directories. -//This function is recursive so will call itself to expand each directory level. +std::string VDMSConfig::get_string_value(std::string val, std::string def) { + return json_config.get(val, def).asString(); +} -void VDMSConfig::expand_directory_layer(std::vector< std::vector* > *p_directory_list, int current_layer) -{ - std::vector* tmp_directory_list = new std::vector(); - if(current_layer > 1) - { - expand_directory_layer(p_directory_list, current_layer - 1); +// This is a function that createa a directory structure with DIRECTORY_LAYERS +// levels with each layer with DIRECTORIES_PER_LAYER ^ n directories. This +// function is recursive so will call itself to expand each directory level. + +void VDMSConfig::expand_directory_layer( + std::vector *> *p_directory_list, + int current_layer) { + std::vector *tmp_directory_list = new std::vector(); + if (current_layer > 1) { + expand_directory_layer(p_directory_list, current_layer - 1); + } + if (p_directory_list->size() == 0) { + for (int i = 0; i < DIRECTORIES_PER_LAYER; i++) { + std::ostringstream tmp_stream; + tmp_stream << std::internal << std::setfill('0') + << std::setw(CHARS_PER_LAYER_NAME) << i; + tmp_directory_list->push_back(tmp_stream.str() + "/"); + // std::cout << (*tmp_directory_list)[i] << std::endl; } - if(p_directory_list->size() == 0) - { - for(int i = 0 ; i < DIRECTORIES_PER_LAYER; i++) - { - std::ostringstream tmp_stream; - tmp_stream << std::internal << std::setfill('0') << std::setw(CHARS_PER_LAYER_NAME) << i; - tmp_directory_list->push_back(tmp_stream.str() + "/" ); - //std::cout << (*tmp_directory_list)[i] << std::endl; - } - p_directory_list->push_back(tmp_directory_list); - } - else - { - for(int j = 0; j < (*p_directory_list)[p_directory_list->size() - 1]->size(); j++) - { - for(int i = 0 ; i < DIRECTORIES_PER_LAYER; i++) - { - std::ostringstream tmp_stream; - tmp_stream << std::internal << std::setfill('0') << std::setw(CHARS_PER_LAYER_NAME) << i; - tmp_directory_list->push_back((* (*p_directory_list)[p_directory_list->size() - 1] )[j] + tmp_stream.str() + "/" ); - //std::cout << (*tmp_directory_list)[tmp_directory_list->size() - 1] << std::endl; - } - } - p_directory_list->push_back(tmp_directory_list); + p_directory_list->push_back(tmp_directory_list); + } else { + for (int j = 0; + j < (*p_directory_list)[p_directory_list->size() - 1]->size(); j++) { + for (int i = 0; i < DIRECTORIES_PER_LAYER; i++) { + std::ostringstream tmp_stream; + tmp_stream << std::internal << std::setfill('0') + << std::setw(CHARS_PER_LAYER_NAME) << i; + tmp_directory_list->push_back( + (*(*p_directory_list)[p_directory_list->size() - 1])[j] + + tmp_stream.str() + "/"); + // std::cout << (*tmp_directory_list)[tmp_directory_list->size() - 1] << + // std::endl; + } } + p_directory_list->push_back(tmp_directory_list); + } } -void VDMSConfig::create_directory_layer(std::vector< std::vector* > *p_directory_list, std::string base_directory) -{ - if( DIRECTORY_LAYERS > 0 ) - { - for(int i = 0; i < p_directory_list->size(); i++) - { - std::vector* tmp_string_vector = (*p_directory_list)[i]; - for(int j = 0; j < tmp_string_vector->size(); j++) - { - check_or_create(base_directory + "/" + (*tmp_string_vector)[j]); - } - } +void VDMSConfig::create_directory_layer( + std::vector *> *p_directory_list, + std::string base_directory) { + if (DIRECTORY_LAYERS > 0) { + for (int i = 0; i < p_directory_list->size(); i++) { + std::vector *tmp_string_vector = (*p_directory_list)[i]; + for (int j = 0; j < tmp_string_vector->size(); j++) { + check_or_create(base_directory + "/" + (*tmp_string_vector)[j]); + } } + } } // This method will check if the dir exists, // and create the dir if it does not exist. -int VDMSConfig::create_dir(std::string path) -{ - struct stat sb; - while (1) - if (stat(path.c_str(), &sb) == 0) - if (sb.st_mode & S_IFDIR) - return 0; - else - return EEXIST; - else if (errno != ENOENT) - return errno; - else if (mkdir(path.c_str(), 0777) == 0) - return 0; - else if (errno != EEXIST) - return errno; +int VDMSConfig::create_dir(std::string path) { + struct stat sb; + while (1) + if (stat(path.c_str(), &sb) == 0) + if (sb.st_mode & S_IFDIR) + return 0; + else + return EEXIST; + else if (errno != ENOENT) + return errno; + else if (mkdir(path.c_str(), 0777) == 0) + return 0; + else if (errno != EEXIST) + return errno; } -void VDMSConfig::check_or_create(std::string path) -{ - if (create_dir(path) == 0){ - return; - } - else{ - std::cout << "Cannot open/create directories structure." << std::endl; - std::cout << "Failed dir: " << path << std::endl; - std::cout << "Check paths and permissions." << std::endl; - std::cout << "Exiting..." << std::endl; - exit(0); - } +void VDMSConfig::check_or_create(std::string path) { + if (create_dir(path) == 0) { + return; + } else { + std::cout << "Cannot open/create directories structure." << std::endl; + std::cout << "Failed dir: " << path << std::endl; + std::cout << "Check paths and permissions." << std::endl; + std::cout << "Exiting..." << std::endl; + exit(0); + } } -void VDMSConfig::build_dirs() -{ - // Root - path_root = get_string_value(PARAM_DB_ROOT, DEFAULT_PATH_ROOT); - check_or_create(path_root); - - // PMGD - path_pmgd = path_root + "/" + DEFAULT_PATH_PMGD; - path_pmgd = get_string_value(PARAM_DB_PMGD, path_pmgd); - check_or_create(path_pmgd); - - // IMAGES - path_images = path_root + "/" + DEFAULT_PATH_IMAGES; - path_images = get_string_value(PARAM_DB_IMAGES, path_images); - check_or_create(path_images); - - std::vector< std::vector* > directory_list; - expand_directory_layer(&directory_list, DIRECTORY_LAYERS); - - // IMAGES - PNG - path_png = path_images + "/" + DEFAULT_PATH_PNG; - path_png = get_string_value(PARAM_DB_PNG, path_png); - check_or_create(path_png); - create_directory_layer(&directory_list, path_png); - - // IMAGES - JPG - path_jpg = path_images + "/" + DEFAULT_PATH_JPG; - path_jpg = get_string_value(PARAM_DB_JPG, path_jpg); - check_or_create(path_jpg); - create_directory_layer(&directory_list, path_jpg); - - // IMAGES - TDB - path_tdb = path_images + "/" + DEFAULT_PATH_TDB; - path_tdb = get_string_value(PARAM_DB_TDB, path_tdb); - check_or_create(path_tdb); - create_directory_layer(&directory_list, path_tdb); - - // IMAGES - BIN - path_bin = path_images + "/" + DEFAULT_PATH_BIN; - path_bin = get_string_value(PARAM_DB_BIN, path_bin); - check_or_create(path_bin); - create_directory_layer(&directory_list, path_bin); - - // BLOBS - path_blobs = path_root + "/" + DEFAULT_PATH_BLOBS; - path_blobs = get_string_value(PARAM_DB_BLOBS, path_blobs); - check_or_create(path_blobs); - create_directory_layer(&directory_list, path_blobs); - - // VIDEOS - path_videos = path_root + "/" + DEFAULT_PATH_VIDEOS; - path_videos = get_string_value(PARAM_DB_VIDEOS, path_videos); - check_or_create(path_videos); - create_directory_layer(&directory_list, path_videos); - - // DESCRIPTORS - path_descriptors = path_root + "/" + DEFAULT_PATH_DESCRIPTORS; - path_descriptors = get_string_value(PARAM_DB_DESCRIPTORS, path_descriptors); - check_or_create(path_descriptors); - - // TMP - path_tmp = "/tmp/" + std::string(DEFAULT_PATH_TMP); - path_tmp = get_string_value(PARAM_DB_TMP, path_tmp); - check_or_create(path_tmp); - create_directory_layer(&directory_list, path_tmp); +void VDMSConfig::build_dirs() { + // Root + path_root = get_string_value(PARAM_DB_ROOT, DEFAULT_PATH_ROOT); + check_or_create(path_root); + + // PMGD + path_pmgd = path_root + "/" + DEFAULT_PATH_PMGD; + path_pmgd = get_string_value(PARAM_DB_PMGD, path_pmgd); + check_or_create(path_pmgd); + + // IMAGES + path_images = path_root + "/" + DEFAULT_PATH_IMAGES; + path_images = get_string_value(PARAM_DB_IMAGES, path_images); + check_or_create(path_images); + + std::vector *> directory_list; + expand_directory_layer(&directory_list, DIRECTORY_LAYERS); + + // IMAGES - PNG + path_png = path_images + "/" + DEFAULT_PATH_PNG; + path_png = get_string_value(PARAM_DB_PNG, path_png); + check_or_create(path_png); + create_directory_layer(&directory_list, path_png); + + // IMAGES - JPG + path_jpg = path_images + "/" + DEFAULT_PATH_JPG; + path_jpg = get_string_value(PARAM_DB_JPG, path_jpg); + check_or_create(path_jpg); + create_directory_layer(&directory_list, path_jpg); + + // IMAGES - TDB + path_tdb = path_images + "/" + DEFAULT_PATH_TDB; + path_tdb = get_string_value(PARAM_DB_TDB, path_tdb); + check_or_create(path_tdb); + create_directory_layer(&directory_list, path_tdb); + + // IMAGES - BIN + path_bin = path_images + "/" + DEFAULT_PATH_BIN; + path_bin = get_string_value(PARAM_DB_BIN, path_bin); + check_or_create(path_bin); + create_directory_layer(&directory_list, path_bin); + + // BLOBS + path_blobs = path_root + "/" + DEFAULT_PATH_BLOBS; + path_blobs = get_string_value(PARAM_DB_BLOBS, path_blobs); + check_or_create(path_blobs); + create_directory_layer(&directory_list, path_blobs); + + // VIDEOS + path_videos = path_root + "/" + DEFAULT_PATH_VIDEOS; + path_videos = get_string_value(PARAM_DB_VIDEOS, path_videos); + check_or_create(path_videos); + create_directory_layer(&directory_list, path_videos); + + // DESCRIPTORS + path_descriptors = path_root + "/" + DEFAULT_PATH_DESCRIPTORS; + path_descriptors = get_string_value(PARAM_DB_DESCRIPTORS, path_descriptors); + check_or_create(path_descriptors); + + // TMP + path_tmp = "/tmp/" + std::string(DEFAULT_PATH_TMP); + path_tmp = get_string_value(PARAM_DB_TMP, path_tmp); + check_or_create(path_tmp); + create_directory_layer(&directory_list, path_tmp); + + // get storage type, set use_aws flag + storage_type = get_string_value(PARAM_STORAGE_TYPE, DEFAULT_STORAGE_TYPE); + if (storage_type == DEFAULT_STORAGE_TYPE) { + aws_flag = false; + } else { + aws_flag = true; + aws_bucket_name = get_string_value(PARAM_BUCKET_NAME, DEFAULT_BUCKET_NAME); + } } diff --git a/src/VDMSConfig.h b/src/VDMSConfig.h index c4e83cb9..7ce7827a 100644 --- a/src/VDMSConfig.h +++ b/src/VDMSConfig.h @@ -31,34 +31,36 @@ #pragma once -#include -#include #include #include #include +#include +#include #include // Parameters in the JSON config file -#define PARAM_DB_ROOT "db_root_path" -#define PARAM_DB_PMGD "pmgd_path" -#define PARAM_DB_IMAGES "images_path" -#define PARAM_DB_PNG "png_path" -#define PARAM_DB_JPG "jpg_path" -#define PARAM_DB_TDB "tdb_path" -#define PARAM_DB_BIN "bin_path" -#define PARAM_DB_BLOBS "blobs_path" -#define PARAM_DB_VIDEOS "videos_path" -#define PARAM_DB_DESCRIPTORS "descriptors_path" -#define PARAM_DB_TMP "tmp_path" - -#define PARAM_NODE_EXPIRATION "expiration_time" +#define PARAM_DB_ROOT "db_root_path" +#define PARAM_DB_PMGD "pmgd_path" +#define PARAM_DB_IMAGES "images_path" +#define PARAM_DB_PNG "png_path" +#define PARAM_DB_JPG "jpg_path" +#define PARAM_DB_TDB "tdb_path" +#define PARAM_DB_BIN "bin_path" +#define PARAM_DB_BLOBS "blobs_path" +#define PARAM_DB_VIDEOS "videos_path" +#define PARAM_DB_DESCRIPTORS "descriptors_path" +#define PARAM_DB_TMP "tmp_path" +#define PARAM_STORAGE_TYPE "storage_type" +#define PARAM_BUCKET_NAME "bucket_name" + +#define PARAM_NODE_EXPIRATION "expiration_time" #define DEFAULT_NODE_EXPIRATION 0 // Parameters used to determine depth and breadth of directory structure -//take parameters from command line if they are supplied +// take parameters from command line if they are supplied #ifndef DIRECTORIES_PER_LAYER - #define DIRECTORIES_PER_LAYER 5 +#define DIRECTORIES_PER_LAYER 5 #endif #ifndef DIRECTORY_LAYERS @@ -69,62 +71,67 @@ #define CHARS_PER_LAYER_NAME 3 #endif - - - - - -#define PARAM_PMGD_NUM_ALLOCATORS "pmgd_num_allocators" +#define PARAM_PMGD_NUM_ALLOCATORS "pmgd_num_allocators" #define DEFAULT_PMGD_NUM_ALLOCATORS 1 -namespace VDMS{ - - class VDMSConfig - { - - public: - static bool init(std::string config_file); - static void destroy(); - static VDMSConfig* instance(); - - private: - static VDMSConfig* cfg; - Json::Value json_config; - - // Dirs - std::string path_root; - std::string path_pmgd; - std::string path_images; - std::string path_png; - std::string path_jpg; - std::string path_bin; - std::string path_tdb; - std::string path_blobs; - std::string path_videos; - std::string path_descriptors; - std::string path_tmp; - - VDMSConfig(std::string config_file); - - void expand_directory_layer(std::vector< std::vector* > *p_directory_list, int current_layer); - void create_directory_layer(std::vector< std::vector* > *p_directory_list, std::string base_directory); - void build_dirs(); - void check_or_create(std::string path); - int create_dir(std::string path); - - public: - int get_int_value(std::string val, int def); - std::string get_string_value(std::string val, std::string def); - const std::string& get_path_root() {return path_root;} - const std::string& get_path_pmgd() {return path_pmgd;} - const std::string& get_path_jpg() {return path_jpg;} - const std::string& get_path_png() {return path_png;} - const std::string& get_path_bin() {return path_bin;} - const std::string& get_path_tdb() {return path_tdb;} - const std::string& get_path_blobs() {return path_blobs;} - const std::string& get_path_videos(){return path_videos;} - const std::string& get_path_descriptors() {return path_descriptors;} - const std::string& get_path_tmp() {return path_tmp;} - }; - -}; // vdms namespace +namespace VDMS { + +class VDMSConfig { + +public: + static bool init(std::string config_file); + static void destroy(); + static VDMSConfig *instance(); + +private: + static VDMSConfig *cfg; + Json::Value json_config; + + // Dirs + std::string path_root; + std::string path_pmgd; + std::string path_images; + std::string path_png; + std::string path_jpg; + std::string path_bin; + std::string path_tdb; + std::string path_blobs; + std::string path_videos; + std::string path_descriptors; + std::string path_tmp; + std::string storage_type; + + bool aws_flag; // use aws flag + std::string aws_bucket_name; // aws bucket name + + VDMSConfig(std::string config_file); + + void expand_directory_layer( + std::vector *> *p_directory_list, + int current_layer); + void create_directory_layer( + std::vector *> *p_directory_list, + std::string base_directory); + void build_dirs(); + void check_or_create(std::string path); + int create_dir(std::string path); + +public: + int get_int_value(std::string val, int def); + std::string get_string_value(std::string val, std::string def); + const std::string &get_path_root() { return path_root; } + const std::string &get_path_pmgd() { return path_pmgd; } + const std::string &get_path_jpg() { return path_jpg; } + const std::string &get_path_png() { return path_png; } + const std::string &get_path_bin() { return path_bin; } + const std::string &get_path_tdb() { return path_tdb; } + const std::string &get_path_blobs() { return path_blobs; } + const std::string &get_path_videos() { return path_videos; } + const std::string &get_path_descriptors() { return path_descriptors; } + const std::string &get_path_tmp() { return path_tmp; } + const std::string &get_storage_type() { return storage_type; } + const std::string &get_bucket_name() { return aws_bucket_name; } + const bool get_aws_flag() { return aws_flag; } +}; + +}; // namespace VDMS diff --git a/src/VideoCommand.cc b/src/VideoCommand.cc index f77f1899..010ad307 100644 --- a/src/VideoCommand.cc +++ b/src/VideoCommand.cc @@ -29,581 +29,555 @@ * */ -#include +#include #include +#include #include "ImageCommand.h" // for enqueue_operations of Image type -#include "VideoCommand.h" #include "VDMSConfig.h" +#include "VideoCommand.h" #include "defines.h" using namespace VDMS; +namespace fs = std::filesystem; -VideoCommand::VideoCommand(const std::string &cmd_name): - RSCommand(cmd_name) -{ -} +VideoCommand::VideoCommand(const std::string &cmd_name) : RSCommand(cmd_name) {} -void VideoCommand::enqueue_operations(VCL::Video& video, const Json::Value& ops) -{ - // Correct operation type and parameters are guaranteed at this point - for (auto& op : ops) { - const std::string& type = get_value(op, "type"); - std::string unit ; - if (type == "threshold") { - video.threshold(get_value(op, "value")); +void VideoCommand::enqueue_operations(VCL::Video &video, + const Json::Value &ops) { + // Correct operation type and parameters are guaranteed at this point + for (auto &op : ops) { + const std::string &type = get_value(op, "type"); + std::string unit; + if (type == "threshold") { + video.threshold(get_value(op, "value")); - } - else if (type == "interval") { + } else if (type == "interval") { - video.interval( - VCL::Video::FRAMES, - get_value(op, "start"), - get_value(op, "stop"), - get_value(op, "step")); + video.interval(VCL::Video::FRAMES, get_value(op, "start"), + get_value(op, "stop"), get_value(op, "step")); - } - else if (type == "resize") { - video.resize(get_value(op, "height"), - get_value(op, "width") ); + } else if (type == "resize") { + video.resize(get_value(op, "height"), get_value(op, "width")); - } - else if (type == "crop") { - video.crop(VCL::Rectangle ( - get_value(op, "x"), - get_value(op, "y"), - get_value(op, "width"), - get_value(op, "height") )); - } - else { - throw ExceptionCommand(ImageError, "Operation not defined"); - } + } else if (type == "crop") { + video.crop(VCL::Rectangle( + get_value(op, "x"), get_value(op, "y"), + get_value(op, "width"), get_value(op, "height"))); + } else { + throw ExceptionCommand(ImageError, "Operation not defined"); } + } } -VCL::Video::Codec VideoCommand::string_to_codec(const std::string& codec) -{ - if (codec == "h263") { - return VCL::Video::Codec::H263; - } - else if (codec == "xvid") { - return VCL::Video::Codec::XVID; - } - else if (codec == "h264") { - return VCL::Video::Codec::H264; - } +VCL::Video::Codec VideoCommand::string_to_codec(const std::string &codec) { + if (codec == "h263") { + return VCL::Video::Codec::H263; + } else if (codec == "xvid") { + return VCL::Video::Codec::XVID; + } else if (codec == "h264") { + return VCL::Video::Codec::H264; + } - return VCL::Video::Codec::NOCODEC; + return VCL::Video::Codec::NOCODEC; } -Json::Value VideoCommand::check_responses(Json::Value& responses) -{ - if (responses.size() != 1) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "PMGD Response Bad Size"; - return return_error; - } +Json::Value VideoCommand::check_responses(Json::Value &responses) { + if (responses.size() != 1) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "PMGD Response Bad Size"; + return return_error; + } - Json::Value& response = responses[0]; - - if (response["status"] != 0) { - response["status"] = RSCommand::Error; - // Uses PMGD info error. - return response; - } + Json::Value &response = responses[0]; + if (response["status"] != 0) { + response["status"] = RSCommand::Error; + // Uses PMGD info error. return response; + } + + return response; } //========= AddVideo definitions ========= -AddVideo::AddVideo() : VideoCommand("AddVideo") -{ - _storage_video = VDMSConfig::instance()->get_path_videos(); +AddVideo::AddVideo() : VideoCommand("AddVideo") { + _storage_video = VDMSConfig::instance()->get_path_videos(); + //_use_aws_storage = VDMSConfig::instance()->get_aws_flag(); } -int AddVideo::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - int node_ref = get_value(cmd, "_ref", - query.get_available_reference()); - - const std::string from_server_file = get_value(cmd, - "from_server_file", ""); - VCL::Video video; - if (from_server_file.empty()) - video = VCL::Video((void*)blob.data(), blob.size()); - else - video = VCL::Video(from_server_file); - - - // Key frame extraction works on binary stream data, without encoding. We - // check whether key-frame extraction is to be applied, and if so, we - // extract the frames before any other operations are applied. Applying - // key-frame extraction after applying pending operations will be - // non-optimal: the video will be decoded while performing the operations. - VCL::KeyFrameList frame_list; - if (get_value(cmd, "index_frames", false)) - frame_list = video.get_key_frame_list(); - - if (cmd.isMember("operations")) { - enqueue_operations(video, cmd["operations"]); - } - - // The container and codec are checked by the schema. - // We default to mp4 and h264, if not specified - const std::string& container = - get_value(cmd, "container", "mp4"); - const std::string& file_name = - VCL::create_unique(_storage_video, container); - - // Modifiyng the existing properties that the user gives - // is a good option to make the AddNode more simple. - // This is not ideal since we are manupulating with user's - // input, but for now it is an acceptable solution. - Json::Value props = get_value(cmd, "properties"); - props[VDMS_VID_PATH_PROP] = file_name; - - // Add Video node - query.AddNode(node_ref, VDMS_VID_TAG, props, Json::Value()); - - const std::string& codec = get_value(cmd, "codec", "h264"); - VCL::Video::Codec vcl_codec = string_to_codec(codec); - - video.store(file_name, vcl_codec); - - // Add key-frames (if extracted) as nodes connected to the video - for (const auto &frame : frame_list) { - Json::Value frame_props; - frame_props[VDMS_KF_IDX_PROP] = static_cast(frame.idx); - frame_props[VDMS_KF_BASE_PROP] = static_cast (frame.base); - - int frame_ref = query.get_available_reference(); - query.AddNode(frame_ref, VDMS_KF_TAG, frame_props, - Json::Value()); - query.AddEdge(-1, node_ref, frame_ref, VDMS_KF_EDGE, - Json::Value()); - } - - // In case we need to cleanup the query - error["video_added"] = file_name; - - if (cmd.isMember("link")) { - add_link(query, cmd["link"], node_ref, VDMS_VID_EDGE); - } - - return 0; +int AddVideo::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; + + int node_ref = get_value(cmd, "_ref", query.get_available_reference()); + + const std::string from_server_file = + get_value(cmd, "from_server_file", ""); + VCL::Video video; + + if (_use_aws_storage) { + VCL::RemoteConnection *connection = new VCL::RemoteConnection(); + std::string bucket = VDMSConfig::instance()->get_bucket_name(); + connection->_bucket_name = bucket; + video.set_connection(connection); + } + + if (from_server_file.empty()) + video = VCL::Video((void *)blob.data(), blob.size()); + else + video = VCL::Video(from_server_file); + + // Key frame extraction works on binary stream data, without encoding. We + // check whether key-frame extraction is to be applied, and if so, we + // extract the frames before any other operations are applied. Applying + // key-frame extraction after applying pending operations will be + // non-optimal: the video will be decoded while performing the operations. + VCL::KeyFrameList frame_list; + if (get_value(cmd, "index_frames", false)) + frame_list = video.get_key_frame_list(); + + if (cmd.isMember("operations")) { + enqueue_operations(video, cmd["operations"]); + } + + // The container and codec are checked by the schema. + // We default to mp4 and h264, if not specified + const std::string &container = + get_value(cmd, "container", "mp4"); + const std::string &file_name = VCL::create_unique(_storage_video, container); + + // Modifiyng the existing properties that the user gives + // is a good option to make the AddNode more simple. + // This is not ideal since we are manupulating with user's + // input, but for now it is an acceptable solution. + Json::Value props = get_value(cmd, "properties"); + props[VDMS_VID_PATH_PROP] = file_name; + + // Add Video node + query.AddNode(node_ref, VDMS_VID_TAG, props, Json::Value()); + + const std::string &codec = get_value(cmd, "codec", "h264"); + VCL::Video::Codec vcl_codec = string_to_codec(codec); + + video.store(file_name, vcl_codec); + + if (_use_aws_storage) { + video._remote->Write(file_name); + std::remove(file_name.c_str()); // remove the local copy of the file + } + + // Add key-frames (if extracted) as nodes connected to the video + for (const auto &frame : frame_list) { + Json::Value frame_props; + frame_props[VDMS_KF_IDX_PROP] = static_cast(frame.idx); + frame_props[VDMS_KF_BASE_PROP] = static_cast(frame.base); + + int frame_ref = query.get_available_reference(); + query.AddNode(frame_ref, VDMS_KF_TAG, frame_props, Json::Value()); + query.AddEdge(-1, node_ref, frame_ref, VDMS_KF_EDGE, Json::Value()); + } + + // In case we need to cleanup the query + error["video_added"] = file_name; + + if (cmd.isMember("link")) { + add_link(query, cmd["link"], node_ref, VDMS_VID_EDGE); + } + + return 0; } -Json::Value AddVideo::construct_responses( - Json::Value& response, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string& blob) -{ - Json::Value ret; - ret[_cmd_name] = RSCommand::check_responses(response); +Json::Value AddVideo::construct_responses(Json::Value &response, + const Json::Value &json, + protobufs::queryMessage &query_res, + const std::string &blob) { + Json::Value ret; + ret[_cmd_name] = RSCommand::check_responses(response); - return ret; + return ret; } -bool AddVideo::need_blob(const Json::Value& cmd) -{ - const Json::Value& add_video_cmd = cmd[_cmd_name]; - return !(add_video_cmd.isMember("from_server_file")); +bool AddVideo::need_blob(const Json::Value &cmd) { + const Json::Value &add_video_cmd = cmd[_cmd_name]; + return !(add_video_cmd.isMember("from_server_file")); } //========= UpdateVideo definitions ========= -UpdateVideo::UpdateVideo() : VideoCommand("UpdateVideo") -{ -} +UpdateVideo::UpdateVideo() : VideoCommand("UpdateVideo") {} -int UpdateVideo::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; +int UpdateVideo::construct_protobuf(PMGDQuery &query, + const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - int node_ref = get_value(cmd, "_ref", -1); + int node_ref = get_value(cmd, "_ref", -1); - Json::Value constraints = get_value(cmd, "constraints"); + Json::Value constraints = get_value(cmd, "constraints"); - Json::Value props = get_value(cmd, "properties"); + Json::Value props = get_value(cmd, "properties"); - Json::Value remove_props = get_value(cmd, "remove_props"); + Json::Value remove_props = get_value(cmd, "remove_props"); - // Update Image node - query.UpdateNode(node_ref, VDMS_VID_TAG, props, - remove_props, - constraints, - get_value(cmd, "unique", false)); + // Update Image node + query.UpdateNode(node_ref, VDMS_VID_TAG, props, remove_props, constraints, + get_value(cmd, "unique", false)); - return 0; + return 0; } -Json::Value UpdateVideo::construct_responses( - Json::Value& responses, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - assert(responses.size() == 1); +Json::Value UpdateVideo::construct_responses(Json::Value &responses, + const Json::Value &json, + protobufs::queryMessage &query_res, + const std::string &blob) { + assert(responses.size() == 1); - Json::Value ret; + Json::Value ret; - // TODO In order to support "codec" or "operations", we could - // implement VCL save operation here. + // TODO In order to support "codec" or "operations", we could + // implement VCL save operation here. - ret[_cmd_name].swap(responses[0]); - return ret; + ret[_cmd_name].swap(responses[0]); + return ret; } //========= FindVideo definitions ========= -FindVideo::FindVideo() : VideoCommand("FindVideo") -{ +FindVideo::FindVideo() : VideoCommand("FindVideo") { + //_use_aws_storage = VDMSConfig::instance()->get_aws_flag(); } -int FindVideo::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; +int FindVideo::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - Json::Value results = get_value(cmd, "results"); + Json::Value results = get_value(cmd, "results"); - // Unless otherwhise specified, we return the blob. - if (get_value(results, "blob", true)){ - results["list"].append(VDMS_VID_PATH_PROP); - } + // Unless otherwhise specified, we return the blob. + if (get_value(results, "blob", true)) { + results["list"].append(VDMS_VID_PATH_PROP); + } - query.QueryNode( - get_value(cmd, "_ref", -1), - VDMS_VID_TAG, - cmd["link"], - cmd["constraints"], - results, - get_value(cmd, "unique", false) - ); + query.QueryNode(get_value(cmd, "_ref", -1), VDMS_VID_TAG, cmd["link"], + cmd["constraints"], results, + get_value(cmd, "unique", false)); - return 0; + return 0; } -Json::Value FindVideo::construct_responses( - Json::Value& responses, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - const Json::Value& cmd = json[_cmd_name]; - - Json::Value ret; - - auto error = [&](Json::Value& res) - { - ret[_cmd_name] = res; - return ret; - }; - - Json::Value resp = check_responses(responses); - if (resp["status"] != RSCommand::Success) { - return error(resp); - } +Json::Value FindVideo::construct_responses(Json::Value &responses, + const Json::Value &json, + protobufs::queryMessage &query_res, + const std::string &blob) { + const Json::Value &cmd = json[_cmd_name]; + + Json::Value ret; + + auto error = [&](Json::Value &res) { + ret[_cmd_name] = res; + return ret; + }; - Json::Value& FindVideo = responses[0]; + Json::Value resp = check_responses(responses); + if (resp["status"] != RSCommand::Success) { + return error(resp); + } - bool flag_empty = true; + Json::Value &FindVideo = responses[0]; - for (auto& ent : FindVideo["entities"]) { + bool flag_empty = true; - if(!ent.isMember(VDMS_VID_PATH_PROP)){ - continue; + for (auto &ent : FindVideo["entities"]) { + + if (!ent.isMember(VDMS_VID_PATH_PROP)) { + continue; + } + + std::string video_path = ent[VDMS_VID_PATH_PROP].asString(); + ent.removeMember(VDMS_VID_PATH_PROP); + + if (ent.getMemberNames().size() > 0) { + flag_empty = false; + } + try { + if (!cmd.isMember("operations") && !cmd.isMember("container") && + !cmd.isMember("codec")) { + // grab the video from aws and put it where vdms expects it + if (_use_aws_storage) { + VCL::RemoteConnection *connection = new VCL::RemoteConnection(); + std::string bucket = VDMSConfig::instance()->get_bucket_name(); + connection->_bucket_name = bucket; + VCL::Video video(video_path); + video.set_connection(connection); + video._remote->Read_Video( + video_path); // this takes the file from aws and puts it back in + // the local database location } - std::string video_path = ent[VDMS_VID_PATH_PROP].asString(); - ent.removeMember(VDMS_VID_PATH_PROP); + // Return video as is. + std::ifstream ifile(video_path, std::ifstream::in); + ifile.seekg(0, std::ios::end); + size_t encoded_size = (long)ifile.tellg(); + ifile.seekg(0, std::ios::beg); - if (ent.getMemberNames().size() > 0) { - flag_empty = false; + std::string *video_str = query_res.add_blobs(); + video_str->resize(encoded_size); + ifile.read((char *)(video_str->data()), encoded_size); + ifile.close(); + + if (_use_aws_storage) { + bool result = fs::remove(video_path); } - try { - if (!cmd.isMember("operations") && - !cmd.isMember("container") && - !cmd.isMember("codec")) - { - // Return video as is. - std::ifstream ifile(video_path, std::ifstream::in); - ifile.seekg(0, std::ios::end); - size_t encoded_size = (long)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - - std::string* video_str = query_res.add_blobs(); - video_str->resize(encoded_size); - ifile.read((char*)(video_str->data()), encoded_size); - ifile.close(); - } - else { - - VCL::Video video(video_path); - - if (cmd.isMember("operations")) { - enqueue_operations(video, cmd["operations"]); - } - - const std::string& container = - get_value(cmd, "container", "mp4"); - const std::string& file_name = - VCL::create_unique("/tmp/tmp/", container); - const std::string& codec = - get_value(cmd, "codec", "h264"); - - VCL::Video::Codec vcl_codec = string_to_codec(codec); - video.store(file_name, vcl_codec); // to /tmp/ for encoding. - - auto video_enc = video.get_encoded(); - int size = video_enc.size(); - - if (size > 0) { - - std::string* video_str = query_res.add_blobs(); - video_str->resize(size); - std::memcpy((void*)video_str->data(), - (void*)video_enc.data(), - size); - } - else { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Video Data not found"; - error(return_error); - } - } - } catch (VCL::Exception e) { - print_exception(e); - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "VCL Exception"; - return error(return_error); + } else { + VCL::Video video(video_path); + + if (cmd.isMember("operations")) { + enqueue_operations(video, cmd["operations"]); } - } - if (flag_empty) { - FindVideo.removeMember("entities"); + const std::string &container = + get_value(cmd, "container", "mp4"); + const std::string &file_name = + VCL::create_unique("/tmp/tmp/", container); + const std::string &codec = get_value(cmd, "codec", "h264"); + + VCL::Video::Codec vcl_codec = string_to_codec(codec); + video.store(file_name, vcl_codec); // to /tmp/ for encoding. + + auto video_enc = video.get_encoded(); + int size = video_enc.size(); + + if (size > 0) { + + std::string *video_str = query_res.add_blobs(); + video_str->resize(size); + std::memcpy((void *)video_str->data(), (void *)video_enc.data(), + size); + } else { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Video Data not found"; + error(return_error); + } + } + } catch (VCL::Exception e) { + print_exception(e); + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "VCL Exception"; + return error(return_error); } + } - ret[_cmd_name].swap(FindVideo); - return ret; + if (flag_empty) { + FindVideo.removeMember("entities"); + } + + ret[_cmd_name].swap(FindVideo); + return ret; } //========= FindFrames definitions ========= -FindFrames::FindFrames() : VideoCommand("FindFrames") -{ +FindFrames::FindFrames() : VideoCommand("FindFrames") { + //_use_aws_storage = VDMSConfig::instance()->get_aws_flag(); } -bool FindFrames::get_interval_index (const Json::Value& cmd, - Json::ArrayIndex& op_index) -{ - if (cmd.isMember("operations")) { - const auto operations = cmd["operations"]; - for (auto i = 0; i < operations.size(); i++) { - const auto op = operations[i]; - const std::string& type = get_value(op, "type"); - if (type == "interval") { - op_index = i; - return true; - } - } +bool FindFrames::get_interval_index(const Json::Value &cmd, + Json::ArrayIndex &op_index) { + if (cmd.isMember("operations")) { + const auto operations = cmd["operations"]; + for (auto i = 0; i < operations.size(); i++) { + const auto op = operations[i]; + const std::string &type = get_value(op, "type"); + if (type == "interval") { + op_index = i; + return true; + } } - return false; + } + return false; } -int FindFrames::construct_protobuf( - PMGDQuery& query, - const Json::Value& jsoncmd, - const std::string& blob, - int grp_id, - Json::Value& error) -{ - const Json::Value& cmd = jsoncmd[_cmd_name]; - - // We try to catch the missing attribute error before - // initiating a PMGD query - Json::ArrayIndex tmp; - bool is_interval = get_interval_index(cmd, tmp); - bool is_frames = cmd.isMember("frames"); - - if (!(is_frames != is_interval)) { - error["status"] = RSCommand::Error; - error["info"] = "Either one of 'frames' or 'operations::interval' " - "must be specified"; - return -1; - } +int FindFrames::construct_protobuf(PMGDQuery &query, const Json::Value &jsoncmd, + const std::string &blob, int grp_id, + Json::Value &error) { + const Json::Value &cmd = jsoncmd[_cmd_name]; - Json::Value results = get_value(cmd, "results"); - results["list"].append(VDMS_VID_PATH_PROP); + // We try to catch the missing attribute error before + // initiating a PMGD query + Json::ArrayIndex tmp; + bool is_interval = get_interval_index(cmd, tmp); + bool is_frames = cmd.isMember("frames"); + + if (!(is_frames != is_interval)) { + error["status"] = RSCommand::Error; + error["info"] = "Either one of 'frames' or 'operations::interval' " + "must be specified"; + return -1; + } - query.QueryNode( - get_value(cmd, "_ref", -1), - VDMS_VID_TAG, - cmd["link"], - cmd["constraints"], - results, - get_value(cmd, "unique", false) - ); + Json::Value results = get_value(cmd, "results"); + results["list"].append(VDMS_VID_PATH_PROP); - return 0; + query.QueryNode(get_value(cmd, "_ref", -1), VDMS_VID_TAG, cmd["link"], + cmd["constraints"], results, + get_value(cmd, "unique", false)); + + return 0; } -Json::Value FindFrames::construct_responses( - Json::Value& responses, - const Json::Value& json, - protobufs::queryMessage &query_res, - const std::string &blob) -{ - const Json::Value& cmd = json[_cmd_name]; - - Json::Value ret; - - auto error = [&](Json::Value& res) - { - ret[_cmd_name] = res; - return ret; - }; - - Json::Value resp = check_responses(responses); - if (resp["status"] != RSCommand::Success) { - return error(resp); +Json::Value FindFrames::construct_responses(Json::Value &responses, + const Json::Value &json, + protobufs::queryMessage &query_res, + const std::string &blob) { + const Json::Value &cmd = json[_cmd_name]; + + Json::Value ret; + + auto error = [&](Json::Value &res) { + ret[_cmd_name] = res; + return ret; + }; + + Json::Value resp = check_responses(responses); + if (resp["status"] != RSCommand::Success) { + return error(resp); + } + + Json::Value &FindFrames = responses[0]; + + bool flag_empty = true; + + for (auto &ent : FindFrames["entities"]) { + + std::string video_path = ent[VDMS_VID_PATH_PROP].asString(); + ent.removeMember(VDMS_VID_PATH_PROP); + + if (ent.getMemberNames().size() > 0) { + flag_empty = false; } - Json::Value& FindFrames = responses[0]; + try { + std::vector frames; - bool flag_empty = true; + // Copy of operations is needed, as we pass the operations to + // the enqueue_operations() method of ImageCommands class, and + // it should not include 'interval' operation. + Json::Value operations = cmd["operations"]; - for (auto& ent : FindFrames["entities"]) { + Json::ArrayIndex interval_idx; + bool is_interval = get_interval_index(cmd, interval_idx); + bool is_frames = cmd.isMember("frames"); - std::string video_path = ent[VDMS_VID_PATH_PROP].asString(); - ent.removeMember(VDMS_VID_PATH_PROP); + if (is_frames) { + for (auto &fr : cmd["frames"]) { + frames.push_back(fr.asUInt()); + } + } else if (is_interval) { - if (ent.getMemberNames().size() > 0) { - flag_empty = false; + Json::Value interval_op = operations[interval_idx]; + + int start = get_value(interval_op, "start"); + int stop = get_value(interval_op, "stop"); + int step = get_value(interval_op, "step"); + + for (int i = start; i < stop; i += step) { + frames.push_back(i); + } + + Json::Value deleted; + operations.removeIndex(interval_idx, &deleted); + } else { + // This should never happen, as we check this condition in + // FindFrames::construct_protobuf(). In case this happens, it + // is better to signal it rather than to continue + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "No 'frames' or 'interval' parameter"; + return error(return_error); + } + + VCL::Video video(video_path); + + // grab the video from aws here if necessary + if (_use_aws_storage) { + VCL::RemoteConnection *connection = new VCL::RemoteConnection(); + std::string bucket = VDMSConfig::instance()->get_bucket_name(); + connection->_bucket_name = bucket; + VCL::Video video(video_path); + video.set_connection(connection); + video._remote->Read_Video( + video_path); // this takes the file from aws and puts it back in the + // local database location + } + + // By default, return frames as PNGs + VCL::Image::Format format = VCL::Image::Format::PNG; + + FindImage img_cmd; + + if (cmd.isMember("format")) { + + format = img_cmd.get_requested_format(cmd); + + if (format == VCL::Image::Format::NONE_IMAGE || + format == VCL::Image::Format::TDB) { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Invalid Return Format for FindFrames"; + return error(return_error); } + } - try { - std::vector frames; - - // Copy of operations is needed, as we pass the operations to - // the enqueue_operations() method of ImageCommands class, and - // it should not include 'interval' operation. - Json::Value operations = cmd["operations"]; - - Json::ArrayIndex interval_idx; - bool is_interval = get_interval_index(cmd, interval_idx); - bool is_frames = cmd.isMember("frames"); - - if (is_frames) { - for (auto& fr : cmd["frames"]) { - frames.push_back(fr.asUInt()); - } - } - else if (is_interval) { - - Json::Value interval_op = operations[interval_idx]; - - int start = get_value(interval_op, "start"); - int stop = get_value(interval_op, "stop"); - int step = get_value(interval_op, "step"); - - for (int i = start; i < stop; i += step) { - frames.push_back(i); - } - - Json::Value deleted; - operations.removeIndex(interval_idx, &deleted); - } - else { - // This should never happen, as we check this condition in - // FindFrames::construct_protobuf(). In case this happens, it - // is better to signal it rather than to continue - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "No 'frames' or 'interval' parameter"; - return error(return_error); - } - - VCL::Video video(video_path); - - // By default, return frames as PNGs - VCL::Image::Format format = VCL::Image::Format::PNG; - - FindImage img_cmd; - - if (cmd.isMember("format")) { - - format = img_cmd.get_requested_format(cmd); - - if (format == VCL::Image::Format::NONE_IMAGE || - format == VCL::Image::Format::TDB) { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Invalid Return Format for FindFrames"; - return error(return_error); - } - } - - for (auto idx : frames) { - cv::Mat mat = video.get_frame(idx); - VCL::Image img(mat, false); - if (!operations.empty()) { - img_cmd.enqueue_operations(img, operations); - } - - std::vector img_enc; - img_enc = img.get_encoded_image(format); - - if (!img_enc.empty()) { - std::string* img_str = query_res.add_blobs(); - img_str->resize(img_enc.size()); - std::memcpy((void*)img_str->data(), - (void*)img_enc.data(), - img_enc.size()); - } - else { - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "Image Data not found"; - return error(return_error); - } - } + for (auto idx : frames) { + cv::Mat mat = video.get_frame(idx); + VCL::Image img(mat, false); + if (!operations.empty()) { + img_cmd.enqueue_operations(img, operations); } - catch (VCL::Exception e) { - print_exception(e); - Json::Value return_error; - return_error["status"] = RSCommand::Error; - return_error["info"] = "VCL Exception"; - return error(return_error); + std::vector img_enc; + img_enc = img.get_encoded_image(format); + + if (!img_enc.empty()) { + std::string *img_str = query_res.add_blobs(); + img_str->resize(img_enc.size()); + std::memcpy((void *)img_str->data(), (void *)img_enc.data(), + img_enc.size()); + } else { + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "Image Data not found"; + return error(return_error); } + } + + // delete the video from local storage here, done with it for now + if (_use_aws_storage) { + std::remove(video_path.c_str()); + } } - if (flag_empty) { - FindFrames.removeMember("entities"); + catch (VCL::Exception e) { + print_exception(e); + Json::Value return_error; + return_error["status"] = RSCommand::Error; + return_error["info"] = "VCL Exception"; + return error(return_error); } + } - ret[_cmd_name].swap(FindFrames); - return ret; + if (flag_empty) { + FindFrames.removeMember("entities"); + } + + ret[_cmd_name].swap(FindFrames); + return ret; } diff --git a/src/VideoCommand.h b/src/VideoCommand.h index 248f33cc..becbb173 100644 --- a/src/VideoCommand.h +++ b/src/VideoCommand.h @@ -30,117 +30,101 @@ */ #pragma once -#include +#include "vcl/Video.h" #include +#include #include -#include "vcl/Video.h" -#include "RSCommand.h" #include "ExceptionsCommand.h" +#include "RSCommand.h" namespace VDMS { // Helper classes for handling various JSON commands. - class VideoCommand: public RSCommand - { - protected: - void enqueue_operations(VCL::Video& video, const Json::Value& op); - - VCL::Video::Codec string_to_codec(const std::string& codec); - - virtual Json::Value check_responses(Json::Value& responses); - - public: - - VideoCommand(const std::string &cmd_name); - - virtual int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error) = 0; - - virtual bool need_blob(const Json::Value& cmd) { return false; } - }; - - class AddVideo: public VideoCommand - { - const std::string DEFAULT_VIDEO_PATH = "videos/database"; - - std::string _storage_video; - - public: - AddVideo(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - Json::Value construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - - bool need_blob(const Json::Value& cmd); - }; - - class UpdateVideo: public VideoCommand - { - public: - UpdateVideo(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - Json::Value construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - }; - - class FindVideo: public VideoCommand - { - public: - FindVideo(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error); - - Json::Value construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob); - }; - - class FindFrames: public VideoCommand - { - bool get_interval_index (const Json::Value& cmd, Json::ArrayIndex& op_index); - public: - FindFrames(); - - int construct_protobuf(PMGDQuery& tx, - const Json::Value& root, - const std::string& blob, - int grp_id, - Json::Value& error) override; - - Json::Value construct_responses( - Json::Value &json_responses, - const Json::Value &json, - protobufs::queryMessage &response, - const std::string &blob) override; - }; +class VideoCommand : public RSCommand { +protected: + void enqueue_operations(VCL::Video &video, const Json::Value &op); + + VCL::Video::Codec string_to_codec(const std::string &codec); + + virtual Json::Value check_responses(Json::Value &responses); + +public: + VideoCommand(const std::string &cmd_name); + + virtual int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error) = 0; + + virtual bool need_blob(const Json::Value &cmd) { return false; } +}; + +class AddVideo : public VideoCommand { + const std::string DEFAULT_VIDEO_PATH = "videos/database"; + std::string _storage_video; + // bool _use_aws_storage; + +public: + AddVideo(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); + + bool need_blob(const Json::Value &cmd); +}; + +class UpdateVideo : public VideoCommand { +public: + UpdateVideo(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; + +class FindVideo : public VideoCommand { + // bool _use_aws_storage; + +public: + FindVideo(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error); + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob); +}; + +class FindFrames : public VideoCommand { + // bool _use_aws_storage; + bool get_interval_index(const Json::Value &cmd, Json::ArrayIndex &op_index); + +public: + FindFrames(); + + int construct_protobuf(PMGDQuery &tx, const Json::Value &root, + const std::string &blob, int grp_id, + Json::Value &error) override; + + Json::Value construct_responses(Json::Value &json_responses, + const Json::Value &json, + protobufs::queryMessage &response, + const std::string &blob) override; +}; }; // namespace VDMS diff --git a/src/defines.h b/src/defines.h index 0a76b97a..5494e53d 100644 --- a/src/defines.h +++ b/src/defines.h @@ -33,66 +33,66 @@ // (RSCommand.cc, ImageCommand.cc, DescriptorsCommand.cc) /* Some conventions: -* Must start with VD: (not VDMS since we have a 16 char limit) -* Tags (for nodes and edges) are all upper case. -* Properties are cammel case, where the first word is lower case. -*/ + * Must start with VD: (not VDMS since we have a 16 char limit) + * Tags (for nodes and edges) are all upper case. + * Properties are cammel case, where the first word is lower case. + */ // General -#define VDMS_GENERIC_LINK "VD:LINK" +#define VDMS_GENERIC_LINK "VD:LINK" // Entities #define VDMS_EN_BLOB_PATH_PROP "VD:blobPath" -#define VDMS_BLOB_TAG "VD:BLOB" -#define VDMS_BLOB_EDGE_TAG "VD:BLOBLINK" +#define VDMS_BLOB_TAG "VD:BLOB" +#define VDMS_BLOB_EDGE_TAG "VD:BLOBLINK" // Images -#define VDMS_IM_TAG "VD:IMG" -#define VDMS_IM_EDGE_TAG "VD:IMGLINK" -#define VDMS_IM_PATH_PROP "VD:imgPath" +#define VDMS_IM_TAG "VD:IMG" +#define VDMS_IM_EDGE_TAG "VD:IMGLINK" +#define VDMS_IM_PATH_PROP "VD:imgPath" // Descriptor Set -#define VDMS_DESC_SET_TAG "VD:DESCSET" -#define VDMS_DESC_SET_EDGE_TAG "VD:DESCSETLINK" // link between set and desc +#define VDMS_DESC_SET_TAG "VD:DESCSET" +#define VDMS_DESC_SET_EDGE_TAG "VD:DESCSETLINK" // link between set and desc #define VDMS_DESC_SET_PATH_PROP "VD:descSetPath" #define VDMS_DESC_SET_NAME_PROP "VD:name" -#define VDMS_DESC_SET_DIM_PROP "VD:dimensions" +#define VDMS_DESC_SET_DIM_PROP "VD:dimensions" // Descriptor -#define VDMS_DESC_TAG "VD:DESC" -#define VDMS_DESC_EDGE_TAG "VD:DESCLINK" -#define VDMS_DESC_LABEL_PROP "VD:label" -#define VDMS_DESC_ID_PROP "VD:descId" +#define VDMS_DESC_TAG "VD:DESC" +#define VDMS_DESC_EDGE_TAG "VD:DESCLINK" +#define VDMS_DESC_LABEL_PROP "VD:label" +#define VDMS_DESC_ID_PROP "VD:descId" -#define VDMS_DESC_LABEL_TAG "VD:DESCLABEL" +#define VDMS_DESC_LABEL_TAG "VD:DESCLABEL" #define VDMS_DESC_LABEL_NAME_PROP "VD:labelName" -#define VDMS_DESC_LABEL_ID_PROP "VD:labelId" +#define VDMS_DESC_LABEL_ID_PROP "VD:labelId" // Regions -#define VDMS_ROI_TAG "VD:ROI" -#define VDMS_ROI_EDGE_TAG "VD:ROILINK" +#define VDMS_ROI_TAG "VD:ROI" +#define VDMS_ROI_EDGE_TAG "VD:ROILINK" #define VDMS_ROI_IMAGE_EDGE "VD:ROIIMGLINK" #define VDMS_ROI_COORD_X_PROP "VD:x1" #define VDMS_ROI_COORD_Y_PROP "VD:y1" -#define VDMS_ROI_WIDTH_PROP "VD:width" -#define VDMS_ROI_HEIGHT_PROP "VD:height" +#define VDMS_ROI_WIDTH_PROP "VD:width" +#define VDMS_ROI_HEIGHT_PROP "VD:height" // Videos -#define VDMS_VID_TAG "VD:VID" -#define VDMS_VID_EDGE "VD:VIDLINK" -#define VDMS_VID_PATH_PROP "VD:videoPath" +#define VDMS_VID_TAG "VD:VID" +#define VDMS_VID_EDGE "VD:VIDLINK" +#define VDMS_VID_PATH_PROP "VD:videoPath" // Key frames (KF) -#define VDMS_KF_TAG "VD:KF" -#define VDMS_KF_EDGE "VD:KFLINK" -#define VDMS_KF_IDX_PROP "VD:frameIndex" +#define VDMS_KF_TAG "VD:KF" +#define VDMS_KF_EDGE "VD:KFLINK" +#define VDMS_KF_IDX_PROP "VD:frameIndex" #define VDMS_KF_BASE_PROP "VD:frameBase" diff --git a/src/vcl/CMakeLists.txt b/src/vcl/CMakeLists.txt index 5ccc5556..36e719c7 100644 --- a/src/vcl/CMakeLists.txt +++ b/src/vcl/CMakeLists.txt @@ -1,8 +1,31 @@ -cmake_minimum_required (VERSION 3.10) +cmake_minimum_required (VERSION 3.17) project(vcl_library) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") +set(CMAKE_CXX_STANDARD 17) + find_package( OpenCV REQUIRED ) include_directories(../../include . /usr/local/include/opencv4 /usr/include/jsoncpp) -add_library(vcl SHARED DescriptorSet.cc DescriptorSetData.cc Exception.cc FaissDescriptorSet.cc FlinngDescriptorSet.cc Image.cc KeyFrame.cc TDBDenseDescriptorSet.cc TDBDescriptorSet.cc TDBImage.cc TDBObject.cc TDBSparseDescriptorSet.cc utils.cc Video.cc CustomVCL.cc) -target_link_libraries(vcl lapack faiss flinng avformat avcodec swscale ${OpenCV_LIBS}) +add_library(vcl SHARED + DescriptorSet.cc + DescriptorSetData.cc + Exception.cc + FaissDescriptorSet.cc + FlinngDescriptorSet.cc + Image.cc + KeyFrame.cc + TDBDenseDescriptorSet.cc + TDBDescriptorSet.cc + TDBImage.cc + TDBObject.cc + TDBSparseDescriptorSet.cc + utils.cc + Video.cc + CustomVCL.cc + RemoteConnection.cc +) +link_directories( /usr/local/lib ) +target_link_libraries(vcl lapack faiss tiledb flinng avformat avcodec swscale ${OpenCV_LIBS}) +target_compile_options(vcl PRIVATE -Wno-deprecated-declarations) + diff --git a/src/vcl/CustomVCL.cc b/src/vcl/CustomVCL.cc index 6ba37533..dca5cd6e 100644 --- a/src/vcl/CustomVCL.cc +++ b/src/vcl/CustomVCL.cc @@ -1,101 +1,111 @@ #include "vcl/CustomVCL.h" -int custom_vcl_function(VCL::Image& img, const Json::Value& ops) -{ - int return_value = 0; - //create IPC structures for communicating between processes - key_t key_ctl_host_remote; - key_ctl_host_remote = ftok("vdms", 60); - - int msgid_ctl_host_remote = msgget(key_ctl_host_remote, 0666 | IPC_CREAT); - data_message message_ctl_host_remote; - //need size of data message excluding message_type field for msgsnd and msgrcv - size_t data_message_size = sizeof(message_ctl_host_remote.data_rows) + - sizeof(message_ctl_host_remote.data_cols) + - sizeof(message_ctl_host_remote.data_type) + - sizeof(message_ctl_host_remote.data_image_size) + - sizeof(message_ctl_host_remote.data_json_size); - - key_t key_data_host_remote; - key_data_host_remote = ftok("vdms", 61); - int shmid_data_host_remote = shmget(key_data_host_remote,SHARED_IMAGE_BUFFER_SIZE,0666|IPC_CREAT); - uint8_t *image_buffer = (uint8_t*) shmat(shmid_data_host_remote,(void*)0,0); - - key_t key_ctl_remote_host; - key_ctl_remote_host = ftok("vdms", 62); - int msgid_ctl_remote_host = msgget(key_ctl_remote_host, 0666 | IPC_CREAT); - data_message message_ctl_remote_host; - - heartbeat_message message_hb_host_remote; - heartbeat_message message_hb_remote_host; - size_t heartbeat_message_size = sizeof(message_hb_host_remote.status); - - //Pass messages to ensure the remote process is functional - message_hb_host_remote.message_type = (long) vcl_message_type::VCL_MESSAGE_HEARTBEAT; - message_hb_host_remote.status = 0; - int out_alive_msg_status = msgsnd(msgid_ctl_host_remote, &message_hb_host_remote, heartbeat_message_size, 0); - - int hb_count = 0; - int in_alive_msg_status = -1; - - //try 10 times to determine if process is running - while(hb_count < 10 && in_alive_msg_status < 0) - { - in_alive_msg_status = msgrcv(msgid_ctl_remote_host, &message_hb_remote_host, heartbeat_message_size, (long) vcl_message_type::VCL_MESSAGE_HEARTBEAT, IPC_NOWAIT); - hb_count++; +int custom_vcl_function(VCL::Image &img, const Json::Value &ops) { + int return_value = 0; + // create IPC structures for communicating between processes + key_t key_ctl_host_remote; + key_ctl_host_remote = ftok("vdms", 60); + int msgid_ctl_host_remote = msgget(key_ctl_host_remote, 0666 | IPC_CREAT); + data_message message_ctl_host_remote; + // need size of data message excluding message_type field for msgsnd and + // msgrcv + size_t data_message_size = sizeof(message_ctl_host_remote.data_rows) + + sizeof(message_ctl_host_remote.data_cols) + + sizeof(message_ctl_host_remote.data_type) + + sizeof(message_ctl_host_remote.data_image_size) + + sizeof(message_ctl_host_remote.data_json_size); + + key_t key_data_host_remote; + key_data_host_remote = ftok("vdms", 61); + int shmid_data_host_remote = + shmget(key_data_host_remote, SHARED_IMAGE_BUFFER_SIZE, 0666 | IPC_CREAT); + uint8_t *image_buffer = + (uint8_t *)shmat(shmid_data_host_remote, (void *)0, 0); + + key_t key_ctl_remote_host; + key_ctl_remote_host = ftok("vdms", 62); + int msgid_ctl_remote_host = msgget(key_ctl_remote_host, 0666 | IPC_CREAT); + data_message message_ctl_remote_host; + + heartbeat_message message_hb_host_remote; + heartbeat_message message_hb_remote_host; + size_t heartbeat_message_size = sizeof(message_hb_host_remote.status); + + // Pass messages to ensure the remote process is functional + message_hb_host_remote.message_type = + (long)vcl_message_type::VCL_MESSAGE_HEARTBEAT; + message_hb_host_remote.status = 0; + int out_alive_msg_status = + msgsnd(msgid_ctl_host_remote, &message_hb_host_remote, + heartbeat_message_size, 0); + + int hb_count = 0; + int in_alive_msg_status = -1; + + // try 10 times to determine if process is running + while (hb_count < 10 && in_alive_msg_status < 0) { + in_alive_msg_status = msgrcv( + msgid_ctl_remote_host, &message_hb_remote_host, heartbeat_message_size, + (long)vcl_message_type::VCL_MESSAGE_HEARTBEAT, IPC_NOWAIT); + hb_count++; + } + + if (in_alive_msg_status > -1) { + // Read image from file and obtain image information to calculate size + cv::Mat in_image = img.get_cvmat(true); + + size_t in_image_size = in_image.total() * in_image.elemSize(); + message_ctl_host_remote.message_type = + (long)vcl_message_type::VCL_MESSAGE_DATA; + message_ctl_host_remote.data_rows = in_image.rows; + message_ctl_host_remote.data_cols = in_image.cols; + message_ctl_host_remote.data_type = in_image.type(); + message_ctl_host_remote.data_image_size = in_image_size; + + // Copy image data into shared memory + memcpy((uint8_t *)&(image_buffer[0]), (uint8_t *)&(in_image.data[0]), + in_image_size); + + std::string *json_string = new std::string(ops.toStyledString()); + message_ctl_host_remote.data_json_size = json_string->size(); + // image size corresponds with first byte after the image + memcpy(&(image_buffer[in_image_size]), json_string->c_str(), + json_string->size()); + int msg_send_result = msgsnd( + msgid_ctl_host_remote, &message_ctl_host_remote, data_message_size, 0); + if (msg_send_result < 0) { + delete json_string; + return -1; } - if(in_alive_msg_status > -1) - { - //Read image from file and obtain image information to calculate size - cv::Mat in_image = img.get_cvmat(true); - - size_t in_image_size = in_image.total() * in_image.elemSize(); - message_ctl_host_remote.message_type = (long) vcl_message_type::VCL_MESSAGE_DATA; - message_ctl_host_remote.data_rows = in_image.rows; - message_ctl_host_remote.data_cols = in_image.cols; - message_ctl_host_remote.data_type = in_image.type(); - message_ctl_host_remote.data_image_size = in_image_size; - - //Copy image data into shared memory - memcpy((uint8_t*) &(image_buffer[0]), (uint8_t*) &(in_image.data[0]), in_image_size); - - std::string* json_string = new std::string(ops.toStyledString()); - message_ctl_host_remote.data_json_size = json_string->size(); - //image size corresponds with first byte after the image - memcpy(&(image_buffer[in_image_size]), json_string->c_str(), json_string->size()); - int msg_send_result = msgsnd(msgid_ctl_host_remote, &message_ctl_host_remote, data_message_size, 0); - if(msg_send_result < 0) - { - delete json_string; - return -1; - } - - int msg_recv_result = msgrcv(msgid_ctl_remote_host, &message_ctl_remote_host, data_message_size, (long)vcl_message_type::VCL_MESSAGE_DATA, 0); - - if(msg_recv_result < 0) - {} - - //Grab data back from shared memory - cv::Mat* out_image = new cv::Mat(message_ctl_remote_host.data_rows, message_ctl_remote_host.data_cols, message_ctl_remote_host.data_type); - memcpy(&(out_image->data[0]), &(image_buffer[0]), message_ctl_remote_host.data_image_size); - - img.deep_copy_cv(*out_image); - - //Free allocated memory - delete out_image; - delete json_string; - - //Free shared IPC components - shmdt(image_buffer); - //msgctl(msgid_ctl_remote_host, IPC_RMID, NULL); - return_value = 0; - } - else - { - return_value = -1; - throw VDMS::ExceptionCommand(ImageError, "Error in custom Function"); + int msg_recv_result = + msgrcv(msgid_ctl_remote_host, &message_ctl_remote_host, + data_message_size, (long)vcl_message_type::VCL_MESSAGE_DATA, 0); + + if (msg_recv_result < 0) { } - return return_value; + // Grab data back from shared memory + cv::Mat *out_image = new cv::Mat(message_ctl_remote_host.data_rows, + message_ctl_remote_host.data_cols, + message_ctl_remote_host.data_type); + memcpy(&(out_image->data[0]), &(image_buffer[0]), + message_ctl_remote_host.data_image_size); + + img.deep_copy_cv(*out_image); + + // Free allocated memory + delete out_image; + delete json_string; + + // Free shared IPC components + shmdt(image_buffer); + // msgctl(msgid_ctl_remote_host, IPC_RMID, NULL); + return_value = 0; + } else { + return_value = -1; + throw VDMS::ExceptionCommand(ImageError, "Error in custom Function"); + } + + return return_value; } diff --git a/src/vcl/DescriptorParams.cc b/src/vcl/DescriptorParams.cc index a1cacd76..e725ddbd 100644 --- a/src/vcl/DescriptorParams.cc +++ b/src/vcl/DescriptorParams.cc @@ -1,45 +1,48 @@ /** -* -* @section LICENSE -* -* The MIT License -* -* @copyright Copyright (c) 2017 Intel Corporation -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), -* to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* @section DESCRIPTION -* -*/ + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + */ using namespace VCL; -DescriptorParams::DescriptorParams(uint64_t numrows = 3, uint64_t cellsperrow = (1<<12), - uint64_t numhashtables = (1<<9), uint64_t hashespertable = 14, - uint64_t subhashbits = 2, uint64_t cutoff=6) { - this->num_rows = numrows; - this->cells_per_row= cellsperrow; - this->num_hash_tables = numhashtables; - this->hashes_per_table = hashespertable; - this->sub_hash_bits = subhashbits; //sub_hash_bits * hashes_per_table must be less than 32, otherwise segfault will happen - this->cut_off= cutoff; +DescriptorParams::DescriptorParams(uint64_t numrows = 3, + uint64_t cellsperrow = (1 << 12), + uint64_t numhashtables = (1 << 9), + uint64_t hashespertable = 14, + uint64_t subhashbits = 2, + uint64_t cutoff = 6) { + this->num_rows = numrows; + this->cells_per_row = cellsperrow; + this->num_hash_tables = numhashtables; + this->hashes_per_table = hashespertable; + this->sub_hash_bits = + subhashbits; // sub_hash_bits * hashes_per_table must be less than 32, + // otherwise segfault will happen + this->cut_off = cutoff; } - - \ No newline at end of file diff --git a/src/vcl/DescriptorParams.h b/src/vcl/DescriptorParams.h index ac5498fd..7282b2c7 100644 --- a/src/vcl/DescriptorParams.h +++ b/src/vcl/DescriptorParams.h @@ -1,74 +1,77 @@ /** -* -* @section LICENSE -* -* The MIT License -* -* @copyright Copyright (c) 2017 Intel Corporation -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), -* to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* @section DESCRIPTION -* -* This file declares the C++ Interface for the abstract DescriptorSetData object. -*/ + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file declares the C++ Interface for the abstract DescriptorSetData + * object. + */ #pragma once -#include -#include #include -#include #include +#include +#include +#include -#include +#include #include +#include #include -#include #include "vcl/DescriptorSet.h" namespace VCL { - class DescriptorParams { +class DescriptorParams { public: - /* Params needed for FLINNG */ - //constants for now until we derive them from N and dimensions - uint64_t num_rows; - uint64_t cells_per_row; - uint64_t num_hash_tables; - uint64_t hashes_per_table; - uint64_t sub_hash_bits; //sub_hash_bits * hashes_per_table must be less than 32, otherwise segfault will happen - uint64_t cut_off; + /* Params needed for FLINNG */ + // constants for now until we derive them from N and dimensions + uint64_t num_rows; + uint64_t cells_per_row; + uint64_t num_hash_tables; + uint64_t hashes_per_table; + uint64_t sub_hash_bits; // sub_hash_bits * hashes_per_table must be less than + // 32, otherwise segfault will happen + uint64_t cut_off; - DescriptorParams(uint64_t numrows = 3, uint64_t cellsperrow = (1<<12), - uint64_t numhashtables = (1<<9), uint64_t hashespertable = 14, - uint64_t subhashbits = 2, uint64_t cutoff=6) { - this->num_rows = numrows; - this->cells_per_row= cellsperrow; - this->num_hash_tables = numhashtables; - this->hashes_per_table = hashespertable; - this->sub_hash_bits = subhashbits; - this->cut_off= cutoff; - } -}; + DescriptorParams(uint64_t numrows = 3, uint64_t cellsperrow = (1 << 12), + uint64_t numhashtables = (1 << 9), + uint64_t hashespertable = 14, uint64_t subhashbits = 2, + uint64_t cutoff = 6) { + this->num_rows = numrows; + this->cells_per_row = cellsperrow; + this->num_hash_tables = numhashtables; + this->hashes_per_table = hashespertable; + this->sub_hash_bits = subhashbits; + this->cut_off = cutoff; + } }; +}; // namespace VCL diff --git a/src/vcl/DescriptorSet.cc b/src/vcl/DescriptorSet.cc index 3b18d54c..a4524546 100644 --- a/src/vcl/DescriptorSet.cc +++ b/src/vcl/DescriptorSet.cc @@ -29,294 +29,287 @@ * */ +#include +#include #include #include -#include +// clang-format off #include "vcl/DescriptorSet.h" #include "DescriptorSetData.h" #include "DescriptorParams.h" #include "FaissDescriptorSet.h" #include "TDBDescriptorSet.h" #include "FlinngDescriptorSet.h" +// clang-format on #define INFO_FILE_NAME "eng_info.txt" -namespace VCL { - -DescriptorSet::DescriptorSet(const std::string &set_path) -{ - read_set_info(set_path); - - if (_eng == DescriptorSetEngine(FaissFlat)) - _set = new FaissFlatDescriptorSet(set_path); - else if (_eng == DescriptorSetEngine(FaissIVFFlat)) - _set = new FaissIVFFlatDescriptorSet(set_path); - else if (_eng == DescriptorSetEngine(TileDBDense)) - _set = new TDBDenseDescriptorSet(set_path); - else if (_eng == DescriptorSetEngine(TileDBSparse)) - _set = new TDBSparseDescriptorSet(set_path); - else if (_eng == DescriptorSetEngine(Flinng)) - _set = new FlinngDescriptorSet(set_path); - else { - std::cerr << "Index Not supported" << std::endl; - throw VCLException(UnsupportedIndex, "Index not supported"); - } -} - -DescriptorSet::DescriptorSet(const std::string &set_path, - unsigned dim, - DescriptorSetEngine eng, - DistanceMetric metric, - VCL::DescriptorParams* param): - _eng(eng) -{ - if (eng == DescriptorSetEngine(FaissFlat)) - _set = new FaissFlatDescriptorSet(set_path, dim, metric); - else if (eng == DescriptorSetEngine(FaissIVFFlat)) - _set = new FaissIVFFlatDescriptorSet(set_path, dim, metric); - else if (eng == DescriptorSetEngine(TileDBDense)) - _set = new TDBDenseDescriptorSet(set_path, dim, metric); - else if (eng == DescriptorSetEngine(TileDBSparse)) - _set = new TDBSparseDescriptorSet(set_path, dim, metric); - else if (eng == DescriptorSetEngine(Flinng)) - _set = new FlinngDescriptorSet(set_path, dim, metric, param); - else { - std::cerr << "Index Not supported" << std::endl; - throw VCLException(UnsupportedIndex, "Index not supported"); - } -} - -DescriptorSet::~DescriptorSet() -{ - delete _set; -} - -void DescriptorSet::write_set_info() -{ - std::string path = _set->get_path() + "/" + INFO_FILE_NAME; - std::ofstream info_file(path); - info_file << _eng << std::endl; - info_file.close(); -} - -void DescriptorSet::read_set_info(const std::string& set_path) -{ - std::string path = set_path + "/" + INFO_FILE_NAME; - std::ifstream info_file(path); - - if (!info_file.good()) { - std::cout << "cannot open: " << path << std::endl; - throw VCLException(OpenFailed, "Cannot open: " + path); - } - - int num; - std::string str; - std::getline(info_file, str); - std::stringstream sstr(str); - sstr >> num; - _eng = (DescriptorSetEngine)num; - info_file.close(); -} - - /* *********************** */ - /* CORE INTERFACE */ - /* *********************** */ +namespace fs = std::filesystem; -std::string DescriptorSet::get_path() -{ - return _set->get_path(); -} - -unsigned DescriptorSet::get_dimensions() -{ - return _set->get_dimensions(); -} +namespace VCL { -long DescriptorSet::get_n_descriptors() -{ - return _set->get_n_total(); -} +DescriptorSet::DescriptorSet(const std::string &set_path) { + read_set_info(set_path); + _remote = nullptr; + + if (_eng == DescriptorSetEngine(FaissFlat)) + _set = new FaissFlatDescriptorSet(set_path); + else if (_eng == DescriptorSetEngine(FaissIVFFlat)) + _set = new FaissIVFFlatDescriptorSet(set_path); + else if (_eng == DescriptorSetEngine(TileDBDense)) + _set = new TDBDenseDescriptorSet(set_path); + else if (_eng == DescriptorSetEngine(TileDBSparse)) + _set = new TDBSparseDescriptorSet(set_path); + else if (_eng == DescriptorSetEngine(Flinng)) + _set = new FlinngDescriptorSet(set_path); + else { + std::cerr << "Index Not supported" << std::endl; + throw VCLException(UnsupportedIndex, "Index not supported"); + } +} + +DescriptorSet::DescriptorSet(const std::string &set_path, unsigned dim, + DescriptorSetEngine eng, DistanceMetric metric, + VCL::DescriptorParams *param) + : _eng(eng) { + _remote = nullptr; + + if (eng == DescriptorSetEngine(FaissFlat)) + _set = new FaissFlatDescriptorSet(set_path, dim, metric); + else if (eng == DescriptorSetEngine(FaissIVFFlat)) + _set = new FaissIVFFlatDescriptorSet(set_path, dim, metric); + else if (eng == DescriptorSetEngine(TileDBDense)) + _set = new TDBDenseDescriptorSet(set_path, dim, metric); + else if (eng == DescriptorSetEngine(TileDBSparse)) + _set = new TDBSparseDescriptorSet(set_path, dim, metric); + else if (eng == DescriptorSetEngine(Flinng)) + _set = new FlinngDescriptorSet(set_path, dim, metric, param); + else { + std::cerr << "Index Not supported" << std::endl; + throw VCLException(UnsupportedIndex, "Index not supported"); + } +} + +DescriptorSet::~DescriptorSet() { delete _set; } + +void DescriptorSet::write_set_info() { + std::string path = _set->get_path() + "/" + INFO_FILE_NAME; + std::ofstream info_file(path); + info_file << _eng << std::endl; + info_file.close(); +} + +void DescriptorSet::read_set_info(const std::string &set_path) { + std::string path = set_path + "/" + INFO_FILE_NAME; + std::ifstream info_file(path); + + if (!info_file.good()) { + std::cout << "cannot open: " << path << std::endl; + throw VCLException(OpenFailed, "Cannot open: " + path); + } + + int num; + std::string str; + std::getline(info_file, str); + std::stringstream sstr(str); + sstr >> num; + _eng = (DescriptorSetEngine)num; + info_file.close(); +} + +/* *********************** */ +/* CORE INTERFACE */ +/* *********************** */ + +std::string DescriptorSet::get_path() { return _set->get_path(); } + +unsigned DescriptorSet::get_dimensions() { return _set->get_dimensions(); } + +long DescriptorSet::get_n_descriptors() { return _set->get_n_total(); } void DescriptorSet::search(DescDataArray queries, unsigned n_queries, - unsigned k, long* descriptors_ids, float* distances) -{ - _set->search(queries, n_queries, k, descriptors_ids, distances); + unsigned k, long *descriptors_ids, + float *distances) { + _set->search(queries, n_queries, k, descriptors_ids, distances); } void DescriptorSet::search(DescDataArray queries, unsigned n_queries, - unsigned k, long* descriptors_ids) -{ - _set->search(queries, n_queries, k, descriptors_ids); + unsigned k, long *descriptors_ids) { + _set->search(queries, n_queries, k, descriptors_ids); } void DescriptorSet::radius_search(DescData queries, float radius, - long* descriptors_ids, float* distances) -{ - _set->radius_search(queries, radius, descriptors_ids, distances); + long *descriptors_ids, float *distances) { + _set->radius_search(queries, radius, descriptors_ids, distances); } -long DescriptorSet::add(DescDataArray descriptors, unsigned n, long* labels) -{ - return _set->add(descriptors, n, labels); +long DescriptorSet::add(DescDataArray descriptors, unsigned n, long *labels) { + return _set->add(descriptors, n, labels); } -long DescriptorSet::add_and_store(DescDataArray descriptors, unsigned n, long* labels) -{ - return _set->add_and_store(descriptors, n, labels); +long DescriptorSet::add_and_store(DescDataArray descriptors, unsigned n, + long *labels) { + return _set->add_and_store(descriptors, n, labels); } -void DescriptorSet::train() -{ - _set->train(); -} +void DescriptorSet::train() { _set->train(); } -void DescriptorSet::finalize_index() -{ - _set->finalize_index(); -} +void DescriptorSet::finalize_index() { _set->finalize_index(); } -void DescriptorSet::train(DescDataArray descriptors, unsigned n) -{ - _set->train(descriptors, n); +void DescriptorSet::train(DescDataArray descriptors, unsigned n) { + _set->train(descriptors, n); } -bool DescriptorSet::is_trained() -{ - return _set->is_trained(); -} +bool DescriptorSet::is_trained() { return _set->is_trained(); } void DescriptorSet::classify(DescDataArray descriptors, unsigned n, - long* labels, unsigned quorum) -{ - _set->classify(descriptors, n, labels, quorum); + long *labels, unsigned quorum) { + _set->classify(descriptors, n, labels, quorum); } -void DescriptorSet::get_descriptors(long* ids, unsigned n, DescDataArray descriptors) -{ - _set->get_descriptors(ids, n, descriptors); +void DescriptorSet::get_descriptors(long *ids, unsigned n, + DescDataArray descriptors) { + _set->get_descriptors(ids, n, descriptors); } -void DescriptorSet::store() -{ - _set->store(); - write_set_info(); +void DescriptorSet::store() { + _set->store(); + write_set_info(); + + // grab the descriptor files from local storage, upload them, delete the local + // copies not deleting the local copies currently to resolve concurrency + // issues + if (_storage == Storage::AWS) { + std::string dir_path = _set->get_path(); + std::vector filenames; + + for (const auto &file : fs::directory_iterator(dir_path)) { + filenames.push_back(file.path()); + } + + for (int i = 0; i < filenames.size(); i++) { + _remote->Write(filenames[i]); + // std::remove(filename.c_str()); + } + } } -void DescriptorSet::store(std::string set_path) -{ - _set->store(set_path); - write_set_info(); +void DescriptorSet::store(std::string set_path) { + _set->store(set_path); + write_set_info(); } - /* *********************** */ - /* VECTOR-BASED INTERFACE */ - /* *********************** */ +/* *********************** */ +/* VECTOR-BASED INTERFACE */ +/* *********************** */ long DescriptorSet::add(DescDataArray descriptors, unsigned n, - LabelIdVector& labels) -{ - if (n != labels.size() && labels.size() != 0) - throw VCLException(SizeMismatch, "Labels Vector of Wrong Size"); + LabelIdVector &labels) { + if (n != labels.size() && labels.size() != 0) + throw VCLException(SizeMismatch, "Labels Vector of Wrong Size"); - return add(descriptors, n, labels.size() > 0 ? (long*) labels.data() : NULL); + return add(descriptors, n, labels.size() > 0 ? (long *)labels.data() : NULL); } long DescriptorSet::add_and_store(DescDataArray descriptors, unsigned n, - LabelIdVector& labels) -{ - if (n != labels.size() && labels.size() != 0) - throw VCLException(SizeMismatch, "Labels Vector of Wrong Size"); + LabelIdVector &labels) { + if (n != labels.size() && labels.size() != 0) + throw VCLException(SizeMismatch, "Labels Vector of Wrong Size"); - return add_and_store(descriptors, n, labels.size() > 0 ? (long*) labels.data() : NULL); + return add_and_store(descriptors, n, + labels.size() > 0 ? (long *)labels.data() : NULL); } void DescriptorSet::search(DescDataArray queries, unsigned n, unsigned k, - DescIdVector& ids, DistanceVector& distances) -{ - ids.resize(n * k); - distances.resize(n * k); - search(queries, n, k, ids.data(), distances.data()); + DescIdVector &ids, DistanceVector &distances) { + ids.resize(n * k); + distances.resize(n * k); + search(queries, n, k, ids.data(), distances.data()); } void DescriptorSet::search(DescDataArray queries, unsigned n, unsigned k, - DescIdVector& ids) -{ - ids.resize(n * k); - search(queries, n, k, ids.data()); + DescIdVector &ids) { + ids.resize(n * k); + search(queries, n, k, ids.data()); } std::vector DescriptorSet::classify(DescDataArray descriptors, unsigned n, - unsigned quorum) -{ - LabelIdVector labels; - labels.resize(n); - classify(descriptors, n, labels.data(), quorum); - return labels; + unsigned quorum) { + LabelIdVector labels; + labels.resize(n); + classify(descriptors, n, labels.data(), quorum); + return labels; } -void DescriptorSet::get_descriptors(std::vector& ids, float* descriptors) -{ - get_descriptors(ids.data(), ids.size(), descriptors); +void DescriptorSet::get_descriptors(std::vector &ids, + float *descriptors) { + get_descriptors(ids.data(), ids.size(), descriptors); } - /* *********************** */ - /* STRING-LABELS SUPPORT */ - /* *********************** */ +/* *********************** */ +/* STRING-LABELS SUPPORT */ +/* *********************** */ -void DescriptorSet::set_labels_map(std::map& labels) -{ - return _set->set_labels_map(labels); +void DescriptorSet::set_labels_map(std::map &labels) { + return _set->set_labels_map(labels); } -std::map DescriptorSet::get_labels_map() -{ - return _set->get_labels_map(); +std::map DescriptorSet::get_labels_map() { + return _set->get_labels_map(); } -void DescriptorSet::set_labels_map(LabelIdVector& ids, - std::vector& labels) -{ - assert (ids.size() == labels.size()); - std::map labels_map; - for (int i = 0; i < ids.size(); ++i) { - labels_map[ids[i]] = labels[i]; - } +void DescriptorSet::set_labels_map(LabelIdVector &ids, + std::vector &labels) { + assert(ids.size() == labels.size()); + std::map labels_map; + for (int i = 0; i < ids.size(); ++i) { + labels_map[ids[i]] = labels[i]; + } - set_labels_map(labels_map); + set_labels_map(labels_map); } -std::vector DescriptorSet::label_id_to_string(LabelIdVector& l_id) -{ - std::vector ret_labels(l_id.size()); - std::map labels_map = _set->get_labels_map(); +std::vector +DescriptorSet::label_id_to_string(LabelIdVector &l_id) { + std::vector ret_labels(l_id.size()); + std::map labels_map = _set->get_labels_map(); - for (int i = 0; i < l_id.size(); ++i) { - ret_labels[i] = labels_map[l_id[i]]; - } - return ret_labels; + for (int i = 0; i < l_id.size(); ++i) { + ret_labels[i] = labels_map[l_id[i]]; + } + return ret_labels; } -long DescriptorSet::get_label_id(const std::string& label) -{ - auto map = _set->get_labels_map(); +long DescriptorSet::get_label_id(const std::string &label) { + auto map = _set->get_labels_map(); - for (auto it = map.begin(); it != map.end(); ++it ) { - if (it->second == label) { - return it->first; - } + for (auto it = map.begin(); it != map.end(); ++it) { + if (it->second == label) { + return it->first; } + } - long id = map.size(); - map[id] = label; - _set->set_labels_map(map); + long id = map.size(); + map[id] = label; + _set->set_labels_map(map); - return id; + return id; } -std::vector DescriptorSet::get_str_labels(DescIdVector& ids) -{ - return _set->get_str_labels(ids.data(), ids.size()); +std::vector DescriptorSet::get_str_labels(DescIdVector &ids) { + return _set->get_str_labels(ids.data(), ids.size()); } +void DescriptorSet::set_connection(RemoteConnection *remote) { + if (!remote->connected()) + remote->start(); + + if (!remote->connected()) { + throw VCLException(SystemNotFound, "No remote connection started"); + } + + _remote = remote; + _storage = Storage::AWS; } +} // namespace VCL diff --git a/src/vcl/DescriptorSetData.cc b/src/vcl/DescriptorSetData.cc index 324a882e..c1d5ca42 100644 --- a/src/vcl/DescriptorSetData.cc +++ b/src/vcl/DescriptorSetData.cc @@ -1,34 +1,34 @@ /** -* -* @section LICENSE -* -* The MIT License -* -* @copyright Copyright (c) 2017 Intel Corporation -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), -* to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* @section DESCRIPTION -* -*/ + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + */ #include #include @@ -38,97 +38,85 @@ using namespace VCL; -DescriptorSet::DescriptorSetData::DescriptorSetData(const std::string &set_path): - _set_path(set_path) -{ +DescriptorSet::DescriptorSetData::DescriptorSetData(const std::string &set_path) + : _set_path(set_path) { _dimensions = 0; _n_total = 0; _metric = VCL::DistanceMetric::L2; // by default - if (!dir_exist(set_path)) { - throw VCLException(OpenFailed, "File does not exists"); - } + throw VCLException(OpenFailed, "File does not exists"); + } } -DescriptorSet::DescriptorSetData::DescriptorSetData( - const std::string &set_path, - uint32_t dim) : - _set_path(set_path), - _dimensions(dim), - _n_total(0) -{ +DescriptorSet::DescriptorSetData::DescriptorSetData(const std::string &set_path, + uint32_t dim) + : _set_path(set_path), _dimensions(dim), _n_total(0) { _metric = VCL::DistanceMetric::L2; // by default - - if (dir_exist(set_path)) { - throw VCLException(OpenFailed, "File already exists"); - } -} -DescriptorSet::DescriptorSetData::~DescriptorSetData() -{ + if (dir_exist(set_path)) { + throw VCLException(OpenFailed, "File already exists"); + } } -void DescriptorSet::DescriptorSetData::radius_search( - float* query, float radius, - long* descriptors, float* distances) -{ - throw VCLException(UnsupportedOperation, "Not Implemented"); +DescriptorSet::DescriptorSetData::~DescriptorSetData() {} + +void DescriptorSet::DescriptorSetData::radius_search(float *query, float radius, + long *descriptors, + float *distances) { + throw VCLException(UnsupportedOperation, "Not Implemented"); } // String labels handling -void DescriptorSet::DescriptorSetData::set_labels_map(std::map& labels) -{ - _labels_map_lock.lock(); - _labels_map = labels; - _labels_map_lock.unlock(); +void DescriptorSet::DescriptorSetData::set_labels_map( + std::map &labels) { + _labels_map_lock.lock(); + _labels_map = labels; + _labels_map_lock.unlock(); } -std::vector DescriptorSet::DescriptorSetData::get_str_labels( - long* ids, unsigned n) -{ - std::vector str_labels(n); - std::vector labels(n); +std::vector +DescriptorSet::DescriptorSetData::get_str_labels(long *ids, unsigned n) { + std::vector str_labels(n); + std::vector labels(n); - get_labels(ids, n, labels.data()); + get_labels(ids, n, labels.data()); - _labels_map_lock.lock(); - for (int i = 0; i < n; ++i) { - assert(labels[i] < _labels_map.size()); - str_labels[i] = _labels_map[labels[i]]; - } - _labels_map_lock.unlock(); + _labels_map_lock.lock(); + for (int i = 0; i < n; ++i) { + assert(labels[i] < _labels_map.size()); + str_labels[i] = _labels_map[labels[i]]; + } + _labels_map_lock.unlock(); - return str_labels; + return str_labels; } -void DescriptorSet::DescriptorSetData::write_labels_map() -{ - std::ofstream out_labels(_set_path + "/labels.txt"); +void DescriptorSet::DescriptorSetData::write_labels_map() { + std::ofstream out_labels(_set_path + "/labels.txt"); - _labels_map_lock.lock(); - for (auto& label : _labels_map) { - out_labels << label.first << " " << label.second << std::endl; - } - _labels_map_lock.unlock(); + _labels_map_lock.lock(); + for (auto &label : _labels_map) { + out_labels << label.first << " " << label.second << std::endl; + } + _labels_map_lock.unlock(); - out_labels.close(); + out_labels.close(); } -void DescriptorSet::DescriptorSetData::read_labels_map() -{ - std::ifstream in_labels(_set_path + "/labels.txt"); - std::string str; - _labels_map_lock.lock(); - _labels_map.clear(); - while (std::getline(in_labels, str)) { - std::stringstream sstr(str); - long id; - sstr >> id; - sstr >> str; - _labels_map[id] = str; - } - _labels_map_lock.unlock(); - in_labels.close(); +void DescriptorSet::DescriptorSetData::read_labels_map() { + std::ifstream in_labels(_set_path + "/labels.txt"); + std::string str; + _labels_map_lock.lock(); + _labels_map.clear(); + while (std::getline(in_labels, str)) { + std::stringstream sstr(str); + long id; + sstr >> id; + sstr >> str; + _labels_map[id] = str; + } + _labels_map_lock.unlock(); + in_labels.close(); } diff --git a/src/vcl/DescriptorSetData.h b/src/vcl/DescriptorSetData.h index a43f4635..c2b2c423 100644 --- a/src/vcl/DescriptorSetData.h +++ b/src/vcl/DescriptorSetData.h @@ -1,278 +1,278 @@ /** -* -* @section LICENSE -* -* The MIT License -* -* @copyright Copyright (c) 2017 Intel Corporation -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), -* to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* @section DESCRIPTION -* -* This file declares the C++ Interface for the abstract DescriptorSetData object. -*/ + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file declares the C++ Interface for the abstract DescriptorSetData + * object. + */ #pragma once -#include -#include #include -#include #include +#include +#include +#include -#include +#include #include +#include #include -#include #include "vcl/DescriptorSet.h" namespace VCL { - class DescriptorSet::DescriptorSetData { - - protected: - - std::string _set_path; - unsigned _dimensions; - uint64_t _n_total; - - DistanceMetric _metric; - - // String labels handling - std::mutex _labels_map_lock; - std::map _labels_map; - - inline bool file_exist(const std::string& name) { - std::ifstream f(name.c_str()); - if (f.good()) { - f.close(); - return true; - } - return false; - } - - inline bool dir_exist(const std::string& dir_name) { - DIR* dir = opendir(dir_name.c_str()); - if (dir) - { - closedir(dir); - return true; - } - - return false; - } - - inline int create_dir(const char *path){ - struct stat sb; - while (1) - if (stat(path, &sb) == 0) - if (sb.st_mode & S_IFDIR) - return 0; - else - return EEXIST; - else if (errno != ENOENT) - return errno; - else if (mkdir(path, 0777) == 0) - return 0; - else if (errno != EEXIST) - return errno; - } - - void write_labels_map(); - void read_labels_map(); - - public: - /** - * Loads an existing collection located at collection_path - * or created a new collection if it does not exist - * Returns error if the set does not exist - * - * @param filename Full Path to the collection folder - */ - DescriptorSetData(const std::string &filename); - - /** - * Creates collection located at filename - * or created a new collection if it does not exist - * - * @param filename Full Path to the collection folder - * @param dim Dimension of the descriptor - */ - DescriptorSetData(const std::string &filename, unsigned dim); - - virtual ~DescriptorSetData(); - - DescriptorSetData(const DescriptorSetData&) = delete; - - std::string get_path() { return _set_path; } - - unsigned get_dimensions() { return _dimensions; } - - /** - * Returns the number of descriptors in the set - */ - long get_n_total() { return _n_total; } - - /** - * Inserts n descriptors and their labels into the set - * Both descriptors and labels must have the same number of elements, - * or labels can have no elements. - * If not labels are defined, -1 is assigned to signify "no label". - - * Note: Given the in-memory nature of the Faiss library, adding - * elements on a set using Faiss as engine will not persist the data - * until the store() method is call. This is contrary to the TileDB - * engines, where every add will return after persisting the data. - - * @param descriptors Buffer to descriptors (size n * dim) - * @param n Number of descriptors - * @param labels Array of labels, can be NULL. - */ - virtual long add(float* descriptors, unsigned n_descriptors, - long* labels = NULL) = 0; - - virtual long add_and_store(float* descriptors, unsigned n_descriptors, - long* labels = NULL) {return 0;} - - /** - * Search for the k closest neighborhs - * - * @param query Query descriptors buffer - * @param n Number of descriptors that will be queried - * @param k Number of maximun neighbors to be returned - * @return ids id of each neighbor (size n * k) (padded with -1) - * @return distances distances to each neighbor (size n * k). - (padded with -1) - */ - virtual void search(float* query, unsigned n, unsigned k, - long* descriptors, float* distances) = 0; - - virtual void search(float* query, unsigned n, unsigned k, - long* descriptors) {} - - /** - * Search for neighborhs within a radius. - * - * Note: We only allow the radius search of a single - * element to avoid having to deal with results that are - * of different (unknown) sized for each query. - * We will work on it once we have a more clear use case for - * this call - * - * @param query Query vector - * @param radius Maximun distance allowed - * @param ids Array of ID of the descriptors - * @param distances Distances of each neighbor - */ - virtual void radius_search(float* query, float radius, - long* descriptors, float* distances); - - /** - * Find the label of the feature vector, based on the closest - * neighbors. - * - * @param descriptors Buffer to descriptors (size n * dim) - * @param n Number of descriptors in buffer - * @return labels Label Ids - * @param quorum Number of elements used for the classification vote. - */ - virtual void classify(float* descriptors, unsigned n, long* ids, - unsigned quorum) = 0; - - /** - * Get the descriptors by specifiying ids. - * This is an exact search by id. - * - * @param ids buffer with ids - * @param n number of ids to query - * @return descriptors pointer to descriptors buffer - size: (n * dim * sizeof(float)) - */ - virtual void get_descriptors(long* ids, unsigned n, - float* descriptors) = 0; - - virtual void get_labels(long* ids, unsigned n, long* labels) = 0; - - /** - * Trains the index with the data present in the collection - * using the specified metric - */ - virtual void train() {} - - /** - * Trains the index using specified descriptors - * - * @param descriptors Reference Descriptors - * @param n Number of descriptors - */ - virtual void train(float* descriptors, unsigned n) { train(); } - - virtual bool is_trained() {return false;} - - virtual void finalize_index() {} - - /** - * Writes the DescriptorSet Index to the system. This will overwrite - * the original - */ - virtual void store() = 0; - - /** - * Writes the DescriptorSet Index to the system into a defined path. - * This will overwrite any other index under the same set_path. - */ - virtual void store(std::string collection_path) = 0; - - // String labels handling - - /** - * Get the label of the descriptors for the spcified ids. - * NOTE: This is a vector becase this is what we return. - * We can, make wrapper functions that recieve arrays as well. - * - * @param ids vector of ids - * @return vector with the string labels - */ - std::vector get_str_labels(long* ids, unsigned n); - - /** - * Get the label of the descriptors for the spcified ids. - * NOTE: This is a vector becase this is what we return. - * We can, make wrapper functions that recieve arrays as well. - * - * @param ids vector of ids - * @return vector with the string labels - */ - std::map get_labels_map() { return _labels_map; } - - /** - * Set the matching between label id and the string corresponding - * to the label - * - * @param ids ids of the labels - * @param labels string for each label - */ - void set_labels_map(std::map& labels); - }; - -}; \ No newline at end of file +class DescriptorSet::DescriptorSetData { + +protected: + std::string _set_path; + unsigned _dimensions; + uint64_t _n_total; + + DistanceMetric _metric; + + // String labels handling + std::mutex _labels_map_lock; + std::map _labels_map; + + inline bool file_exist(const std::string &name) { + std::ifstream f(name.c_str()); + if (f.good()) { + f.close(); + return true; + } + return false; + } + + inline bool dir_exist(const std::string &dir_name) { + DIR *dir = opendir(dir_name.c_str()); + if (dir) { + closedir(dir); + return true; + } + + return false; + } + + inline int create_dir(const char *path) { + struct stat sb; + while (1) + if (stat(path, &sb) == 0) + if (sb.st_mode & S_IFDIR) + return 0; + else + return EEXIST; + else if (errno != ENOENT) + return errno; + else if (mkdir(path, 0777) == 0) + return 0; + else if (errno != EEXIST) + return errno; + } + + void write_labels_map(); + void read_labels_map(); + +public: + /** + * Loads an existing collection located at collection_path + * or created a new collection if it does not exist + * Returns error if the set does not exist + * + * @param filename Full Path to the collection folder + */ + DescriptorSetData(const std::string &filename); + + /** + * Creates collection located at filename + * or created a new collection if it does not exist + * + * @param filename Full Path to the collection folder + * @param dim Dimension of the descriptor + */ + DescriptorSetData(const std::string &filename, unsigned dim); + + virtual ~DescriptorSetData(); + + DescriptorSetData(const DescriptorSetData &) = delete; + + std::string get_path() { return _set_path; } + + unsigned get_dimensions() { return _dimensions; } + + /** + * Returns the number of descriptors in the set + */ + long get_n_total() { return _n_total; } + + /** + * Inserts n descriptors and their labels into the set + * Both descriptors and labels must have the same number of elements, + * or labels can have no elements. + * If not labels are defined, -1 is assigned to signify "no label". + + * Note: Given the in-memory nature of the Faiss library, adding + * elements on a set using Faiss as engine will not persist the data + * until the store() method is call. This is contrary to the TileDB + * engines, where every add will return after persisting the data. + + * @param descriptors Buffer to descriptors (size n * dim) + * @param n Number of descriptors + * @param labels Array of labels, can be NULL. + */ + virtual long add(float *descriptors, unsigned n_descriptors, + long *labels = NULL) = 0; + + virtual long add_and_store(float *descriptors, unsigned n_descriptors, + long *labels = NULL) { + return 0; + } + + /** + * Search for the k closest neighborhs + * + * @param query Query descriptors buffer + * @param n Number of descriptors that will be queried + * @param k Number of maximun neighbors to be returned + * @return ids id of each neighbor (size n * k) (padded with -1) + * @return distances distances to each neighbor (size n * k). + (padded with -1) + */ + virtual void search(float *query, unsigned n, unsigned k, long *descriptors, + float *distances) = 0; + + virtual void search(float *query, unsigned n, unsigned k, long *descriptors) { + } + + /** + * Search for neighborhs within a radius. + * + * Note: We only allow the radius search of a single + * element to avoid having to deal with results that are + * of different (unknown) sized for each query. + * We will work on it once we have a more clear use case for + * this call + * + * @param query Query vector + * @param radius Maximun distance allowed + * @param ids Array of ID of the descriptors + * @param distances Distances of each neighbor + */ + virtual void radius_search(float *query, float radius, long *descriptors, + float *distances); + + /** + * Find the label of the feature vector, based on the closest + * neighbors. + * + * @param descriptors Buffer to descriptors (size n * dim) + * @param n Number of descriptors in buffer + * @return labels Label Ids + * @param quorum Number of elements used for the classification vote. + */ + virtual void classify(float *descriptors, unsigned n, long *ids, + unsigned quorum) = 0; + + /** + * Get the descriptors by specifiying ids. + * This is an exact search by id. + * + * @param ids buffer with ids + * @param n number of ids to query + * @return descriptors pointer to descriptors buffer + size: (n * dim * sizeof(float)) + */ + virtual void get_descriptors(long *ids, unsigned n, float *descriptors) = 0; + + virtual void get_labels(long *ids, unsigned n, long *labels) = 0; + + /** + * Trains the index with the data present in the collection + * using the specified metric + */ + virtual void train() {} + + /** + * Trains the index using specified descriptors + * + * @param descriptors Reference Descriptors + * @param n Number of descriptors + */ + virtual void train(float *descriptors, unsigned n) { train(); } + + virtual bool is_trained() { return false; } + + virtual void finalize_index() {} + + /** + * Writes the DescriptorSet Index to the system. This will overwrite + * the original + */ + virtual void store() = 0; + + /** + * Writes the DescriptorSet Index to the system into a defined path. + * This will overwrite any other index under the same set_path. + */ + virtual void store(std::string collection_path) = 0; + + // String labels handling + + /** + * Get the label of the descriptors for the spcified ids. + * NOTE: This is a vector becase this is what we return. + * We can, make wrapper functions that recieve arrays as well. + * + * @param ids vector of ids + * @return vector with the string labels + */ + std::vector get_str_labels(long *ids, unsigned n); + + /** + * Get the label of the descriptors for the spcified ids. + * NOTE: This is a vector becase this is what we return. + * We can, make wrapper functions that recieve arrays as well. + * + * @param ids vector of ids + * @return vector with the string labels + */ + std::map get_labels_map() { return _labels_map; } + + /** + * Set the matching between label id and the string corresponding + * to the label + * + * @param ids ids of the labels + * @param labels string for each label + */ + void set_labels_map(std::map &labels); +}; + +}; // namespace VCL \ No newline at end of file diff --git a/src/vcl/Exception.cc b/src/vcl/Exception.cc index d257849e..275b5940 100644 --- a/src/vcl/Exception.cc +++ b/src/vcl/Exception.cc @@ -32,11 +32,10 @@ #include "vcl/Exception.h" -void print_exception(const VCL::Exception &e, FILE *f) -{ - fprintf(f, "[Exception] %s at %s:%d\n", e.name, e.file, e.line); - if (e.errno_val != 0) - fprintf(f, "%s: %s\n", e.msg.c_str(), strerror(e.errno_val)); - else if (!e.msg.empty()) - fprintf(f, "%s\n", e.msg.c_str()); +void print_exception(const VCL::Exception &e, FILE *f) { + fprintf(f, "[Exception] %s at %s:%d\n", e.name, e.file, e.line); + if (e.errno_val != 0) + fprintf(f, "%s: %s\n", e.msg.c_str(), strerror(e.errno_val)); + else if (!e.msg.empty()) + fprintf(f, "%s\n", e.msg.c_str()); } \ No newline at end of file diff --git a/src/vcl/FaissDescriptorSet.cc b/src/vcl/FaissDescriptorSet.cc index a34cb2fe..22c1f33f 100644 --- a/src/vcl/FaissDescriptorSet.cc +++ b/src/vcl/FaissDescriptorSet.cc @@ -27,355 +27,315 @@ * */ -#include -#include -#include #include +#include #include +#include +#include -#include #include +#include -#include "vcl/Exception.h" #include "FaissDescriptorSet.h" +#include "vcl/Exception.h" -#include -#include #include "faiss/impl/AuxIndexStructures.h" +#include +#include #define FAISS_IDX_FILE_NAME "faiss.idx" -#define IDS_IDX_FILE_NAME "ids.arr" +#define IDS_IDX_FILE_NAME "ids.arr" using namespace VCL; -FaissDescriptorSet::FaissDescriptorSet(const std::string &set_path): - DescriptorSetData(set_path) -{ - _index = 0; - _faiss_file = _set_path + "/" + FAISS_IDX_FILE_NAME; - read_label_ids(); - read_labels_map(); +FaissDescriptorSet::FaissDescriptorSet(const std::string &set_path) + : DescriptorSetData(set_path) { + _index = 0; + _faiss_file = _set_path + "/" + FAISS_IDX_FILE_NAME; + read_label_ids(); + read_labels_map(); } FaissDescriptorSet::FaissDescriptorSet(const std::string &set_path, - unsigned dim) : - DescriptorSetData(set_path, dim) -{ - _index = 0; - _faiss_file = _set_path + "/" + FAISS_IDX_FILE_NAME; + unsigned dim) + : DescriptorSetData(set_path, dim) { + _index = 0; + _faiss_file = _set_path + "/" + FAISS_IDX_FILE_NAME; } -FaissDescriptorSet::~FaissDescriptorSet() -{ -} +FaissDescriptorSet::~FaissDescriptorSet() {} -void FaissDescriptorSet::write_label_ids() -{ - std::ofstream out_ids(_set_path + "/" + IDS_IDX_FILE_NAME, - std::ofstream::binary); +void FaissDescriptorSet::write_label_ids() { + std::ofstream out_ids(_set_path + "/" + IDS_IDX_FILE_NAME, + std::ofstream::binary); - unsigned ids_size = _label_ids.size(); - out_ids.write((char*)&ids_size, sizeof(ids_size)); - out_ids.write((char*)_label_ids.data(), sizeof(long) * ids_size); - out_ids.close(); + unsigned ids_size = _label_ids.size(); + out_ids.write((char *)&ids_size, sizeof(ids_size)); + out_ids.write((char *)_label_ids.data(), sizeof(long) * ids_size); + out_ids.close(); } -void FaissDescriptorSet::read_label_ids() -{ - std::ifstream in_ids(_set_path + "/" + IDS_IDX_FILE_NAME, - std::ofstream::binary); +void FaissDescriptorSet::read_label_ids() { + std::ifstream in_ids(_set_path + "/" + IDS_IDX_FILE_NAME, + std::ofstream::binary); - if (!in_ids.good()) { - throw VCLException(OpenFailed, "Cannot read labels file"); - } + if (!in_ids.good()) { + throw VCLException(OpenFailed, "Cannot read labels file"); + } - unsigned ids_size; - in_ids.read((char*)&ids_size, sizeof(ids_size)); - _label_ids.resize(ids_size); - in_ids.read((char*)_label_ids.data(), sizeof(long) * ids_size); - in_ids.close(); + unsigned ids_size; + in_ids.read((char *)&ids_size, sizeof(ids_size)); + _label_ids.resize(ids_size); + in_ids.read((char *)_label_ids.data(), sizeof(long) * ids_size); + in_ids.close(); } -long FaissDescriptorSet::add(float* descriptors, unsigned n, long* labels) -{ - assert(n > 0); +long FaissDescriptorSet::add(float *descriptors, unsigned n, long *labels) { + assert(n > 0); - _lock.lock(); + _lock.lock(); - long id_first = _index->ntotal; + long id_first = _index->ntotal; - if (labels != NULL) { - _label_ids.resize(_index->ntotal + n); - long* dst = _label_ids.data() + _index->ntotal; - std::memcpy(dst, labels, n * sizeof(long)); - } + if (labels != NULL) { + _label_ids.resize(_index->ntotal + n); + long *dst = _label_ids.data() + _index->ntotal; + std::memcpy(dst, labels, n * sizeof(long)); + } - _index->add(n, descriptors); - _n_total = _index->ntotal; - _lock.unlock(); + _index->add(n, descriptors); + _n_total = _index->ntotal; + _lock.unlock(); - return id_first; + return id_first; } +void FaissDescriptorSet::train() { train_core(NULL, 0); } - -void FaissDescriptorSet::train() -{ - train_core(NULL,0); +void FaissDescriptorSet::train(float *descriptors, unsigned n) { + train_core(descriptors, n); } -void FaissDescriptorSet::train(float* descriptors, unsigned n) -{ - train_core(descriptors,n); +void FaissDescriptorSet::train_core(float *descriptors, unsigned n) { + _lock.lock(); + long n_total = _index->ntotal; + float *recons = new float[n_total * _dimensions]; + _index->reconstruct_n(0, n_total, recons); + _index->reset(); + _index->train(n == 0 ? n_total : n, n == 0 ? recons : descriptors); + _index->add(n_total, recons); + _lock.unlock(); + + delete[] recons; } -void FaissDescriptorSet::train_core(float* descriptors, unsigned n) -{ - _lock.lock(); - long n_total = _index->ntotal; - float* recons = new float[n_total * _dimensions]; - _index->reconstruct_n (0, n_total, recons); - _index->reset(); - _index->train(n == 0? n_total : n, n == 0? recons : descriptors); - _index->add(n_total, recons); - _lock.unlock(); - - delete[] recons; -} - -bool FaissDescriptorSet::is_trained() -{ - return _index->is_trained; -} +bool FaissDescriptorSet::is_trained() { return _index->is_trained; } // No need to use locks on this read-only operation as faiss handles internally -void FaissDescriptorSet::search(float* query, unsigned n_queries, unsigned k, - long* descriptors, float* distances) -{ - _index->search(n_queries, query, k, distances, descriptors); +void FaissDescriptorSet::search(float *query, unsigned n_queries, unsigned k, + long *descriptors, float *distances) { + _index->search(n_queries, query, k, distances, descriptors); } -void FaissDescriptorSet::radius_search(float* query, float radius, - long* descriptors, float* distances) -{ - faiss::RangeSearchResult rs(1); // 1 is the Number of queries - _index->range_search(1, query, radius, &rs); - - // rs.lims is of size 2, as nq is of size 1. - // Check faiss::RangeSearchResult definition for more details. - long found = rs.lims[1]; - std::memcpy(descriptors, rs.labels, sizeof(long)*found); - std::memcpy(distances, rs.distances, sizeof(float)*found); +void FaissDescriptorSet::radius_search(float *query, float radius, + long *descriptors, float *distances) { + faiss::RangeSearchResult rs(1); // 1 is the Number of queries + _index->range_search(1, query, radius, &rs); + + // rs.lims is of size 2, as nq is of size 1. + // Check faiss::RangeSearchResult definition for more details. + long found = rs.lims[1]; + std::memcpy(descriptors, rs.labels, sizeof(long) * found); + std::memcpy(distances, rs.distances, sizeof(float) * found); } -void FaissDescriptorSet::classify(float* descriptors, unsigned n, long* ids, - unsigned quorum) -{ - float* distances = new float[n * quorum]; - long* ids_aux = new long [n * quorum]; - - search(descriptors, n, quorum, ids_aux, distances); - - _lock.lock(); - for (int j = 0; j < n; ++j) { - std::map map_voting; - long winner = -1; - unsigned max = 0; - for (int i = 0; i < quorum; ++i) { - long idx = ids_aux[quorum*j + i]; - if (idx < 0) - continue; // Means not found - - long label_id = _label_ids.at(idx); - map_voting[label_id] += 1; - if (max < map_voting[label_id]) { - max = map_voting[label_id]; - winner = label_id; - } - } - ids[j] = winner; +void FaissDescriptorSet::classify(float *descriptors, unsigned n, long *ids, + unsigned quorum) { + float *distances = new float[n * quorum]; + long *ids_aux = new long[n * quorum]; + + search(descriptors, n, quorum, ids_aux, distances); + + _lock.lock(); + for (int j = 0; j < n; ++j) { + std::map map_voting; + long winner = -1; + unsigned max = 0; + for (int i = 0; i < quorum; ++i) { + long idx = ids_aux[quorum * j + i]; + if (idx < 0) + continue; // Means not found + + long label_id = _label_ids.at(idx); + map_voting[label_id] += 1; + if (max < map_voting[label_id]) { + max = map_voting[label_id]; + winner = label_id; + } } - _lock.unlock(); + ids[j] = winner; + } + _lock.unlock(); } -void FaissDescriptorSet::get_labels(long* ids, unsigned n, long* labels) -{ - _lock.lock(); +void FaissDescriptorSet::get_labels(long *ids, unsigned n, long *labels) { + _lock.lock(); - for (int i = 0; i < n; ++i) { - long idx = ids[i]; - if (idx > _label_ids.size()){ - _lock.unlock(); // unlock before throwing exception - throw VCLException(ObjectNotFound, "Label id does not exists"); - } - labels[i] = _label_ids[idx]; + for (int i = 0; i < n; ++i) { + long idx = ids[i]; + if (idx > _label_ids.size()) { + _lock.unlock(); // unlock before throwing exception + throw VCLException(ObjectNotFound, "Label id does not exists"); } + labels[i] = _label_ids[idx]; + } - _lock.unlock(); + _lock.unlock(); } -void FaissDescriptorSet::get_descriptors(long* ids, unsigned n, - float* descriptors) -{ - int offset = 0; - - try { - for (int i = 0; i < n; ++i) { - _index->reconstruct(ids[i], descriptors + i*_dimensions); - } - } catch(faiss::FaissException& e) { - throw VCLException(UndefinedException, "faiss::reconstruct(3) failed"); - } -} +void FaissDescriptorSet::get_descriptors(long *ids, unsigned n, + float *descriptors) { + int offset = 0; -void FaissDescriptorSet::store() -{ - store(_set_path); + try { + for (int i = 0; i < n; ++i) { + _index->reconstruct(ids[i], descriptors + i * _dimensions); + } + } catch (faiss::FaissException &e) { + throw VCLException(UndefinedException, "faiss::reconstruct(3) failed"); + } } -void FaissDescriptorSet::store(std::string set_path) -{ - _lock.lock(); - _set_path = set_path; - _faiss_file = _set_path + "/" + FAISS_IDX_FILE_NAME; +void FaissDescriptorSet::store() { store(_set_path); } - int ret = create_dir(_set_path.c_str()); - if (ret == 0 || ret == EEXIST) { // Directory exists or created - faiss::write_index((const faiss::IndexFlat*)(_index), - _faiss_file.c_str()); - write_label_ids(); - _lock.unlock(); +void FaissDescriptorSet::store(std::string set_path) { + _lock.lock(); + _set_path = set_path; + _faiss_file = _set_path + "/" + FAISS_IDX_FILE_NAME; - write_labels_map(); - } - else { - _lock.unlock(); // unlock before throwing exception - throw VCLException(OpenFailed, _faiss_file + - "cannot be created or written. " + - "Error: " + std::to_string(ret)); - } + int ret = create_dir(_set_path.c_str()); + if (ret == 0 || ret == EEXIST) { // Directory exists or created + faiss::write_index((const faiss::IndexFlat *)(_index), _faiss_file.c_str()); + write_label_ids(); + _lock.unlock(); + write_labels_map(); + } else { + _lock.unlock(); // unlock before throwing exception + throw VCLException(OpenFailed, _faiss_file + + "cannot be created or written. " + + "Error: " + std::to_string(ret)); + } } // FaissFlatDescriptorSet -FaissFlatDescriptorSet::FaissFlatDescriptorSet(const std::string &set_path): - FaissDescriptorSet(set_path) -{ - try { - _index = faiss::read_index(_faiss_file.c_str()); +FaissFlatDescriptorSet::FaissFlatDescriptorSet(const std::string &set_path) + : FaissDescriptorSet(set_path) { + try { + _index = faiss::read_index(_faiss_file.c_str()); - } catch(faiss::FaissException& e) { - throw VCLException(OpenFailed, "Problem reading: " + _faiss_file); - } + } catch (faiss::FaissException &e) { + throw VCLException(OpenFailed, "Problem reading: " + _faiss_file); + } - // Faiss will sometimes throw, or sometimes set _index = NULL, - // we check both just in case. - if (!_index) { - throw VCLException(OpenFailed, "Problem reading: " + _faiss_file); - } + // Faiss will sometimes throw, or sometimes set _index = NULL, + // we check both just in case. + if (!_index) { + throw VCLException(OpenFailed, "Problem reading: " + _faiss_file); + } - _dimensions = _index->d; - _n_total = _index->ntotal; + _dimensions = _index->d; + _n_total = _index->ntotal; } FaissFlatDescriptorSet::FaissFlatDescriptorSet(const std::string &set_path, - unsigned dim, DistanceMetric metric) - : FaissDescriptorSet(set_path, dim) -{ - if (metric == L2) - _index = new faiss::IndexFlatL2(_dimensions); - else if (metric == IP) - _index = new faiss::IndexFlatIP(_dimensions); - else - throw VCLException(UnsupportedIndex, "Metric Not implemented"); + unsigned dim, + DistanceMetric metric) + : FaissDescriptorSet(set_path, dim) { + if (metric == L2) + _index = new faiss::IndexFlatL2(_dimensions); + else if (metric == IP) + _index = new faiss::IndexFlatIP(_dimensions); + else + throw VCLException(UnsupportedIndex, "Metric Not implemented"); } // FaissIVFFlatDescriptorSet -FaissIVFFlatDescriptorSet::FaissIVFFlatDescriptorSet(const std::string &set_path): - FaissDescriptorSet(set_path) -{ - try { - _index = (faiss::IndexIVFFlat*)faiss::read_index(_faiss_file.c_str()); +FaissIVFFlatDescriptorSet::FaissIVFFlatDescriptorSet( + const std::string &set_path) + : FaissDescriptorSet(set_path) { + try { + _index = (faiss::IndexIVFFlat *)faiss::read_index(_faiss_file.c_str()); + + } catch (faiss::FaissException &e) { + throw VCLException(OpenFailed, "Problem reading: " + _faiss_file); + } + + // Faiss will sometimes throw, or sometimes set _index = NULL, + // we check both just in case. + if (!_index) { + throw VCLException(OpenFailed, "Problem reading: " + _faiss_file); + } + + _dimensions = _index->d; + _n_total = _index->ntotal; +} - } catch(faiss::FaissException& e) { - throw VCLException(OpenFailed, "Problem reading: " + _faiss_file); - } +FaissIVFFlatDescriptorSet::FaissIVFFlatDescriptorSet( + const std::string &set_path, unsigned dim, DistanceMetric metric) + : FaissDescriptorSet(set_path, dim) { + // TODO: Revise nlist param for future optimizations. + // 4 is a suggested value by faiss for the IVFFlat index, + // that's why we leave it for now. + int nlist = 4; + + if (metric == L2) { + faiss::IndexFlatL2 *quantizer = new faiss::IndexFlatL2(_dimensions); + + _index = new faiss::IndexIVFFlat(quantizer, _dimensions, nlist, + faiss::METRIC_L2); + } else if (metric == IP) { + faiss::IndexFlatIP *quantizer = new faiss::IndexFlatIP(_dimensions); + + _index = new faiss::IndexIVFFlat(quantizer, _dimensions, nlist, + faiss::METRIC_INNER_PRODUCT); + } else + throw VCLException(UnsupportedIndex, "Metric Not implemented"); +} - // Faiss will sometimes throw, or sometimes set _index = NULL, - // we check both just in case. - if (!_index) { - throw VCLException(OpenFailed, "Problem reading: " + _faiss_file); - } +long FaissIVFFlatDescriptorSet::add(float *descriptors, unsigned n, + long *labels) { + assert(n > 0); - _dimensions = _index->d; - _n_total = _index->ntotal; -} + _lock.lock(); -FaissIVFFlatDescriptorSet::FaissIVFFlatDescriptorSet( - const std::string &set_path, - unsigned dim, DistanceMetric metric) - : FaissDescriptorSet(set_path, dim) -{ - // TODO: Revise nlist param for future optimizations. - // 4 is a suggested value by faiss for the IVFFlat index, - // that's why we leave it for now. - int nlist = 4; - - if (metric == L2) { - faiss::IndexFlatL2* quantizer = - new faiss::IndexFlatL2(_dimensions); - - _index = new faiss::IndexIVFFlat(quantizer, _dimensions, - nlist, - faiss::METRIC_L2); - } - else if (metric == IP) { - faiss::IndexFlatIP* quantizer = - new faiss::IndexFlatIP(_dimensions); + // This index need training before inserting elements. + // This will only happen the first time something is added, + // and will attempt to use the inserted elements for training. + if (!_index->is_trained) { - _index = new faiss::IndexIVFFlat(quantizer, _dimensions, - nlist, - faiss::METRIC_INNER_PRODUCT); - } - else - throw VCLException(UnsupportedIndex, "Metric Not implemented"); -} + long desc_4_training = _dimensions * 100; -long FaissIVFFlatDescriptorSet::add(float* descriptors, - unsigned n, long* labels) -{ - assert(n > 0); - - _lock.lock(); - - // This index need training before inserting elements. - // This will only happen the first time something is added, - // and will attempt to use the inserted elements for training. - if (!_index->is_trained) { - - long desc_4_training = _dimensions * 100; - - if (n < desc_4_training) { - // Train with random data - // The user can later call train() with better data. - std::vector aux_desc(desc_4_training * _dimensions); - std::memcpy(aux_desc.data(), descriptors, - n * _dimensions * sizeof(float)); - _index->train(desc_4_training, aux_desc.data()); - } - else { - _index->train(n, descriptors); - } - - // This is needed for doing reconstructions: - // More info: https://github.com/facebookresearch/faiss/issues/374 - ((faiss::IndexIVFFlat*)_index)->make_direct_map(); + if (n < desc_4_training) { + // Train with random data + // The user can later call train() with better data. + std::vector aux_desc(desc_4_training * _dimensions); + std::memcpy(aux_desc.data(), descriptors, + n * _dimensions * sizeof(float)); + _index->train(desc_4_training, aux_desc.data()); + } else { + _index->train(n, descriptors); } - _lock.unlock(); - long id_first = FaissDescriptorSet::add(descriptors, n, labels); + // This is needed for doing reconstructions: + // More info: https://github.com/facebookresearch/faiss/issues/374 + ((faiss::IndexIVFFlat *)_index)->make_direct_map(); + } + _lock.unlock(); + + long id_first = FaissDescriptorSet::add(descriptors, n, labels); - return id_first; + return id_first; } diff --git a/src/vcl/FaissDescriptorSet.h b/src/vcl/FaissDescriptorSet.h index 0acab4a8..d12badcf 100644 --- a/src/vcl/FaissDescriptorSet.h +++ b/src/vcl/FaissDescriptorSet.h @@ -34,12 +34,12 @@ #pragma once +#include +#include #include #include -#include #include -#include -#include +#include #include "DescriptorSetData.h" @@ -48,73 +48,65 @@ namespace VCL { - class FaissDescriptorSet : public DescriptorSet::DescriptorSetData { - - protected: +class FaissDescriptorSet : public DescriptorSet::DescriptorSetData { - std::string _faiss_file; +protected: + std::string _faiss_file; - faiss::Index* _index; + faiss::Index *_index; - std::mutex _lock; - std::vector _label_ids; + std::mutex _lock; + std::vector _label_ids; - void write_label_ids(); - void read_label_ids(); + void write_label_ids(); + void read_label_ids(); - void train_core(float* descriptors, unsigned n); + void train_core(float *descriptors, unsigned n); - public: +public: + FaissDescriptorSet(const std::string &set_path); + FaissDescriptorSet(const std::string &set_path, unsigned dim); - FaissDescriptorSet(const std::string &set_path); - FaissDescriptorSet(const std::string &set_path, unsigned dim); + ~FaissDescriptorSet(); - ~FaissDescriptorSet(); + virtual long add(float *descriptors, unsigned n_descriptors, long *classes); - virtual long add(float* descriptors, unsigned n_descriptors, - long* classes); + void train(); - void train(); + void train(float *descriptors, unsigned n); - void train(float* descriptors, unsigned n); + bool is_trained(); - bool is_trained(); + void search(float *query, unsigned n, unsigned k, long *ids, + float *distances); - void search(float* query, unsigned n, unsigned k, - long* ids, float* distances); + void radius_search(float *query, float radius, long *ids, float *distances); - void radius_search(float* query, float radius, - long* ids, float* distances); + void classify(float *descriptors, unsigned n, long *ids, unsigned quorum); - void classify(float* descriptors, unsigned n, long* ids, - unsigned quorum); + void get_descriptors(long *ids, unsigned n, float *descriptors); - void get_descriptors(long* ids, unsigned n, float* descriptors); + void get_labels(long *ids, unsigned n, long *labels); - void get_labels(long* ids, unsigned n, long* labels); - - void store(); - void store(std::string set_path); - - }; - - class FaissFlatDescriptorSet : public FaissDescriptorSet { - - public: + void store(); + void store(std::string set_path); +}; - FaissFlatDescriptorSet(const std::string& set_path); - FaissFlatDescriptorSet(const std::string& set_path, unsigned dim, - DistanceMetric metric); - }; +class FaissFlatDescriptorSet : public FaissDescriptorSet { - class FaissIVFFlatDescriptorSet : public FaissDescriptorSet { +public: + FaissFlatDescriptorSet(const std::string &set_path); + FaissFlatDescriptorSet(const std::string &set_path, unsigned dim, + DistanceMetric metric); +}; - public: +class FaissIVFFlatDescriptorSet : public FaissDescriptorSet { - FaissIVFFlatDescriptorSet(const std::string& set_path); - FaissIVFFlatDescriptorSet(const std::string& set_path, unsigned dim, - DistanceMetric metric); +public: + FaissIVFFlatDescriptorSet(const std::string &set_path); + FaissIVFFlatDescriptorSet(const std::string &set_path, unsigned dim, + DistanceMetric metric); - long add(float* descriptors, unsigned n_descriptors, long* classes); - }; + long add(float *descriptors, unsigned n_descriptors, long *classes); }; +}; // namespace VCL diff --git a/src/vcl/FlinngDescriptorSet.cc b/src/vcl/FlinngDescriptorSet.cc index ce9ca300..4f018b52 100644 --- a/src/vcl/FlinngDescriptorSet.cc +++ b/src/vcl/FlinngDescriptorSet.cc @@ -28,278 +28,256 @@ */ #include -#include -#include -#include #include +#include #include +#include +#include -#include #include +#include -#include "vcl/Exception.h" #include "FlinngDescriptorSet.h" - +#include "vcl/Exception.h" #define FLINNG_IDX_FILE_NAME "flinng.idx" -#define IDS_IDX_FILE_NAME "flinng_ids.arr" +#define IDS_IDX_FILE_NAME "flinng_ids.arr" using namespace VCL; -void FlinngDescriptorSet::getFlinngParams(VCL::DescriptorParams* par, flinng::FlinngBuilder* buidler) { - buidler->num_rows = par->num_rows; - buidler->cells_per_row= par->cells_per_row; - buidler->num_hash_tables = par->num_hash_tables; - buidler->hashes_per_table = par->hashes_per_table; - buidler->sub_hash_bits = par->sub_hash_bits; //sub_hash_bits * hashes_per_table must be less than 32, otherwise segfault will happen - buidler->cut_off= par->cut_off; +void FlinngDescriptorSet::getFlinngParams(VCL::DescriptorParams *par, + flinng::FlinngBuilder *buidler) { + buidler->num_rows = par->num_rows; + buidler->cells_per_row = par->cells_per_row; + buidler->num_hash_tables = par->num_hash_tables; + buidler->hashes_per_table = par->hashes_per_table; + buidler->sub_hash_bits = + par->sub_hash_bits; // sub_hash_bits * hashes_per_table must be less than + // 32, otherwise segfault will happen + buidler->cut_off = par->cut_off; } -FlinngDescriptorSet::FlinngDescriptorSet(const std::string &set_path): - DescriptorSetData(set_path) -{ - _flinng_file = _set_path + "/" + FLINNG_IDX_FILE_NAME; - _index = flinng::BaseDenseFlinng32::from_index(_flinng_file.c_str()); - is_finalized=false; - read_label_ids(); - read_labels_map(); +FlinngDescriptorSet::FlinngDescriptorSet(const std::string &set_path) + : DescriptorSetData(set_path) { + _flinng_file = _set_path + "/" + FLINNG_IDX_FILE_NAME; + _index = flinng::BaseDenseFlinng32::from_index(_flinng_file.c_str()); + is_finalized = false; + read_label_ids(); + read_labels_map(); } FlinngDescriptorSet::FlinngDescriptorSet(const std::string &set_path, - unsigned dim, DistanceMetric metric, VCL::DescriptorParams* par) : - DescriptorSetData(set_path, dim) -{ - _index = 0; - _flinng_file = _set_path + "/" + FLINNG_IDX_FILE_NAME; - is_finalized=false; - flinng::FlinngBuilder* builder = new flinng::FlinngBuilder(); - getFlinngParams(par, builder); - - if (metric == L2) { - _index = new flinng::L2DenseFlinng32(dim, builder); - //_index = new L2DenseFlinng32(num_rows, cells_per_row, data_dimension, num_hash_tables, hashes_per_table, sub_hash_bits, cutoff); - - } - else if (metric == IP) { - _index = new flinng::DenseFlinng32(dim, builder); - //_index = new DenseFlinng32(num_rows, cells_per_row, data_dimension, num_hash_tables, hashes_per_table); - } - else - throw VCLException(UnsupportedIndex, "Metric Not implemented"); - + unsigned dim, DistanceMetric metric, + VCL::DescriptorParams *par) + : DescriptorSetData(set_path, dim) { + _index = 0; + _flinng_file = _set_path + "/" + FLINNG_IDX_FILE_NAME; + is_finalized = false; + flinng::FlinngBuilder *builder = new flinng::FlinngBuilder(); + getFlinngParams(par, builder); + + if (metric == L2) { + _index = new flinng::L2DenseFlinng32(dim, builder); + //_index = new L2DenseFlinng32(num_rows, cells_per_row, data_dimension, + // num_hash_tables, hashes_per_table, sub_hash_bits, cutoff); + + } else if (metric == IP) { + _index = new flinng::DenseFlinng32(dim, builder); + //_index = new DenseFlinng32(num_rows, cells_per_row, data_dimension, + // num_hash_tables, hashes_per_table); + } else + throw VCLException(UnsupportedIndex, "Metric Not implemented"); } -FlinngDescriptorSet::~FlinngDescriptorSet() -{ -} +FlinngDescriptorSet::~FlinngDescriptorSet() {} void FlinngDescriptorSet::finalize_index() { - _index->finalize_construction(); - //placeholder for any operations post indexing + _index->finalize_construction(); + // placeholder for any operations post indexing } -void FlinngDescriptorSet::write_label_ids() -{ - std::ofstream out_ids(_set_path + "/" + IDS_IDX_FILE_NAME, - std::ofstream::binary); +void FlinngDescriptorSet::write_label_ids() { + std::ofstream out_ids(_set_path + "/" + IDS_IDX_FILE_NAME, + std::ofstream::binary); - unsigned ids_size = _label_ids.size(); - out_ids.write((char*)&ids_size, sizeof(ids_size)); - out_ids.write((char*)_label_ids.data(), sizeof(long) * ids_size); - out_ids.close(); + unsigned ids_size = _label_ids.size(); + out_ids.write((char *)&ids_size, sizeof(ids_size)); + out_ids.write((char *)_label_ids.data(), sizeof(long) * ids_size); + out_ids.close(); } -void FlinngDescriptorSet::read_label_ids() -{ - std::ifstream in_ids(_set_path + "/" + IDS_IDX_FILE_NAME, - std::ofstream::binary); +void FlinngDescriptorSet::read_label_ids() { + std::ifstream in_ids(_set_path + "/" + IDS_IDX_FILE_NAME, + std::ofstream::binary); - if (!in_ids.good()) { - throw VCLException(OpenFailed, "Cannot read labels file"); - } + if (!in_ids.good()) { + throw VCLException(OpenFailed, "Cannot read labels file"); + } - unsigned ids_size; - in_ids.read((char*)&ids_size, sizeof(ids_size)); - _label_ids.resize(ids_size); - in_ids.read((char*)_label_ids.data(), sizeof(long) * ids_size); - in_ids.close(); + unsigned ids_size; + in_ids.read((char *)&ids_size, sizeof(ids_size)); + _label_ids.resize(ids_size); + in_ids.read((char *)_label_ids.data(), sizeof(long) * ids_size); + in_ids.close(); } -long FlinngDescriptorSet::add(float* descriptors, unsigned n, long* labels=NULL) -{ - assert(n > 0); +long FlinngDescriptorSet::add(float *descriptors, unsigned n, + long *labels = NULL) { + assert(n > 0); - _lock.lock(); + _lock.lock(); - is_finalized=false; - + is_finalized = false; - long id_first = _n_total; + long id_first = _n_total; - if (labels != NULL) { - _label_ids.resize(_n_total + n); - long* dst = _label_ids.data() + _n_total; - memcpy(dst, labels, n * sizeof(long)); - } + if (labels != NULL) { + _label_ids.resize(_n_total + n); + long *dst = _label_ids.data() + _n_total; + memcpy(dst, labels, n * sizeof(long)); + } - _index->add(descriptors, n); - _n_total +=n; - - _lock.unlock(); - return id_first; + _index->add(descriptors, n); + _n_total += n; + + _lock.unlock(); + return id_first; } -long FlinngDescriptorSet::add_and_store(float* descriptors, unsigned n, long* labels=NULL) -{ - assert(n > 0); +long FlinngDescriptorSet::add_and_store(float *descriptors, unsigned n, + long *labels = NULL) { + assert(n > 0); - _lock.lock(); - - is_finalized=false; + _lock.lock(); - long id_first = _n_total; + is_finalized = false; - if (labels != NULL) { - _label_ids.resize(_n_total + n); - long* dst = _label_ids.data() + _n_total; - - memcpy(dst, labels, n * sizeof(long)); - } - - _index->add_and_store(descriptors, n); - _n_total += n; - _lock.unlock(); - return id_first; -} + long id_first = _n_total; + if (labels != NULL) { + _label_ids.resize(_n_total + n); + long *dst = _label_ids.data() + _n_total; + memcpy(dst, labels, n * sizeof(long)); + } -void FlinngDescriptorSet::train() -{ - throw VCLException(NotImplemented, "Train Operation not supported for used Index"); - //Not applicable for flinng + _index->add_and_store(descriptors, n); + _n_total += n; + _lock.unlock(); + return id_first; } -void FlinngDescriptorSet::train(float* descriptors, unsigned n) -{ - throw VCLException(NotImplemented, "Train Operation not supported for used Index"); - //Not applicable for flinng +void FlinngDescriptorSet::train() { + throw VCLException(NotImplemented, + "Train Operation not supported for used Index"); + // Not applicable for flinng } -bool FlinngDescriptorSet::is_trained() -{ - return false; +void FlinngDescriptorSet::train(float *descriptors, unsigned n) { + throw VCLException(NotImplemented, + "Train Operation not supported for used Index"); + // Not applicable for flinng } +bool FlinngDescriptorSet::is_trained() { return false; } -void FlinngDescriptorSet::search(float* query, unsigned n_queries, unsigned k, - long * descriptors, float* distances) -{ - if(!is_finalized){ - _lock.lock(); - finalize_index(); - is_finalized=true; - _lock.unlock(); - } - _index->search_with_distance(query, n_queries, k, descriptors, distances); +void FlinngDescriptorSet::search(float *query, unsigned n_queries, unsigned k, + long *descriptors, float *distances) { + if (!is_finalized) { + _lock.lock(); + finalize_index(); + is_finalized = true; + _lock.unlock(); + } + _index->search_with_distance(query, n_queries, k, descriptors, distances); } -void FlinngDescriptorSet::search(float* query, unsigned n_queries, unsigned k, - long * descriptors) -{ - if(!is_finalized){ - _lock.lock(); - finalize_index(); - is_finalized=true; - _lock.unlock(); - } - _index->search(query, n_queries, k, descriptors); - +void FlinngDescriptorSet::search(float *query, unsigned n_queries, unsigned k, + long *descriptors) { + if (!is_finalized) { + _lock.lock(); + finalize_index(); + is_finalized = true; + _lock.unlock(); + } + _index->search(query, n_queries, k, descriptors); } -void FlinngDescriptorSet::radius_search(float* query, float radius, - long * descriptors, float* distances) -{ - throw VCLException(NotImplemented, "Radius Search Operation not supported for used Index"); - //TODO +void FlinngDescriptorSet::radius_search(float *query, float radius, + long *descriptors, float *distances) { + throw VCLException(NotImplemented, + "Radius Search Operation not supported for used Index"); + // TODO } -void FlinngDescriptorSet::classify(float* descriptors, unsigned n, long* ids, - unsigned quorum) -{ - float* distances = new float[n * quorum]; - long* ids_aux = new long [n * quorum]; - - search(descriptors, n, quorum, ids_aux, distances); - - _lock.lock(); - for (int j = 0; j < n; ++j) { - std::map map_voting; - long winner = -1; - unsigned max = 0; - for (int i = 0; i < quorum; ++i) { - long idx = ids_aux[quorum*j + i]; - if (idx < 0) - continue; // Means not found - - long label_id = _label_ids.at(idx); - map_voting[label_id] += 1; - if (max < map_voting[label_id]) { - max = map_voting[label_id]; - winner = label_id; - } - } - ids[j] = winner; +void FlinngDescriptorSet::classify(float *descriptors, unsigned n, long *ids, + unsigned quorum) { + float *distances = new float[n * quorum]; + long *ids_aux = new long[n * quorum]; + + search(descriptors, n, quorum, ids_aux, distances); + + _lock.lock(); + for (int j = 0; j < n; ++j) { + std::map map_voting; + long winner = -1; + unsigned max = 0; + for (int i = 0; i < quorum; ++i) { + long idx = ids_aux[quorum * j + i]; + if (idx < 0) + continue; // Means not found + + long label_id = _label_ids.at(idx); + map_voting[label_id] += 1; + if (max < map_voting[label_id]) { + max = map_voting[label_id]; + winner = label_id; + } } - _lock.unlock(); + ids[j] = winner; + } + _lock.unlock(); } -void FlinngDescriptorSet::get_labels(long* ids, unsigned n, long* labels) -{ - _lock.lock(); +void FlinngDescriptorSet::get_labels(long *ids, unsigned n, long *labels) { + _lock.lock(); - for (int i = 0; i < n; ++i) { - long idx = ids[i]; - if (idx > _label_ids.size()){ - throw VCLException(ObjectNotFound, "Label id does not exists"); - } - labels[i] = _label_ids[idx]; + for (int i = 0; i < n; ++i) { + long idx = ids[i]; + if (idx > _label_ids.size()) { + throw VCLException(ObjectNotFound, "Label id does not exists"); } + labels[i] = _label_ids[idx]; + } - _lock.unlock(); + _lock.unlock(); } -void FlinngDescriptorSet::get_descriptors(long* ids, unsigned n, - float* descriptors) -{ - int offset = 0; - for (int i = 0; i < n; ++i) { - _index->fetch_descriptors(ids[i], descriptors + i*_dimensions); - } +void FlinngDescriptorSet::get_descriptors(long *ids, unsigned n, + float *descriptors) { + int offset = 0; + for (int i = 0; i < n; ++i) { + _index->fetch_descriptors(ids[i], descriptors + i * _dimensions); + } } -void FlinngDescriptorSet::store() -{ - store(_set_path); -} +void FlinngDescriptorSet::store() { store(_set_path); } -void FlinngDescriptorSet::store(std::string set_path) -{ - _lock.lock(); - _set_path = set_path; - _flinng_file = _set_path + "/" + FLINNG_IDX_FILE_NAME; +void FlinngDescriptorSet::store(std::string set_path) { + _lock.lock(); + _set_path = set_path; + _flinng_file = _set_path + "/" + FLINNG_IDX_FILE_NAME; - int ret = create_dir(_set_path.c_str()); - if (ret == 0 || ret == EEXIST) { // Directory exists or created - _index->write_index(_flinng_file.c_str()); - write_label_ids(); - _lock.unlock(); + int ret = create_dir(_set_path.c_str()); + if (ret == 0 || ret == EEXIST) { // Directory exists or created + _index->write_index(_flinng_file.c_str()); + write_label_ids(); + _lock.unlock(); - write_labels_map(); - } - else { - throw VCLException(OpenFailed, _flinng_file + - "cannot be created or written. " + - "Error: " + std::to_string(ret)); - } -} + write_labels_map(); + } else { + throw VCLException(OpenFailed, _flinng_file + + "cannot be created or written. " + + "Error: " + std::to_string(ret)); + } +} diff --git a/src/vcl/FlinngDescriptorSet.h b/src/vcl/FlinngDescriptorSet.h index 3de438fe..288dbe00 100644 --- a/src/vcl/FlinngDescriptorSet.h +++ b/src/vcl/FlinngDescriptorSet.h @@ -34,82 +34,74 @@ #pragma once +#include +#include #include #include -#include #include -#include -#include +#include #include "DescriptorSetData.h" -//#include "../../../FLINNG/include/lib_flinng.h" //todo update make files for flinng lib include directory +//#include "../../../FLINNG/include/lib_flinng.h" //todo update make files for +// flinng lib include directory +#include "DescriptorParams.h" #include "lib_flinng.h" -#include "DescriptorParams.h" - - namespace VCL { - class FlinngDescriptorSet : public DescriptorSet::DescriptorSetData { - - protected: - - std::string _flinng_file; - bool is_finalized; +class FlinngDescriptorSet : public DescriptorSet::DescriptorSetData { - flinng::BaseDenseFlinng32* _index; //FLinng have a base class by this name - //depending on metric to be used will point to the right index - flinng::FlinngBuilder* _builder; - +protected: + std::string _flinng_file; + bool is_finalized; - std::mutex _lock; - std::vector _label_ids; + flinng::BaseDenseFlinng32 *_index; // FLinng have a base class by this name + // depending on metric to be used will point to the right index + flinng::FlinngBuilder *_builder; - void write_label_ids(); - void read_label_ids(); + std::mutex _lock; + std::vector _label_ids; - void train_core(float* descriptors, unsigned n); - void getFlinngParams(VCL::DescriptorParams* par, flinng::FlinngBuilder* builder); + void write_label_ids(); + void read_label_ids(); - public: + void train_core(float *descriptors, unsigned n); + void getFlinngParams(VCL::DescriptorParams *par, + flinng::FlinngBuilder *builder); - FlinngDescriptorSet(const std::string &set_path); - FlinngDescriptorSet(const std::string &set_path, unsigned dim, DistanceMetric metric, VCL::DescriptorParams* par = NULL); +public: + FlinngDescriptorSet(const std::string &set_path); + FlinngDescriptorSet(const std::string &set_path, unsigned dim, + DistanceMetric metric, VCL::DescriptorParams *par = NULL); + ~FlinngDescriptorSet(); - ~FlinngDescriptorSet(); + virtual long add(float *descriptors, unsigned n_descriptors, long *classes); + virtual long add_and_store(float *descriptors, unsigned n_descriptors, + long *classes); - virtual long add(float* descriptors, unsigned n_descriptors, - long* classes); - virtual long add_and_store(float* descriptors, unsigned n_descriptors, long* classes); + void train(); - void train(); + void train(float *descriptors, unsigned n); - void train(float* descriptors, unsigned n); + bool is_trained(); - bool is_trained(); + void finalize_index(); - void finalize_index(); + void search(float *query, unsigned n, unsigned k, long *ids); - void search(float* query, unsigned n, unsigned k, - long* ids); + void search(float *query, unsigned n, unsigned k, long *ids, + float *distances); - void search(float* query, unsigned n, unsigned k, - long* ids, float* distances); + void radius_search(float *query, float radius, long *ids, float *distances); - void radius_search(float* query, float radius, - long* ids, float* distances); + void classify(float *descriptors, unsigned n, long *ids, unsigned quorum); - void classify(float* descriptors, unsigned n, long* ids, - unsigned quorum); + void get_descriptors(long *ids, unsigned n, float *descriptors); - void get_descriptors(long* ids, unsigned n, float* descriptors); + void get_labels(long *ids, unsigned n, long *labels); - void get_labels(long* ids, unsigned n, long* labels); - - void store(); - void store(std::string set_path); - - }; + void store(); + void store(std::string set_path); }; - +}; // namespace VCL diff --git a/src/vcl/Image.cc b/src/vcl/Image.cc index dcb9dad2..2bd64c9d 100644 --- a/src/vcl/Image.cc +++ b/src/vcl/Image.cc @@ -5,7 +5,7 @@ * * The MIT License * - * @copyright Copyright (c) 2017 Intel Corporation + * @copyright Copyright (c) 2023 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,940 +27,1233 @@ * */ +#include +#include +#include #include +#include +#include +#include -#include "vcl/Image.h" #include "vcl/Exception.h" +#include "vcl/Image.h" using namespace VCL; - /* *********************** */ - /* OPERATION */ - /* *********************** */ +/* *********************** */ +/* OPERATION */ +/* *********************** */ - /* *********************** */ - /* READ OPERATION */ - /* *********************** */ +/* *********************** */ +/* READ OPERATION */ +/* *********************** */ -Image::Read::Read(const std::string& filename, Image::Format format) - : Operation(format), - _fullpath(filename) -{ -} +Image::Read::Read(const std::string &filename, Image::Format format) + : Operation(format), _fullpath(filename) {} + +void Image::Read::operator()(Image *img) { + std::string typestr = img->_storage == Storage::LOCAL ? "LOCAL" : "AWS"; -void Image::Read::operator()(Image *img) -{ - if ( _format == Image::Format::TDB ) { - if ( img->_tdb == NULL ) - throw VCLException(TileDBNotFound, "Image::Format indicates image \ + if (_format == Image::Format::TDB) { + if (img->_tdb == NULL) + throw VCLException(TileDBNotFound, "Image::Format indicates image \ stored in TDB format, but no data was found"); - img->_tdb->read(); - img->_height = img->_tdb->get_image_height(); - img->_width = img->_tdb->get_image_width(); - img->_channels = img->_tdb->get_image_channels(); - } - else if(_format == Image::Format::BIN) - { - FILE * bin_file; - bin_file = fopen(_fullpath.c_str(), "rb"); - if(bin_file != NULL) - { - img->_bin = (char*) malloc (sizeof(char)*img->_bin_size); - if (img->_bin != NULL) - fread (img->_bin,1,img->_bin_size,bin_file); - fclose(bin_file); - } - else - { - throw VCLException(OpenFailed, _fullpath + " could not be written"); - } - } - else - { - cv::Mat img_read = cv::imread(_fullpath, cv::IMREAD_ANYCOLOR); - img->shallow_copy_cv(img_read); - if ( img->_cv_img.empty() ) - throw VCLException(ObjectEmpty, _fullpath + " could not be read, \ - object is empty"); + img->_tdb->read(); + img->_height = img->_tdb->get_image_height(); + img->_width = img->_tdb->get_image_width(); + img->_channels = img->_tdb->get_image_channels(); + } else if (img->_storage == Storage::LOCAL) { + if (_format == Image::Format::BIN) { + FILE *bin_file; + bin_file = fopen(_fullpath.c_str(), "rb"); + if (bin_file != NULL) { + img->_bin = (char *)malloc(sizeof(char) * img->_bin_size); + if (img->_bin != NULL) + fread(img->_bin, 1, img->_bin_size, bin_file); + fclose(bin_file); + } else { + throw VCLException(OpenFailed, _fullpath + " could not be written"); + } + } else { + cv::Mat img_read = cv::imread(_fullpath, cv::IMREAD_ANYCOLOR); + img->shallow_copy_cv(img_read); + if (img->_cv_img.empty()) + throw VCLException(ObjectEmpty, + _fullpath + " could not be read, object is empty"); } - - + } else //_type == S3 + { + std::vector data = img->_remote->Read(_fullpath); + if (!data.empty()) + img->deep_copy_cv(cv::imdecode(cv::Mat(data), cv::IMREAD_ANYCOLOR)); + else + throw VCLException( + ObjectEmpty, _fullpath + " could not be read from RemoteConnection"); + } } - /* *********************** */ - /* WRITE OPERATION */ - /* *********************** */ +/* *********************** */ +/* WRITE OPERATION */ +/* *********************** */ + +Image::Write::Write(const std::string &filename, Image::Format format, + Image::Format old_format, bool metadata) + : Operation(format), _old_format(old_format), _metadata(metadata), + _fullpath(filename) {} + +void Image::Write::operator()(Image *img) { + if (_format == Image::Format::TDB) { + if (img->_tdb == NULL) { + if (img->_storage == Storage::LOCAL) { + img->_tdb = new TDBImage(_fullpath); + img->_tdb->set_compression(img->_compress); + } else if (img->_storage == Storage::AWS) { + img->_tdb = new TDBImage(_fullpath, *(img->_remote)); + } else { + throw VCLException( + UnsupportedSystem, + "The system specified by the path is not supported currently"); + } + } -Image::Write::Write(const std::string& filename, Image::Format format, - Image::Format old_format, bool metadata) - : Operation(format), - _old_format(old_format), - _metadata(metadata), - _fullpath(filename) -{ + if (img->_tdb->has_data()) { + if (img->_storage == Storage::LOCAL) { + img->_tdb->set_configuration(img->_remote); + } + img->_tdb->write(_fullpath, _metadata); + } else { + img->_tdb->write(img->_cv_img, _metadata); + } + } else if (_format == Image::Format::BIN) // TODO: Implement Remote + { + FILE *bin_file; + bin_file = fopen(_fullpath.c_str(), "wb"); + if (bin_file != NULL) { + fwrite(img->_bin, sizeof(char), img->_bin_size, bin_file); + fclose(bin_file); + } else { + throw VCLException(OpenFailed, _fullpath + " could not be written"); + } + } else { + cv::Mat cv_img; + if (_old_format == Image::Format::TDB) + cv_img = img->_tdb->get_cvmat(); + else + cv_img = img->_cv_img; + + if (!cv_img.empty()) { + if (img->_storage == Storage::LOCAL) { + cv::imwrite(_fullpath, cv_img); + } else { + std::vector data; + std::string ext = "." + img->format_to_string(_format); + cv::imencode(ext, cv_img, data); + img->_remote->Write(_fullpath, data); + } + } else + throw VCLException(ObjectEmpty, + _fullpath + " could not be written, object is empty"); + } } -void Image::Write::operator()(Image *img) -{ - - if (_format == Image::Format::TDB) { - if ( img->_tdb == NULL ) { - img->_tdb = new TDBImage(_fullpath); - img->_tdb->set_compression(img->_compress); - } +/* *********************** */ +/* RESIZE OPERATION */ +/* *********************** */ + +void Image::Resize::operator()(Image *img) { + if (_format == Image::Format::TDB) { + img->_tdb->resize(_rect); + img->_height = img->_tdb->get_image_height(); + img->_width = img->_tdb->get_image_width(); + img->_channels = img->_tdb->get_image_channels(); + } else { + if (!img->_cv_img.empty()) { + cv::Mat cv_resized; + cv::resize(img->_cv_img, cv_resized, cv::Size(_rect.width, _rect.height)); + img->shallow_copy_cv(cv_resized); + } else + throw VCLException(ObjectEmpty, "Image object is empty"); + } + img->_op_completed++; +} - if ( img->_tdb->has_data() ) - img->_tdb->write(_fullpath, _metadata); - else - img->_tdb->write(img->_cv_img, _metadata); - } - else if(_format == Image::Format::BIN) - { - FILE * bin_file; - bin_file = fopen (_fullpath.c_str(), "wb"); - if(bin_file != NULL) - { - fwrite(img->_bin , sizeof(char), img->_bin_size, bin_file); - fclose(bin_file); - } - else - { - throw VCLException(OpenFailed, _fullpath + " could not be written"); - } - } - else { - cv::Mat cv_img; - if (_old_format == Image::Format::TDB) - cv_img = img->_tdb->get_cvmat(); - else - cv_img = img->_cv_img; - - if ( !cv_img.empty() ) - cv::imwrite(_fullpath, cv_img); - - else - throw VCLException(ObjectEmpty, _fullpath + " could not be written \ - object is empty"); - } +/* *********************** */ +/* CROP OPERATION */ +/* *********************** */ + +void Image::Crop::operator()(Image *img) { + if (_format == Image::Format::TDB) { + img->_tdb->read(_rect); + img->_height = img->_tdb->get_image_height(); + img->_width = img->_tdb->get_image_width(); + img->_channels = img->_tdb->get_image_channels(); + } else { + if (!img->_cv_img.empty()) { + if (img->_cv_img.rows < _rect.height + _rect.y || + img->_cv_img.cols < _rect.width + _rect.x) + throw VCLException(SizeMismatch, + "Requested area is not within the image"); + cv::Mat roi_img(img->_cv_img, _rect); + img->shallow_copy_cv(roi_img); + } else + throw VCLException(ObjectEmpty, "Image object is empty"); + } + img->_op_completed++; } - /* *********************** */ - /* RESIZE OPERATION */ - /* *********************** */ +/* *********************** */ +/* THRESHOLD OPERATION */ +/* *********************** */ + +void Image::Threshold::operator()(Image *img) { + if (_format == Image::Format::TDB) + img->_tdb->threshold(_threshold); + else { + if (!img->_cv_img.empty()) + cv::threshold(img->_cv_img, img->_cv_img, _threshold, _threshold, + cv::THRESH_TOZERO); + else + throw VCLException(ObjectEmpty, "Image object is empty"); + } + img->_op_completed++; +} -void Image::Resize::operator()(Image *img) -{ - if ( _format == Image::Format::TDB ) { - img->_tdb->resize(_rect); - img->_height = img->_tdb->get_image_height(); - img->_width = img->_tdb->get_image_width(); - img->_channels = img->_tdb->get_image_channels(); - } - else { - if ( !img->_cv_img.empty() ) { - cv::Mat cv_resized; - cv::resize(img->_cv_img, cv_resized, cv::Size(_rect.width, _rect.height)); - img->shallow_copy_cv(cv_resized); - } - else - throw VCLException(ObjectEmpty, "Image object is empty"); - } +/* *********************** */ +/* FLIP OPERATION */ +/* *********************** */ + +void Image::Flip::operator()(Image *img) { + if (_format == Image::Format::TDB) { + // Not implemented + throw VCLException(NotImplemented, + "Operation not supported for this format"); + } else { + if (!img->_cv_img.empty()) { + cv::Mat dst = + cv::Mat(img->_cv_img.rows, img->_cv_img.cols, img->_cv_img.type()); + cv::flip(img->_cv_img, dst, _code); + img->shallow_copy_cv(dst); + } else + throw VCLException(ObjectEmpty, "Image object is empty"); + } + img->_op_completed++; } - /* *********************** */ - /* CROP OPERATION */ - /* *********************** */ +/* *********************** */ +/* ROTATE OPERATION */ +/* *********************** */ + +void Image::Rotate::operator()(Image *img) { + if (_format == Image::Format::TDB) { + // Not implemented + throw VCLException(NotImplemented, + "Operation not supported for this format"); + } else { + if (!img->_cv_img.empty()) { + + if (_keep_size) { + cv::Mat dst = + cv::Mat(img->_cv_img.rows, img->_cv_img.cols, img->_cv_img.type()); + + cv::Point2f im_c(img->_cv_img.cols / 2., img->_cv_img.rows / 2.); + cv::Mat r = cv::getRotationMatrix2D(im_c, _angle, 1.0); + + cv::warpAffine(img->_cv_img, dst, r, img->_cv_img.size()); + img->_cv_img = dst.clone(); + } else { + + cv::Point2f im_c((img->_cv_img.cols - 1) / 2.0, + (img->_cv_img.rows - 1) / 2.0); + cv::Mat r = cv::getRotationMatrix2D(im_c, _angle, 1.0); + // Bbox rectangle + cv::Rect2f bbox = + cv::RotatedRect(cv::Point2f(), img->_cv_img.size(), _angle) + .boundingRect2f(); + // Transformation Matrix + r.at(0, 2) += bbox.width / 2.0 - img->_cv_img.cols / 2.0; + r.at(1, 2) += bbox.height / 2.0 - img->_cv_img.rows / 2.0; + + cv::Mat dst; + cv::warpAffine(img->_cv_img, dst, r, bbox.size()); + img->shallow_copy_cv(dst); + } + } else + throw VCLException(ObjectEmpty, "Image object is empty"); + } + img->_op_completed++; +} -void Image::Crop::operator()(Image *img) -{ - if ( _format == Image::Format::TDB ) { - img->_tdb->read(_rect); - img->_height = img->_tdb->get_image_height(); - img->_width = img->_tdb->get_image_width(); - img->_channels = img->_tdb->get_image_channels(); - } - else { - if ( !img->_cv_img.empty() ) { - if ( img->_cv_img.rows < _rect.height + _rect.y || img->_cv_img.cols < _rect.width + _rect.x ) - throw VCLException(SizeMismatch, "Requested area is not within the image"); - cv::Mat roi_img(img->_cv_img, _rect); - img->shallow_copy_cv(roi_img); - } - else - throw VCLException(ObjectEmpty, "Image object is empty"); - } +/* *********************** */ +/* REMOTE OPERATION */ +/* *********************** */ + +void Image::RemoteOperation::operator()(Image *img) { + if (_format == Image::Format::TDB) { + // Not implemented + throw VCLException(NotImplemented, + "Operation not supported for this format"); + } else { + if (!img->_cv_img.empty()) { + img->set_remoteOp_params(_options, _url); + } else + throw VCLException(ObjectEmpty, "Image object is empty"); + } } - /* *********************** */ - /* THRESHOLD OPERATION */ - /* *********************** */ - -void Image::Threshold::operator()(Image *img) -{ - if ( _format == Image::Format::TDB ) - img->_tdb->threshold(_threshold); - else { - if ( !img->_cv_img.empty() ) - cv::threshold(img->_cv_img, img->_cv_img, _threshold, _threshold, - cv::THRESH_TOZERO); - else - throw VCLException(ObjectEmpty, "Image object is empty"); - } +/* *********************** */ +/* SYNCREMOTE OPERATION */ +/* *********************** */ + +size_t writeCallback(char *ip, size_t size, size_t nmemb, void *op) { + ((std::string *)op)->append((char *)ip, size * nmemb); + return size * nmemb; } - /* *********************** */ - /* FLIP OPERATION */ - /* *********************** */ +void Image::SyncRemoteOperation::operator()(Image *img) { + if (_format == Image::Format::TDB) { + // Not implemented + throw VCLException(NotImplemented, + "Operation not supported for this format"); + } else { + if (!img->_cv_img.empty()) { -void Image::Flip::operator()(Image *img) -{ - if ( _format == Image::Format::TDB ) { - // Not implemented - throw VCLException(NotImplemented, - "Operation not supported for this format"); - } - else { - if ( !img->_cv_img.empty() ) { - cv::Mat dst = cv::Mat(img->_cv_img.rows, img->_cv_img.cols, - img->_cv_img.type()); - cv::flip(img->_cv_img, dst, _code); - img->shallow_copy_cv(dst); + std::string readBuffer; + + CURL *curl = NULL; + + CURLcode res; + struct curl_slist *headers = NULL; + curl_mime *form = NULL; + curl_mimepart *field = NULL; + + curl = curl_easy_init(); + + if (curl) { + auto time_now = std::chrono::system_clock::now(); + std::chrono::duration utc_time = time_now.time_since_epoch(); + + VCL::Image::Format img_format = img->get_image_format(); + std::string format = img->format_to_string(img_format); + + if (format == "" && _options.isMember("format")) { + format = _options["format"].toStyledString().data(); + format.erase(std::remove(format.begin(), format.end(), '\n'), + format.end()); + format = format.substr(1, format.size() - 2); + } else { + format = "jpg"; } - else - throw VCLException(ObjectEmpty, "Image object is empty"); - } -} - /* *********************** */ - /* ROTATE OPERATION */ - /* *********************** */ + std::string filePath = + "/tmp/tempfile" + std::to_string(utc_time.count()) + "." + format; + cv::imwrite(filePath, img->_cv_img); -void Image::Rotate::operator()(Image *img) -{ - if ( _format == Image::Format::TDB ) { - // Not implemented - throw VCLException(NotImplemented, - "Operation not supported for this format"); - } - else { - if ( !img->_cv_img.empty() ) { - - if (_keep_size) { - cv::Mat dst = cv::Mat(img->_cv_img.rows, img->_cv_img.cols, - img->_cv_img.type()); - - cv::Point2f im_c(img->_cv_img.cols/2., img->_cv_img.rows/2.); - cv::Mat r = cv::getRotationMatrix2D(im_c, _angle, 1.0); - - cv::warpAffine(img->_cv_img, dst, r, img->_cv_img.size()); - img->_cv_img = dst.clone(); - } - else { - - cv::Point2f im_c((img->_cv_img.cols-1)/2.0, - (img->_cv_img.rows-1)/2.0); - cv::Mat r = cv::getRotationMatrix2D(im_c, _angle, 1.0); - // Bbox rectangle - cv::Rect2f bbox = cv::RotatedRect(cv::Point2f(), - img->_cv_img.size(), - _angle) - .boundingRect2f(); - // Transformation Matrix - r.at(0,2) += bbox.width/2.0 - img->_cv_img.cols/2.0; - r.at(1,2) += bbox.height/2.0 - img->_cv_img.rows/2.0; - - cv::Mat dst; - cv::warpAffine(img->_cv_img, dst, r, bbox.size()); - img->shallow_copy_cv(dst); - } + std::ofstream tsfile; + + auto opstart = std::chrono::system_clock::now(); + + form = curl_mime_init(curl); + + field = curl_mime_addpart(form); + curl_mime_name(field, "imageData"); + if (curl_mime_filedata(field, filePath.data()) != CURLE_OK) { + if (std::remove(filePath.data()) != 0) { + } + throw VCLException(ObjectEmpty, "Unable to create file for remoting"); } - else - throw VCLException(ObjectEmpty, "Image object is empty"); - } -} - /* *********************** */ - /* CONSTRUCTORS */ - /* *********************** */ + field = curl_mime_addpart(form); + curl_mime_name(field, "jsonData"); + if (curl_mime_data(field, _options.toStyledString().data(), + _options.toStyledString().length()) != CURLE_OK) { + if (std::remove(filePath.data()) != 0) { + } + throw VCLException(ObjectEmpty, "Unable to create curl mime data"); + } -Image::Image() -{ - _channels = 0; - _height = 0; - _width = 0; - _cv_type = CV_8UC3; + // Post data + if (curl_easy_setopt(curl, CURLOPT_URL, _url.data()) != CURLE_OK) { + throw VCLException(UndefinedException, "CURL setup error with URL"); + } + if (curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback) != + CURLE_OK) { + throw VCLException(UndefinedException, + "CURL setup error with callback"); + } + if (curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer) != + CURLE_OK) { + throw VCLException(UndefinedException, + "CURL setup error with read buffer"); + } + if (curl_easy_setopt(curl, CURLOPT_MIMEPOST, form) != CURLE_OK) { + throw VCLException(UndefinedException, "CURL setup error with form"); + } - _format = Image::Format::NONE_IMAGE; - _compress = CompressionType::LZ4; + res = curl_easy_perform(curl); - _tdb = nullptr; - _image_id = ""; - _bin = nullptr; - _bin_size = 0; -} - -Image::Image(const std::string &image_id) -{ - _channels = 0; - _height = 0; - _width = 0; - _cv_type = CV_8UC3; - _bin = 0; - _bin_size = 0; - - std::string extension = get_extension(image_id); - set_format(extension); - - _compress = CompressionType::LZ4; - - _image_id = create_fullpath(image_id, _format); - - if ( _format == Image::Format::TDB ) { - _tdb = new TDBImage(_image_id); - _tdb->set_compression(_compress); - } - else - _tdb = nullptr; + curl_easy_cleanup(curl); + curl_mime_free(form); + + // Decode the response - read(image_id); + std::vector vectordata(readBuffer.begin(), + readBuffer.end()); + cv::Mat data_mat(vectordata, true); + cv::Mat decoded_mat(cv::imdecode(data_mat, 1)); + + img->shallow_copy_cv(decoded_mat); + + if (std::remove(filePath.data()) != 0) { + } + } + + } else + throw VCLException(ObjectEmpty, "Image object is empty"); + } + img->_op_completed++; } -Image::Image(const cv::Mat &cv_img, bool copy) -{ - if ( cv_img.empty() ) { - throw VCLException(ObjectEmpty, "Image object is empty"); - } +/* *********************** */ +/* USER OPERATION */ +/* *********************** */ - if (copy) - deep_copy_cv(cv_img); - else - shallow_copy_cv(cv_img); +void Image::UserOperation::operator()(Image *img) { + if (_format == Image::Format::TDB) { + // Not implemented + throw VCLException(NotImplemented, + "Operation not supported for this format"); + } else { + if (!img->_cv_img.empty()) { - _format = Image::Format::NONE_IMAGE; - _compress = CompressionType::LZ4; - _image_id = ""; + std::string opfile; - _tdb = nullptr; - _bin = nullptr; - _bin_size = 0; + zmq::context_t context(1); + zmq::socket_t socket(context, zmq::socket_type::req); + + std::string port = _options["port"].asString(); + std::string address = "tcp://127.0.0.1:" + port; + + socket.connect(address.data()); + + auto time_now = std::chrono::system_clock::now(); + std::chrono::duration utc_time = time_now.time_since_epoch(); + + VCL::Image::Format img_format = img->get_image_format(); + std::string format = img->format_to_string(img_format); + + if (format == "" && _options.isMember("format")) { + format = _options["format"].toStyledString().data(); + format.erase(std::remove(format.begin(), format.end(), '\n'), + format.end()); + format = format.substr(1, format.size() - 2); + } else { + format = "jpg"; + } + + std::string filePath = + "/tmp/tempfile" + std::to_string(utc_time.count()) + "." + format; + cv::imwrite(filePath, img->_cv_img); + + // std::string operation_id = _options["id"].toStyledString().data(); + // operation_id.erase(std::remove(operation_id.begin(), + // operation_id.end(), '\n'), operation_id.end()); operation_id = + // operation_id.substr(1, operation_id.size() - 2); + + _options["ipfile"] = filePath; + + // std::string message_to_send = filePath + "::" + operation_id; + std::string message_to_send = _options.toStyledString(); + + int message_len = message_to_send.length(); + zmq::message_t ipfile(message_len); + memcpy(ipfile.data(), message_to_send.data(), message_len); + + socket.send(ipfile, 0); + + while (true) { + char buffer[256]; + int size = socket.recv(buffer, 255, 0); + + buffer[size] = '\0'; + opfile = buffer; + + break; + } + + std::ifstream rfile; + rfile.open(opfile); + + if (rfile) { + rfile.close(); + } else { + if (std::remove(filePath.data()) != 0) { + } + throw VCLException(OpenFailed, "UDF Error"); + } + + VCL::Image res_image(opfile); + img->shallow_copy_cv(res_image.get_cvmat(true)); + + if (std::remove(filePath.data()) != 0) { + } + + if (std::remove(opfile.data()) != 0) { + } + } else + throw VCLException(ObjectEmpty, "Image object is empty"); + } + img->_op_completed++; } -Image::Image(void* buffer, long size, char binary_image_flag, int flags) -{ - _bin = 0; - _bin_size = 0; +/* *********************** */ +/* CONSTRUCTORS */ +/* *********************** */ + +Image::Image() { + _channels = 0; + _height = 0; + _width = 0; + _cv_type = CV_8UC3; + + _format = Image::Format::NONE_IMAGE; + _compress = CompressionType::LZ4; + + _tdb = nullptr; + _image_id = ""; + _bin = nullptr; + _bin_size = 0; + _remote = nullptr; + _op_completed = 0; +} + +Image::Image(const std::string &image_id, std::string bucket_name) { + _remote = nullptr; + + if (bucket_name.length() != 0) { + VCL::RemoteConnection *connection = new VCL::RemoteConnection(); + connection->_bucket_name = bucket_name; + set_connection(connection); + } + _channels = 0; + _height = 0; + _width = 0; + _cv_type = CV_8UC3; + _bin = 0; + _bin_size = 0; + + std::string extension = get_extension(image_id); + set_format(extension); + + _compress = CompressionType::LZ4; + + _image_id = create_fullpath(image_id, _format); + + if (_format == Image::Format::TDB) { + _tdb = new TDBImage(_image_id); + _tdb->set_compression(_compress); + } else _tdb = nullptr; - _bin = nullptr; - set_data_from_encoded(buffer, size, binary_image_flag, flags); - _format = Image::Format::NONE_IMAGE; - _compress = CompressionType::LZ4; - _image_id = ""; + read(image_id); + _op_completed = 0; } -Image::Image(void* buffer, cv::Size dimensions, int cv_type) -{ - _bin = 0; - _bin_size = 0; +Image::Image(const cv::Mat &cv_img, bool copy) { + if (cv_img.empty()) { + throw VCLException(ObjectEmpty, "Image object is empty"); + } - _height = dimensions.height; - _width = dimensions.width; - _cv_type = cv_type; - _channels = (cv_type / 8) + 1; + _remote = nullptr; - _format = Image::Format::TDB; - _compress = CompressionType::LZ4; - _image_id = ""; + if (copy) + deep_copy_cv(cv_img); + else + shallow_copy_cv(cv_img); - set_data_from_raw(buffer, _height*_width*_channels); - _tdb->set_compression(_compress); + _format = Image::Format::NONE_IMAGE; + _compress = CompressionType::LZ4; + _image_id = ""; + + _tdb = nullptr; + _bin = nullptr; + _bin_size = 0; + + _op_completed = 0; } -Image::Image(const Image &img, bool copy) -{ - _bin = 0; - _bin_size = 0; +Image::Image(void *buffer, long size, char binary_image_flag, int flags) { + _bin = 0; + _bin_size = 0; + _remote = nullptr; - _height = img._height; - _width = img._width; - _cv_type = img._cv_type; - _channels = img._channels; + _tdb = nullptr; + _bin = nullptr; + set_data_from_encoded(buffer, size, binary_image_flag, flags); - _format = img._format; - _compress = img._compress; - _image_id = img._image_id; + _format = Image::Format::NONE_IMAGE; + _compress = CompressionType::LZ4; + _image_id = ""; + _op_completed = 0; +} - if ( !(img._cv_img).empty() ) { - if (copy) { - deep_copy_cv(img._cv_img); - } - else { - shallow_copy_cv(img._cv_img); - } - } +Image::Image(void *buffer, cv::Size dimensions, int cv_type) { + _bin = 0; + _bin_size = 0; + _remote = nullptr; - if ( img._tdb != NULL ) - _tdb = new TDBImage(*img._tdb); - else - _tdb = NULL; - - int start; - if ( img._operations.size() > 0 ) { - std::shared_ptr front = img._operations.front(); - if (front->get_type() == OperationType::READ) { - start = 1; - cv::Mat img_read = cv::imread(img._image_id, cv::IMREAD_ANYCOLOR); - shallow_copy_cv(img_read); - } - else - start = 0; + _height = dimensions.height; + _width = dimensions.width; + _cv_type = cv_type; + _channels = (cv_type / 8) + 1; + + _format = Image::Format::TDB; + _compress = CompressionType::LZ4; + _image_id = ""; + + set_data_from_raw(buffer, _height * _width * _channels); + _tdb->set_compression(_compress); + + _op_completed = 0; +} - for (int i = start; i < img._operations.size(); ++i) - _operations.push_back(img._operations[i]); +Image::Image(const Image &img, bool copy) { + _bin = 0; + _bin_size = 0; + _remote = nullptr; + + _height = img._height; + _width = img._width; + _cv_type = img._cv_type; + _channels = img._channels; + + _format = img._format; + _compress = img._compress; + _image_id = img._image_id; + + if (!(img._cv_img).empty()) { + if (copy) { + deep_copy_cv(img._cv_img); + } else { + shallow_copy_cv(img._cv_img); } + } + + if (img._tdb != NULL) + _tdb = new TDBImage(*img._tdb); + else + _tdb = NULL; + + int start; + if (img._operations.size() > 0) { + std::shared_ptr front = img._operations.front(); + if (front->get_type() == OperationType::READ) { + start = 1; + cv::Mat img_read = cv::imread(img._image_id, cv::IMREAD_ANYCOLOR); + shallow_copy_cv(img_read); + } else + start = 0; + + for (int i = start; i < img._operations.size(); ++i) + _operations.push_back(img._operations[i]); + } + + _op_completed = img._op_completed; + remoteOp_params = img.remoteOp_params; } -Image::Image(Image &&img) noexcept -{ - _bin = 0; - _bin_size = 0; +Image::Image(Image &&img) noexcept { + _bin = 0; + _bin_size = 0; + _remote = nullptr; - _format = img._format; - _compress = img._compress; - _image_id = img._image_id; - _tdb = img._tdb; - _operations = std::move(img._operations); - shallow_copy_cv(img._cv_img); + _format = img._format; + _compress = img._compress; + _image_id = img._image_id; + _tdb = img._tdb; + _operations = std::move(img._operations); + shallow_copy_cv(img._cv_img); + + img._tdb = NULL; - img._tdb = NULL; + _op_completed = img._op_completed; + remoteOp_params = img.remoteOp_params; } -Image& Image::operator=(const Image &img) -{ +Image &Image::operator=(const Image &img) { - TDBImage *temp = _tdb; - _bin = 0; - _bin_size = 0; - if ( !(img._cv_img).empty() ) - deep_copy_cv(img._cv_img); - else { - _channels = img._channels; + TDBImage *temp = _tdb; + _bin = 0; + _bin_size = 0; + if (!(img._cv_img).empty()) + deep_copy_cv(img._cv_img); + else { + _channels = img._channels; - _height = img._height; - _width = img._width; + _height = img._height; + _width = img._width; - _cv_type = img._cv_type; - } + _cv_type = img._cv_type; + } - _format = img._format; - _compress = img._compress; - _image_id = img._image_id; + _format = img._format; + _compress = img._compress; + _image_id = img._image_id; - if ( img._tdb != NULL ) { - _tdb = new TDBImage(*img._tdb); - } - else - _tdb = NULL; + if (img._tdb != NULL) { + _tdb = new TDBImage(*img._tdb); + } else + _tdb = NULL; - int start; + int start; - _operations.clear(); - _operations.shrink_to_fit(); + _operations.clear(); + _operations.shrink_to_fit(); - if ( img._operations.size() > 0 ) { - std::shared_ptr front = img._operations.front(); - if (front->get_type() == OperationType::READ) { - start = 1; - cv::Mat img_read = cv::imread(img._image_id, cv::IMREAD_ANYCOLOR); - shallow_copy_cv(img_read); - } - else - start = 0; + if (img._operations.size() > 0) { + std::shared_ptr front = img._operations.front(); + if (front->get_type() == OperationType::READ) { + start = 1; + cv::Mat img_read = cv::imread(img._image_id, cv::IMREAD_ANYCOLOR); + shallow_copy_cv(img_read); + } else + start = 0; - for (int i = start; i < img._operations.size(); ++i) - _operations.push_back(img._operations[i]); - } + for (int i = start; i < img._operations.size(); ++i) + _operations.push_back(img._operations[i]); + } - delete temp; + _op_completed = img._op_completed; + remoteOp_params = img.remoteOp_params; - return *this; + delete temp; + + return *this; } -Image::~Image() -{ - _operations.clear(); - _operations.shrink_to_fit(); - delete _tdb; - if(_bin) - free(_bin); +Image::~Image() { + _operations.clear(); + _operations.shrink_to_fit(); + delete _tdb; + if (_bin) + free(_bin); } - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* GET FUNCTIONS */ +/* *********************** */ -std::string Image::get_image_id() const -{ - return _image_id; -} +std::string Image::get_image_id() const { return _image_id; } -cv::Size Image::get_dimensions() -{ - // TODO: iterate over operations themsevles to determine - // image size, rather than performing the operations. - if ( _operations.size() > 0 ) - perform_operations(); - return cv::Size(_width, _height); +cv::Size Image::get_dimensions(bool performOp) { + // TODO: iterate over operations themsevles to determine + // image size, rather than performing the operations. + if (_operations.size() > 0 && performOp) + perform_operations(); + return cv::Size(_width, _height); } -Image::Format Image::get_image_format() const -{ - return _format; -} +Image::Format Image::get_image_format() const { return _format; } -long Image::get_raw_data_size() -{ - if ( _height == 0 ) { - if ( _format == Image::Format::TDB ) { - if ( _tdb == NULL ) - throw VCLException(TileDBNotFound, "Image::Format indicates image \ +long Image::get_raw_data_size() { + if (_height == 0) { + if (_format == Image::Format::TDB) { + if (_tdb == NULL) + throw VCLException(TileDBNotFound, "Image::Format indicates image \ stored in TDB format, but no data was found"); - return _tdb->get_image_size(); - } - else { - std::shared_ptr op = _operations.front(); - (*op)(this); - _operations.erase(_operations.begin()); - } + return _tdb->get_image_size(); + } else { + std::shared_ptr op = _operations.front(); + (*op)(this); + _operations.erase(_operations.begin()); } + } - return long(_height) * long(_width) * _channels; + return long(_height) * long(_width) * _channels; } -int Image::get_image_type() const -{ - return _cv_type; -} +int Image::get_image_type() const { return _cv_type; } -Image Image::get_area(const Rectangle &roi) const -{ - Image area(*this); +Image Image::get_area(const Rectangle &roi, bool performOp) const { + Image area(*this); - if ( area._format == Image::Format::TDB && area._operations.size() == 1 ) { - if ( area._tdb == NULL ) - throw VCLException(TileDBNotFound, "Image::Format indicates image \ + if (area._format == Image::Format::TDB && area._operations.size() == 1) { + if (area._tdb == NULL) + throw VCLException(TileDBNotFound, "Image::Format indicates image \ stored in TDB format, but no data was found"); - area._operations.pop_back(); - } + area._operations.pop_back(); + } - std::shared_ptr op = std::make_shared (roi, area._format); + std::shared_ptr op = std::make_shared(roi, area._format); - area._operations.push_back(op); + area._operations.push_back(op); + if (performOp) area.perform_operations(); - area._height = roi.height; - area._width = roi.width; + area._height = roi.height; + area._width = roi.width; - return area; + return area; } -cv::Mat Image::get_cvmat(bool copy) -{ +cv::Mat Image::get_cvmat(bool copy, bool performOp) { + if (performOp) perform_operations(); - cv::Mat mat = (_format == Format::TDB) ? _tdb->get_cvmat() : _cv_img; + cv::Mat mat = (_format == Format::TDB) ? _tdb->get_cvmat() : _cv_img; - if (copy) - return mat.clone(); + if (copy) + return mat.clone(); + else + return mat; +} + +void Image::get_raw_data(void *buffer, long buffer_size, bool performOp) { + if (performOp) + perform_operations(); + + switch (_cv_type % 8) { + case 0: + if (_format != Format::TDB) + copy_to_buffer(static_cast(buffer)); + else + _tdb->get_buffer(static_cast(buffer), buffer_size); + break; + case 1: + if (_format != Format::TDB) + copy_to_buffer(static_cast(buffer)); + else + _tdb->get_buffer(static_cast(buffer), buffer_size); + break; + case 2: + if (_format != Format::TDB) + copy_to_buffer(static_cast(buffer)); else - return mat; -} - -void Image::get_raw_data(void* buffer, long buffer_size ) -{ - perform_operations(); - - switch ( _cv_type % 8 ) { - case 0: - if ( _format != Format::TDB ) - copy_to_buffer(static_cast(buffer)); - else - _tdb->get_buffer(static_cast(buffer), buffer_size); - break; - case 1: - if ( _format != Format::TDB ) - copy_to_buffer(static_cast(buffer)); - else - _tdb->get_buffer(static_cast(buffer), buffer_size); - break; - case 2: - if ( _format != Format::TDB ) - copy_to_buffer(static_cast(buffer)); - else - _tdb->get_buffer(static_cast(buffer), buffer_size); - break; - case 3: - if ( _format != Format::TDB ) - copy_to_buffer(static_cast(buffer)); - else - _tdb->get_buffer(static_cast(buffer), buffer_size); - break; - case 4: - if ( _format != Format::TDB ) - copy_to_buffer(static_cast(buffer)); - else - _tdb->get_buffer(static_cast(buffer), buffer_size); - break; - case 5: - if ( _format != Format::TDB ) - copy_to_buffer(static_cast(buffer)); - else - _tdb->get_buffer(static_cast(buffer), buffer_size); - break; - case 6: - if ( _format != Format::TDB ) - copy_to_buffer(static_cast(buffer)); - else - _tdb->get_buffer(static_cast(buffer), buffer_size); - break; - default: - throw VCLException(UnsupportedFormat, _cv_type + " is not a \ + _tdb->get_buffer(static_cast(buffer), buffer_size); + break; + case 3: + if (_format != Format::TDB) + copy_to_buffer(static_cast(buffer)); + else + _tdb->get_buffer(static_cast(buffer), buffer_size); + break; + case 4: + if (_format != Format::TDB) + copy_to_buffer(static_cast(buffer)); + else + _tdb->get_buffer(static_cast(buffer), buffer_size); + break; + case 5: + if (_format != Format::TDB) + copy_to_buffer(static_cast(buffer)); + else + _tdb->get_buffer(static_cast(buffer), buffer_size); + break; + case 6: + if (_format != Format::TDB) + copy_to_buffer(static_cast(buffer)); + else + _tdb->get_buffer(static_cast(buffer), buffer_size); + break; + default: + throw VCLException(UnsupportedFormat, _cv_type + " is not a \ supported type"); - break; - } + break; + } } +int Image::get_enqueued_operation_count() { return _operations.size(); } -std::vector Image::get_encoded_image(Image::Format format, - const std::vector& params) -{ +int Image::get_op_completed() { return _op_completed; } - //When data is stored in raw binary format, read data from file - if(format == VCL::Image::Format::BIN) - { - std::ifstream bin_image(_image_id, std::ios::in | std::ifstream::binary); - long file_size = bin_image.tellg(); - bin_image.seekg(0, std::ios::end); - file_size = bin_image.tellg() - file_size; - std::vector buffer(file_size, 0); - bin_image.seekg(0, std::ios::beg); - bin_image.read((char *) &buffer[0], file_size); - bin_image.close(); - return buffer; +Json::Value Image::get_remoteOp_params() { return remoteOp_params; } - } - - else - { - perform_operations(); - - std::string extension = "." + format_to_string(format); - - if ( _cv_img.empty() ) { - if ( _tdb == NULL) - throw VCLException(ObjectEmpty, "No data to encode"); - else { - cv::Mat img = _tdb->get_cvmat(); - shallow_copy_cv(img); - } - } - - std::vector buffer; - cv::imencode(extension, _cv_img, buffer, params); - return buffer; - } +std::vector +Image::get_encoded_image(Image::Format format, const std::vector ¶ms) { -} + // When data is stored in raw binary format, read data from file + if (format == VCL::Image::Format::BIN) { + std::ifstream bin_image(_image_id, std::ios::in | std::ifstream::binary); + long file_size = bin_image.tellg(); + bin_image.seekg(0, std::ios::end); + file_size = bin_image.tellg() - file_size; + std::vector buffer(file_size, 0); + bin_image.seekg(0, std::ios::beg); + bin_image.read((char *)&buffer[0], file_size); + bin_image.close(); + return buffer; - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ - -void Image::set_data_from_raw(void* buffer, long size) -{ - switch ( _cv_type % 8 ) { - case 0: - _tdb = new TDBImage(static_cast(buffer), size); - break; - case 1: - _tdb = new TDBImage(static_cast(buffer), size); - break; - case 2: - _tdb = new TDBImage(static_cast(buffer), size); - break; - case 3: - _tdb = new TDBImage(static_cast(buffer), size); - break; - case 4: - _tdb = new TDBImage(static_cast(buffer), size); - break; - case 5: - _tdb = new TDBImage(static_cast(buffer), size); - break; - case 6: - _tdb = new TDBImage(static_cast(buffer), size); - break; - default: - throw VCLException(UnsupportedFormat, _cv_type + " is not a \ - supported type"); - break; - } -} + } + + else { + perform_operations(); -void Image::set_data_from_encoded(void *buffer, long size, char binary_image_flag, int flags) -{ - //with raw binary files, we simply copy the data and do not encode - if(binary_image_flag) - { - _bin_size = size; - _bin = (char*) malloc (sizeof(char)*size); - memcpy ( _bin, buffer, size ); + std::string extension = "." + format_to_string(format); + + if (_cv_img.empty()) { + if (_tdb == NULL) + throw VCLException(ObjectEmpty, "No data to encode"); + else { + cv::Mat img = _tdb->get_cvmat(); + shallow_copy_cv(img); + } } - else - { - cv::Mat raw_data(cv::Size(size, 1), CV_8UC1, buffer); - cv::Mat img = cv::imdecode(raw_data, flags); - if ( img.empty() ) { - throw VCLException(ObjectEmpty, "Image object is empty"); - } + std::vector buffer; + cv::imencode(extension, _cv_img, buffer, params); + return buffer; + } +} - // - // We can safely make a shallow-copy here, as cv::Mat uses a reference - // counter to keep track of the references - // +std::vector +Image::get_encoded_image_async(Image::Format format, + const std::vector ¶ms) { + + // When data is stored in raw binary format, read data from file + if (format == VCL::Image::Format::BIN) { + std::ifstream bin_image(_image_id, std::ios::in | std::ifstream::binary); + long file_size = bin_image.tellg(); + bin_image.seekg(0, std::ios::end); + file_size = bin_image.tellg() - file_size; + std::vector buffer(file_size, 0); + bin_image.seekg(0, std::ios::beg); + bin_image.read((char *)&buffer[0], file_size); + bin_image.close(); + return buffer; + + } + + else { + std::string extension = "." + format_to_string(format); + + if (_cv_img.empty()) { + if (_tdb == NULL) + throw VCLException(ObjectEmpty, "No data to encode"); + else { + cv::Mat img = _tdb->get_cvmat(); shallow_copy_cv(img); + } } + std::vector buffer; + cv::imencode(extension, _cv_img, buffer, params); + return buffer; + } +} + +/* *********************** */ +/* SET FUNCTIONS */ +/* *********************** */ + +void Image::set_data_from_raw(void *buffer, long size) { + switch (_cv_type % 8) { + case 0: + _tdb = new TDBImage(static_cast(buffer), size); + break; + case 1: + _tdb = new TDBImage(static_cast(buffer), size); + break; + case 2: + _tdb = new TDBImage(static_cast(buffer), size); + break; + case 3: + _tdb = new TDBImage(static_cast(buffer), size); + break; + case 4: + _tdb = new TDBImage(static_cast(buffer), size); + break; + case 5: + _tdb = new TDBImage(static_cast(buffer), size); + break; + case 6: + _tdb = new TDBImage(static_cast(buffer), size); + break; + default: + throw VCLException(UnsupportedFormat, _cv_type + " is not a \ + supported type"); + break; + } } -void Image::set_compression(CompressionType comp) -{ - _compress = comp; +void Image::set_data_from_encoded(void *buffer, long size, + char binary_image_flag, int flags) { + // with raw binary files, we simply copy the data and do not encode + if (binary_image_flag) { + _bin_size = size; + _bin = (char *)malloc(sizeof(char) * size); + memcpy(_bin, buffer, size); + } else { + cv::Mat raw_data(cv::Size(size, 1), CV_8UC1, buffer); + cv::Mat img = cv::imdecode(raw_data, flags); + + if (img.empty()) { + throw VCLException(ObjectEmpty, "Image object is empty"); + } + + // + // We can safely make a shallow-copy here, as cv::Mat uses a reference + // counter to keep track of the references + // + shallow_copy_cv(img); + } } -void Image::set_dimensions(cv::Size dims) -{ - _height = dims.height; - _width = dims.width; +void Image::set_compression(CompressionType comp) { _compress = comp; } + +void Image::set_dimensions(cv::Size dims) { + _height = dims.height; + _width = dims.width; - if ( _format == Image::Format::TDB ) { - if ( _tdb == NULL ) - throw VCLException(TileDBNotFound, "Image::Format indicates image \ + if (_format == Image::Format::TDB) { + if (_tdb == NULL) + throw VCLException(TileDBNotFound, "Image::Format indicates image \ stored in TDB format, but no data was found"); - _tdb->set_image_properties(_height, _width, _channels); - } + _tdb->set_image_properties(_height, _width, _channels); + } } -void Image::set_format(const std::string &extension) -{ - if ( extension == "jpg" ) - _format = Image::Format::JPG; - else if ( extension == "png" ) - _format = Image::Format::PNG; - else if ( extension == "tdb" ) - _format = Image::Format::TDB; - else if ( extension == "bin" ) - _format = Image::Format::BIN; - else - throw VCLException(UnsupportedFormat, extension + " is not a \ +void Image::set_format(const std::string &extension) { + if (extension == "jpg") + _format = Image::Format::JPG; + else if (extension == "png") + _format = Image::Format::PNG; + else if (extension == "tdb") + _format = Image::Format::TDB; + else if (extension == "bin") + _format = Image::Format::BIN; + else + throw VCLException(UnsupportedFormat, extension + " is not a \ supported format"); } -void Image::set_image_type(int cv_type) -{ - _cv_type = cv_type; +void Image::set_image_type(int cv_type) { + _cv_type = cv_type; - _channels = (cv_type / 8) + 1; + _channels = (cv_type / 8) + 1; } -void Image::set_minimum_dimension(int dimension) -{ - if ( _format == Image::Format::TDB ) { - if ( _tdb == NULL ) - throw VCLException(TileDBNotFound, "Image::Format indicates image \ +void Image::set_minimum_dimension(int dimension) { + if (_format == Image::Format::TDB) { + if (_tdb == NULL) + throw VCLException(TileDBNotFound, "Image::Format indicates image \ stored in TDB format, but no data was found\n"); - _tdb->set_minimum(dimension); - } + _tdb->set_minimum(dimension); + } } - /* *********************** */ - /* IMAGE INTERACTIONS */ - /* *********************** */ +void Image::set_remoteOp_params(Json::Value options, std::string url) { + remoteOp_params["options"] = options; + remoteOp_params["url"] = url; +} -void Image::perform_operations() -{ - try - { - for (int x = 0; x < _operations.size(); ++x) { - std::shared_ptr op = _operations[x]; - if ( op == NULL ) - throw VCLException(ObjectEmpty, "Nothing to be done"); - (*op)(this); - } - } catch( cv::Exception& e ) { - throw VCLException(OpenCVError, e.what()); +void Image::update_op_completed() { _op_completed++; } + +void Image::set_connection(RemoteConnection *remote) { + if (!remote->connected()) + remote->start(); + + if (!remote->connected()) { + throw VCLException(SystemNotFound, "No remote connection started"); + } + + _remote = remote; + _storage = Storage::AWS; + + if (_tdb != NULL) { + _tdb->set_configuration(remote); + } +} + +/* *********************** */ +/* IMAGE INTERACTIONS */ +/* *********************** */ + +void Image::perform_operations() { + try { + for (int x = 0; x < _operations.size(); ++x) { + std::shared_ptr op = _operations[x]; + if (op == NULL) + throw VCLException(ObjectEmpty, "Nothing to be done"); + (*op)(this); } + } catch (cv::Exception &e) { + throw VCLException(OpenCVError, e.what()); + } + + _operations.clear(); +} - _operations.clear(); +int Image::execute_operation() { + std::shared_ptr op = _operations[_op_completed]; + if (op == NULL) + throw VCLException(ObjectEmpty, "Nothing to be done"); + + if ((*op).get_type() != VCL::Image::OperationType::REMOTEOPERATION) { + (*op)(this); + return 0; + } else { + (*op)(this); + return -1; + } } -void Image::read(const std::string &image_id) -{ - _image_id = create_fullpath(image_id, _format); - _operations.push_back(std::make_shared (_image_id, _format)); +void Image::read(const std::string &image_id) { + _image_id = create_fullpath(image_id, _format); + _operations.push_back(std::make_shared(_image_id, _format)); } void Image::store(const std::string &image_id, Image::Format image_format, - bool store_metadata) -{ - _operations.push_back(std::make_shared (create_fullpath(image_id, - image_format), image_format, _format, store_metadata)); - perform_operations(); + bool store_metadata) { + _operations.push_back( + std::make_shared(create_fullpath(image_id, image_format), + image_format, _format, store_metadata)); + perform_operations(); } -void Image::delete_image() -{ - if (_tdb != NULL) - _tdb->delete_image(); +void Image::delete_image() { + if (_tdb != NULL) + _tdb->delete_image(); - if (exists(_image_id)) { - std::remove(_image_id.c_str()); - } + if (exists(_image_id)) { + std::remove(_image_id.c_str()); + } else if (_remote != NULL) { + _remote->Remove_Object(_image_id); + } } -void Image::resize(int new_height, int new_width) -{ - _operations.push_back(std::make_shared (Rectangle(0, 0, - new_width, new_height), _format)); +void Image::resize(int new_height, int new_width) { + _operations.push_back(std::make_shared( + Rectangle(0, 0, new_width, new_height), _format)); } -void Image::crop(const Rectangle &rect) -{ - if ( _format == Format::TDB && _operations.size() == 1 ) { - if ( _tdb == NULL ) - throw VCLException(TileDBNotFound, "Image::Format indicates image \ +void Image::crop(const Rectangle &rect) { + if (_format == Format::TDB && _operations.size() == 1) { + if (_tdb == NULL) + throw VCLException(TileDBNotFound, "Image::Format indicates image \ stored in TDB format, but no data was found"); - _operations.pop_back(); - } + _operations.pop_back(); + } + + _operations.push_back(std::make_shared(rect, _format)); +} + +void Image::threshold(int value) { + _operations.push_back(std::make_shared(value, _format)); +} + +void Image::flip(int code) { + _operations.push_back(std::make_shared(code, _format)); +} - _operations.push_back(std::make_shared (rect, _format)); +void Image::rotate(float angle, bool keep_size) { + _operations.push_back(std::make_shared(angle, keep_size, _format)); } -void Image::threshold(int value) -{ - _operations.push_back(std::make_shared (value, _format)); +void Image::syncremoteOperation(std::string url, Json::Value options) { + _operations.push_back( + std::make_shared(url, options, _format)); } -void Image::flip(int code) -{ - _operations.push_back(std::make_shared (code, _format)); +void Image::remoteOperation(std::string url, Json::Value options) { + _operations.push_back( + std::make_shared(url, options, _format)); } -void Image::rotate(float angle, bool keep_size) -{ - _operations.push_back(std::make_shared (angle, keep_size, _format)); +void Image::userOperation(Json::Value options) { + _operations.push_back(std::make_shared(options, _format)); } - /* *********************** */ - /* COPY FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* COPY FUNCTIONS */ +/* *********************** */ -void Image::deep_copy_cv(const cv::Mat &cv_img) -{ - _channels = cv_img.channels(); +void Image::deep_copy_cv(const cv::Mat &cv_img) { + _channels = cv_img.channels(); - _height = cv_img.rows; - _width = cv_img.cols; + _height = cv_img.rows; + _width = cv_img.cols; - _cv_type = cv_img.type(); + _cv_type = cv_img.type(); - _cv_img = cv_img.clone(); // deep copy + _cv_img = cv_img.clone(); // deep copy } -void Image::shallow_copy_cv(const cv::Mat &cv_img) -{ - _channels = cv_img.channels(); +void Image::shallow_copy_cv(const cv::Mat &cv_img) { + _channels = cv_img.channels(); - _height = cv_img.rows; - _width = cv_img.cols; + _height = cv_img.rows; + _width = cv_img.cols; - _cv_type = cv_img.type(); + _cv_type = cv_img.type(); - _cv_img = cv_img; // shallow copy + _cv_img = cv_img; // shallow copy } -template -void Image::copy_to_buffer(T* buffer) -{ +template void Image::copy_to_buffer(T *buffer) { - static_assert(std::is_integral::value - || std::is_floating_point::value, "Cannot copy from T"); + static_assert(std::is_integral::value || std::is_floating_point::value, + "Cannot copy from T"); - int index = 0; + int index = 0; - int rows = _height; - int columns = _width; + int rows = _height; + int columns = _width; - if ( _cv_img.isContinuous() ) { - columns *= rows; - rows = 1; - } + if (_cv_img.isContinuous()) { + columns *= rows; + rows = 1; + } - for ( int i = 0; i < rows; ++i ) { - for ( int j = 0; j < columns; ++j ) { - if ( _channels == 1 ) - buffer[index] = T(_cv_img.at(i, j)); - else { - cv::Vec3b colors = _cv_img.at(i, j); - for ( int x = 0; x < _channels; ++x ) { - buffer[index + x] = T(colors.val[x]); - } - } - index += _channels; + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (_channels == 1) + buffer[index] = T(_cv_img.at(i, j)); + else { + cv::Vec3b colors = _cv_img.at(i, j); + for (int x = 0; x < _channels; ++x) { + buffer[index + x] = T(colors.val[x]); } + } + index += _channels; } + } } - /* *********************** */ - /* UTIL FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* UTIL FUNCTIONS */ +/* *********************** */ std::string Image::create_fullpath(const std::string &filename, - Image::Format format) -{ - if ( filename == "" ) - throw VCLException(ObjectNotFound, "Location to write object is undefined"); + Image::Format format) { + if (filename == "") + throw VCLException(ObjectNotFound, "Location to write object is undefined"); - std::string extension = get_extension(filename); - std::string ext = format_to_string(format); + std::string extension = get_extension(filename); + std::string ext = format_to_string(format); - if ( ext.compare(extension) == 0 || ext == "" ) - return filename; - else - return filename + "." + ext; -} - -std::string Image::format_to_string(Image::Format format) -{ - switch( format ) - { - case Image::Format::NONE_IMAGE: - return ""; - case Image::Format::JPG: - return "jpg"; - case Image::Format::PNG: - return "png"; - case Image::Format::TDB: - return "tdb"; - case Image::Format::BIN: - return "bin"; - default: - throw VCLException(UnsupportedFormat, (int)format + " is not a \ + if (ext.compare(extension) == 0 || ext == "") + return filename; + else + return filename + "." + ext; +} + +std::string Image::format_to_string(Image::Format format) { + switch (format) { + case Image::Format::NONE_IMAGE: + return ""; + case Image::Format::JPG: + return "jpg"; + case Image::Format::PNG: + return "png"; + case Image::Format::TDB: + return "tdb"; + case Image::Format::BIN: + return "bin"; + default: + throw VCLException(UnsupportedFormat, (int)format + " is not a \ valid format"); - } + } } diff --git a/src/vcl/KeyFrame.cc b/src/vcl/KeyFrame.cc index cb5a9d5f..a09bbd36 100644 --- a/src/vcl/KeyFrame.cc +++ b/src/vcl/KeyFrame.cc @@ -35,8 +35,7 @@ #include "vcl/KeyFrame.h" -extern "C" -{ +extern "C" { #include #include #include @@ -49,545 +48,519 @@ using namespace VCL; /* KEY_FRAME_OP */ /* *********************** */ -int KeyFrameOp::init_stream(void) -{ - int ret = 0; - unsigned n_video_stream = 0; +int KeyFrameOp::init_stream(void) { + int ret = 0; + unsigned n_video_stream = 0; - _fctx.fmt_context = avformat_alloc_context(); - ret = avformat_open_input(&_fctx.fmt_context, - _filename.c_str(), NULL, NULL); - if (ret != 0) - return ret; + _fctx.fmt_context = avformat_alloc_context(); + ret = avformat_open_input(&_fctx.fmt_context, _filename.c_str(), NULL, NULL); + if (ret != 0) + return ret; - ret = avformat_find_stream_info(_fctx.fmt_context, NULL); - if (ret != 0) - return ret; + ret = avformat_find_stream_info(_fctx.fmt_context, NULL); + if (ret != 0) + return ret; - AVCodecParameters* codec = NULL; - for (unsigned i = 0; i < _fctx.fmt_context->nb_streams && !codec; i++) { + AVCodecParameters *codec = NULL; + for (unsigned i = 0; i < _fctx.fmt_context->nb_streams && !codec; i++) { - AVStream* stream = _fctx.fmt_context->streams[i]; + AVStream *stream = _fctx.fmt_context->streams[i]; - if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - codec = stream->codecpar; + codec = stream->codecpar; - _fctx.video_stream = stream; - _fctx.video_stream_idx = i; + _fctx.video_stream = stream; + _fctx.video_stream_idx = i; - int64_t time_base_num = stream->r_frame_rate.num; - int64_t time_base_den = stream->r_frame_rate.den; - _nb_frames = stream->nb_frames; - _time_base = (time_base_den * AV_TIME_BASE) / time_base_num; + int64_t time_base_num = stream->r_frame_rate.num; + int64_t time_base_den = stream->r_frame_rate.den; + _nb_frames = stream->nb_frames; + _time_base = (time_base_den * AV_TIME_BASE) / time_base_num; - n_video_stream++; - } + n_video_stream++; } + } - if (n_video_stream == 0) { - throw VCLException(FFmpegInitFailed, "No video stream found"); - } + if (n_video_stream == 0) { + throw VCLException(FFmpegInitFailed, "No video stream found"); + } - if (n_video_stream > 1) { - throw VCLException(FFmpegInitFailed, - "Cannot handle more than 1 video stream per file"); - } + if (n_video_stream > 1) { + throw VCLException(FFmpegInitFailed, + "Cannot handle more than 1 video stream per file"); + } - if (!codec) - return AVERROR_ENCODER_NOT_FOUND; - else if (codec->codec_id != AV_CODEC_ID_H264) - return AVERROR_INVALIDDATA; + if (!codec) + return AVERROR_ENCODER_NOT_FOUND; + else if (codec->codec_id != AV_CODEC_ID_H264) + return AVERROR_INVALIDDATA; - return 0; + return 0; } -std::string KeyFrameOp::error_msg(int errnum, const std::string& opt) -{ - char errbuf[128]; +std::string KeyFrameOp::error_msg(int errnum, const std::string &opt) { + char errbuf[128]; - int ret = av_strerror(errnum, errbuf, sizeof(errbuf)); - if (ret != 0) - sprintf(errbuf, "unknown ffmpeg error"); + int ret = av_strerror(errnum, errbuf, sizeof(errbuf)); + if (ret != 0) + sprintf(errbuf, "unknown ffmpeg error"); - std::string cause = ""; - if (!opt.empty()) - cause += (opt + ": "); + std::string cause = ""; + if (!opt.empty()) + cause += (opt + ": "); - return cause + errbuf; + return cause + errbuf; } -KeyFrameOp::KeyFrameOp(std::string filename) : -_filename(filename) -{ - int ret = init_stream(); - if (ret != 0) - throw VCLException(FFmpegInitFailed, - error_msg(ret, "init_parser() failed")); +KeyFrameOp::KeyFrameOp(std::string filename) : _filename(filename) { + int ret = init_stream(); + if (ret != 0) + throw VCLException(FFmpegInitFailed, + error_msg(ret, "init_parser() failed")); - av_log_set_level(AV_LOG_QUIET); + av_log_set_level(AV_LOG_QUIET); } KeyFrameOp::~KeyFrameOp() { - if (_fctx.fmt_context) { - avformat_close_input(&_fctx.fmt_context); - avformat_free_context(_fctx.fmt_context); - } + if (_fctx.fmt_context) { + avformat_close_input(&_fctx.fmt_context); + avformat_free_context(_fctx.fmt_context); + } } /* *********************** */ /* KEY_FRAME_PARSER */ /* *********************** */ -int KeyFrameParser::fill_frame_list(void) noexcept -{ - AVPacket* pkt = av_packet_alloc(); - if (!pkt) - return AVERROR_EXTERNAL; +int KeyFrameParser::fill_frame_list(void) noexcept { + AVPacket *pkt = av_packet_alloc(); + if (!pkt) + return AVERROR_EXTERNAL; - unsigned frame_idx = 0; + unsigned frame_idx = 0; - while (true) { - av_packet_unref(pkt); - int ret = av_read_frame(_fctx.fmt_context, pkt); + while (true) { + av_packet_unref(pkt); + int ret = av_read_frame(_fctx.fmt_context, pkt); - if (ret != 0 && ret != AVERROR_EOF) { - return ret; - } - else if (ret == AVERROR_EOF) { - return 0; - } + if (ret != 0 && ret != AVERROR_EOF) { + return ret; + } else if (ret == AVERROR_EOF) { + return 0; + } - if (pkt->stream_index != _fctx.video_stream_idx) { - continue; - } + if (pkt->stream_index != _fctx.video_stream_idx) { + continue; + } - if (pkt->flags & AV_PKT_FLAG_KEY) { - KeyFrame frame = {.idx = frame_idx, .base = pkt->pos}; - _frame_list.push_back(frame); - } - frame_idx++; - }; + if (pkt->flags & AV_PKT_FLAG_KEY) { + KeyFrame frame = {.idx = frame_idx, .base = pkt->pos}; + _frame_list.push_back(frame); + } + frame_idx++; + }; + av_packet_unref(pkt); - av_packet_unref(pkt); - - return 0; + return 0; } -const KeyFrameList& KeyFrameParser::parse(void) -{ - int ret = fill_frame_list(); - if (ret != 0) - throw VCLException(FFmpegParseFailed, - error_msg(ret, "fill_frame_list() failed")); +const KeyFrameList &KeyFrameParser::parse(void) { + int ret = fill_frame_list(); + if (ret != 0) + throw VCLException(FFmpegParseFailed, + error_msg(ret, "fill_frame_list() failed")); - return _frame_list; + return _frame_list; } /* *********************** */ /* KEY_FRAME_DECODER */ /* *********************** */ -KeyFrameDecoder::KeyFrameDecoder(std::string filename) : - KeyFrameOp(filename) - ,_last_consumed_frame(-1) -{ - int ret = init_decoder(); - if (ret != 0) - throw VCLException(FFmpegDecodeFailed, error_msg(ret, "init_decoder")); +KeyFrameDecoder::KeyFrameDecoder(std::string filename) + : KeyFrameOp(filename), _last_consumed_frame(-1) { + int ret = init_decoder(); + if (ret != 0) + throw VCLException(FFmpegDecodeFailed, error_msg(ret, "init_decoder")); - ret = init_bsf(); - if (ret != 0) - throw VCLException(FFmpegDecodeFailed, error_msg(ret, "init_bsf")); + ret = init_bsf(); + if (ret != 0) + throw VCLException(FFmpegDecodeFailed, error_msg(ret, "init_bsf")); } -KeyFrameDecoder::~KeyFrameDecoder() -{ - for (auto &f : _frame_list) - av_frame_free(&f.frame); - if (_ctx.video_codec_context); - avcodec_close(_ctx.video_codec_context); - if (_ctx.frame_codec_context); - avcodec_close(_ctx.frame_codec_context); - if (_ctx.bsf_context) - av_bsf_free(&_ctx.bsf_context); +KeyFrameDecoder::~KeyFrameDecoder() { + for (auto &f : _frame_list) + av_frame_free(&f.frame); + if (_ctx.video_codec_context) + ; + avcodec_close(_ctx.video_codec_context); + if (_ctx.frame_codec_context) + ; + avcodec_close(_ctx.frame_codec_context); + if (_ctx.bsf_context) + av_bsf_free(&_ctx.bsf_context); } -int KeyFrameDecoder::init_decoder(void) noexcept -{ - // Initialize H264 video decoder - AVCodecParameters* video_codec = - _fctx.video_stream->codecpar; +int KeyFrameDecoder::init_decoder(void) noexcept { + // Initialize H264 video decoder + AVCodecParameters *video_codec = _fctx.video_stream->codecpar; - _ctx.byte_stream_format = (video_codec->bit_rate) ? - H264Format::AVCC : H264Format::AnnexB; + _ctx.byte_stream_format = + (video_codec->bit_rate) ? H264Format::AVCC : H264Format::AnnexB; - const AVCodec* codec_ptr = avcodec_find_decoder(video_codec->codec_id); + const AVCodec *codec_ptr = avcodec_find_decoder(video_codec->codec_id); - if (!codec_ptr) - return AVERROR_DECODER_NOT_FOUND; + if (!codec_ptr) + return AVERROR_DECODER_NOT_FOUND; - _ctx.video_codec_context = avcodec_alloc_context3(codec_ptr); - if (!_ctx.video_codec_context) - return AVERROR_DECODER_NOT_FOUND; + _ctx.video_codec_context = avcodec_alloc_context3(codec_ptr); + if (!_ctx.video_codec_context) + return AVERROR_DECODER_NOT_FOUND; - int ret = avcodec_open2(_ctx.video_codec_context, codec_ptr, NULL); - if (ret < 0) - return ret; + int ret = avcodec_open2(_ctx.video_codec_context, codec_ptr, NULL); + if (ret < 0) + return ret; - return 0; + return 0; } -int KeyFrameDecoder::init_bsf(void) noexcept -{ - int ret = 0; - const AVBitStreamFilter* bsf; +int KeyFrameDecoder::init_bsf(void) noexcept { + int ret = 0; + const AVBitStreamFilter *bsf; - bsf = av_bsf_get_by_name("h264_mp4toannexb"); - if (!bsf) - return AVERROR_BSF_NOT_FOUND; + bsf = av_bsf_get_by_name("h264_mp4toannexb"); + if (!bsf) + return AVERROR_BSF_NOT_FOUND; - ret = av_bsf_alloc(bsf, &_ctx.bsf_context); - if (ret != 0) - return ret; + ret = av_bsf_alloc(bsf, &_ctx.bsf_context); + if (ret != 0) + return ret; - AVRational time_base; - AVCodecParameters* codec; + AVRational time_base; + AVCodecParameters *codec; - time_base = _fctx.video_stream->time_base; - codec = _fctx.video_stream->codecpar; + time_base = _fctx.video_stream->time_base; + codec = _fctx.video_stream->codecpar; - ret = avcodec_parameters_copy(_ctx.bsf_context->par_in, codec); - if (ret < 0) - return ret; + ret = avcodec_parameters_copy(_ctx.bsf_context->par_in, codec); + if (ret < 0) + return ret; - _ctx.bsf_context->time_base_in = time_base; + _ctx.bsf_context->time_base_in = time_base; - ret = av_bsf_init(_ctx.bsf_context); - if (ret != 0) - return ret; + ret = av_bsf_init(_ctx.bsf_context); + if (ret != 0) + return ret; - return 0; + return 0; } -void KeyFrameDecoder::clear(void) -{ - _enc_frame_list.clear(); +void KeyFrameDecoder::clear(void) { + _enc_frame_list.clear(); - for (auto &f : _frame_list) - av_frame_free(&f.frame); - _frame_list.clear(); + for (auto &f : _frame_list) + av_frame_free(&f.frame); + _frame_list.clear(); - for (auto& interval : _interval_map) - interval.second.clear(); + for (auto &interval : _interval_map) + interval.second.clear(); } -void KeyFrameDecoder::set_key_frames(const KeyFrameList& key_frames) -{ - int ret = populate_intervals(key_frames); - if (ret != 0) - throw VCLException(FFmpegDecodeFailed, - error_msg(AVERROR_EXTERNAL, "populate_intervals")); +void KeyFrameDecoder::set_key_frames(const KeyFrameList &key_frames) { + int ret = populate_intervals(key_frames); + if (ret != 0) + throw VCLException(FFmpegDecodeFailed, + error_msg(AVERROR_EXTERNAL, "populate_intervals")); } // This method will only decode a list of frames that are within an // interval, defined by start and end. -int KeyFrameDecoder::decode_interval(const KeyFrame& start, - const KeyFrame& end, - const std::vector& frames) -{ - AVPacket* pkt = av_packet_alloc(); - if (!pkt) - return AVERROR_EXTERNAL; - - AVFrame* current_frame = av_frame_alloc(); - if (!current_frame) - return AVERROR_EXTERNAL; - - int ret = 0; - - unsigned first_frame = frames.at(0); - - bool do_seek = true; - if (first_frame > _last_consumed_frame && _last_consumed_frame >= start.idx ) - { - do_seek = false; +int KeyFrameDecoder::decode_interval(const KeyFrame &start, const KeyFrame &end, + const std::vector &frames) { + AVPacket *pkt = av_packet_alloc(); + if (!pkt) + return AVERROR_EXTERNAL; + + AVFrame *current_frame = av_frame_alloc(); + if (!current_frame) + return AVERROR_EXTERNAL; + + int ret = 0; + + unsigned first_frame = frames.at(0); + + bool do_seek = true; + if (first_frame > _last_consumed_frame && _last_consumed_frame >= start.idx) { + do_seek = false; + } + + if (do_seek) { + // Compute the time, slightly after a key frame, for seeking. + int64_t seekTarget = int64_t(start.idx + 1) * _time_base; + + if (_ctx.byte_stream_format == H264Format::AVCC) { + ret = av_seek_frame(_fctx.fmt_context, -1, seekTarget, + AVSEEK_FLAG_BACKWARD); + } else { + ret = av_seek_frame(_fctx.fmt_context, _fctx.video_stream_idx, start.base, + AVSEEK_FLAG_BYTE); } - if (do_seek) { - // Compute the time, slightly after a key frame, for seeking. - int64_t seekTarget = int64_t(start.idx + 1) * _time_base; + avcodec_flush_buffers(_ctx.video_codec_context); + } - if (_ctx.byte_stream_format == H264Format::AVCC) { - ret = av_seek_frame(_fctx.fmt_context, -1, - seekTarget, AVSEEK_FLAG_BACKWARD); - } - else { - ret = av_seek_frame(_fctx.fmt_context, _fctx.video_stream_idx, - start.base, AVSEEK_FLAG_BYTE); - } + if (ret != 0) + return ret; - avcodec_flush_buffers(_ctx.video_codec_context); - } + unsigned frame_idx = 0; + bool av_read_eof = false; - if (ret != 0) - return ret; - - unsigned frame_idx = 0; - bool av_read_eof = false; - - unsigned idx = do_seek ? start.idx : _last_consumed_frame + 1; - - for ( ; idx < end.idx; ) { - - if(!av_read_eof) { - do { - ret = av_read_frame(_fctx.fmt_context, pkt); - if (ret == AVERROR_EOF) { - av_read_eof = true; - break; - } - } while (pkt->stream_index != _fctx.video_stream_idx); - - if (av_read_eof) continue; - - // This is needed to filter (small modifications) packets: - // https://stackoverflow.com/questions/32028437/what-are-bitstream-filters-in-ffmpeg - if (_ctx.byte_stream_format != H264Format::AnnexB) { - ret = av_bsf_send_packet(_ctx.bsf_context, pkt); - if (ret != 0) - return ret; - - ret = av_bsf_receive_packet(_ctx.bsf_context, pkt); - if (ret == AVERROR(EAGAIN)) { - continue; - } - else if (ret < 0) - return ret; - } - } - else { - // Sometimes, there will be frames in the avcoded buffers - // waiting to be recieved without new packets. - // In order to flush those frames, we keep sending - // null packets (as the operations are always one-send-one-recieve). - pkt = NULL; - } + unsigned idx = do_seek ? start.idx : _last_consumed_frame + 1; - ret = avcodec_send_packet(_ctx.video_codec_context, pkt); - if (ret < 0 && ret != AVERROR_EOF) { - return ret; - } + for (; idx < end.idx;) { - ret = avcodec_receive_frame(_ctx.video_codec_context, current_frame); - if (ret == AVERROR(EAGAIN)) { - continue; - } - else if (ret == AVERROR_EOF) { - // avcoded has no more frames, video has reached to the end. - break; - } - else if (ret < 0) { - return ret; - } - else if (ret == 0) { - _last_consumed_frame = idx; - - if (idx == frames[frame_idx]) { - AVFrame* frame = av_frame_clone(current_frame); - _frame_list.push_back({.frame = frame, .idx = idx}); - if (++frame_idx == frames.size()) { - break; - } - } + if (!av_read_eof) { + do { + ret = av_read_frame(_fctx.fmt_context, pkt); + if (ret == AVERROR_EOF) { + av_read_eof = true; + break; } - ++idx; - } + } while (pkt->stream_index != _fctx.video_stream_idx); - av_frame_free(¤t_frame); + if (av_read_eof) + continue; - if (pkt != NULL) - av_packet_unref(pkt); + // This is needed to filter (small modifications) packets: + // https://stackoverflow.com/questions/32028437/what-are-bitstream-filters-in-ffmpeg + if (_ctx.byte_stream_format != H264Format::AnnexB) { + ret = av_bsf_send_packet(_ctx.bsf_context, pkt); + if (ret != 0) + return ret; - return 0; -} + ret = av_bsf_receive_packet(_ctx.bsf_context, pkt); + if (ret == AVERROR(EAGAIN)) { + continue; + } else if (ret < 0) + return ret; + } + } else { + // Sometimes, there will be frames in the avcoded buffers + // waiting to be recieved without new packets. + // In order to flush those frames, we keep sending + // null packets (as the operations are always one-send-one-recieve). + pkt = NULL; + } -int KeyFrameDecoder::populate_intervals(const KeyFrameList& key_frames) -{ - if (key_frames.empty()) - return -1; - if (!_interval_map.empty()) - return -1; + ret = avcodec_send_packet(_ctx.video_codec_context, pkt); + if (ret < 0 && ret != AVERROR_EOF) { + return ret; + } - std::vector sorted_frame_list(key_frames); + ret = avcodec_receive_frame(_ctx.video_codec_context, current_frame); + if (ret == AVERROR(EAGAIN)) { + continue; + } else if (ret == AVERROR_EOF) { + // avcoded has no more frames, video has reached to the end. + break; + } else if (ret < 0) { + return ret; + } else if (ret == 0) { + _last_consumed_frame = idx; + + if (idx == frames[frame_idx]) { + AVFrame *frame = av_frame_clone(current_frame); + _frame_list.push_back({.frame = frame, .idx = idx}); + if (++frame_idx == frames.size()) { + break; + } + } + } + ++idx; + } - std::sort(sorted_frame_list.begin(), sorted_frame_list.end(), - [&](KeyFrame l, KeyFrame r) { return l.idx < r.idx; }); + av_frame_free(¤t_frame); - // Frame 0 of a valid H264 stream must be a key-frame - if (sorted_frame_list.front().idx != 0) - return -1; + if (pkt != NULL) + av_packet_unref(pkt); - for (auto i = 0; i < sorted_frame_list.size() - 1; ++i) { - FrameInterval interval = {.start = sorted_frame_list[i], - .end = sorted_frame_list[i+1]}; - _interval_map.push_back(std::make_pair(interval, - std::vector())); - } + return 0; +} - // We add an auxiliary interval to the end of the interval map to cover - // the frames between the last-key frame in the 'key_frames' and the end - // of stream. Since we do not know the index of the last frame, - // we simply assign end of interval to the maximum unsigned value, as - // decode_interval() excludes 'FrameInterval.end' - unsigned max_unsigned = std::numeric_limits::max(); - FrameInterval last_interval = {.start = sorted_frame_list.back(), - .end = {.idx = max_unsigned, .base = 0}}; - _interval_map.push_back(std::make_pair(last_interval, - std::vector())); - - return 0; +int KeyFrameDecoder::populate_intervals(const KeyFrameList &key_frames) { + if (key_frames.empty()) + return -1; + if (!_interval_map.empty()) + return -1; + + std::vector sorted_frame_list(key_frames); + + std::sort(sorted_frame_list.begin(), sorted_frame_list.end(), + [&](KeyFrame l, KeyFrame r) { return l.idx < r.idx; }); + + // Frame 0 of a valid H264 stream must be a key-frame + if (sorted_frame_list.front().idx != 0) + return -1; + + for (auto i = 0; i < sorted_frame_list.size() - 1; ++i) { + FrameInterval interval = {.start = sorted_frame_list[i], + .end = sorted_frame_list[i + 1]}; + _interval_map.push_back(std::make_pair(interval, std::vector())); + } + + // We add an auxiliary interval to the end of the interval map to cover + // the frames between the last-key frame in the 'key_frames' and the end + // of stream. Since we do not know the index of the last frame, + // we simply assign end of interval to the maximum unsigned value, as + // decode_interval() excludes 'FrameInterval.end' + unsigned max_unsigned = std::numeric_limits::max(); + FrameInterval last_interval = {.start = sorted_frame_list.back(), + .end = {.idx = max_unsigned, .base = 0}}; + _interval_map.push_back( + std::make_pair(last_interval, std::vector())); + + return 0; } -int KeyFrameDecoder::populate_interval_map(const std::vector& frames) -{ - if (frames.empty()) - return -1; - - // Operation below assumes both '_interval_map' and 'frames' list are - // sorted in ascending order. - unsigned last_idx = 0; - for (auto& interval : _interval_map) { - while (frames[last_idx] < interval.first.end.idx) { - interval.second.push_back(frames[last_idx]); - if (++last_idx == frames.size()) - return 0; - } +int KeyFrameDecoder::populate_interval_map( + const std::vector &frames) { + if (frames.empty()) + return -1; + + // Operation below assumes both '_interval_map' and 'frames' list are + // sorted in ascending order. + unsigned last_idx = 0; + for (auto &interval : _interval_map) { + while (frames[last_idx] < interval.first.end.idx) { + interval.second.push_back(frames[last_idx]); + if (++last_idx == frames.size()) + return 0; } - return 0; + } + return 0; } -int KeyFrameDecoder::encode_frames(void) -{ - int ret; - - if (_frame_list.empty()) - return -1; - - AVFrame *frame = _frame_list[0].frame; - - // In future, we may encode the resulting image with different codecs - // based on the user input. When that feature is to be implemented, - // target codecs and pixel formats must be stored in a table. Until then, - // we hardcode RGB24 as the pixel format when encoding the images, as it - // is supported by libpng. - AVPixelFormat dst_format = AV_PIX_FMT_RGB24; - AVPixelFormat src_format = static_cast(frame->format); - - if (!_ctx.frame_codec_context) { - // Initialize frame encoder (PNG for now, may change in the future) - AVCodec *image_codec = avcodec_find_encoder(AV_CODEC_ID_PNG); - if (!image_codec) - return AVERROR_ENCODER_NOT_FOUND; - - _ctx.frame_codec_context = avcodec_alloc_context3(image_codec); - if (!_ctx.frame_codec_context) - return AVERROR_EXTERNAL; - - _ctx.frame_codec_context->pix_fmt = dst_format; - _ctx.frame_codec_context->height = frame->height; - _ctx.frame_codec_context->width = frame->width; - _ctx.frame_codec_context->time_base = _fctx.video_stream->time_base; - - ret = avcodec_open2(_ctx.frame_codec_context, image_codec, NULL); - if (ret < 0) - return ret; - } +int KeyFrameDecoder::encode_frames(void) { + int ret; - AVFrame* dst_frame = av_frame_alloc(); - if (!dst_frame) - return AVERROR_EXTERNAL; - if (src_format != dst_format) { - _ctx.sws_context = sws_getCachedContext(_ctx.sws_context, frame->width, - frame->height, src_format, frame->width, frame->height, dst_format, - SWS_BILINEAR, NULL, NULL, NULL); - - dst_frame->format = dst_format; - dst_frame->width = frame->width; - dst_frame->height = frame->height; - - ret = av_frame_get_buffer(dst_frame, 0); - if (ret < 0) - return ret; - } + if (_frame_list.empty()) + return -1; - AVPacket* pkt = av_packet_alloc(); - if (!pkt) - return AVERROR_EXTERNAL; + AVFrame *frame = _frame_list[0].frame; - for (const auto& f : _frame_list) { - // We convert the pixel format of the decoded raw frame to - // 'dst_format', since the H264 stream is likely to have YUV as pixel - // format, however, not all image encoders support it. - if (src_format == dst_format) - av_frame_ref(dst_frame, f.frame); - else - sws_scale(_ctx.sws_context, f.frame->data, f.frame->linesize, 0, - f.frame->height, dst_frame->data, dst_frame->linesize); + // In future, we may encode the resulting image with different codecs + // based on the user input. When that feature is to be implemented, + // target codecs and pixel formats must be stored in a table. Until then, + // we hardcode RGB24 as the pixel format when encoding the images, as it + // is supported by libpng. + AVPixelFormat dst_format = AV_PIX_FMT_RGB24; + AVPixelFormat src_format = static_cast(frame->format); - ret = avcodec_send_frame(_ctx.frame_codec_context, dst_frame); - if (ret < 0) - return ret; + if (!_ctx.frame_codec_context) { + // Initialize frame encoder (PNG for now, may change in the future) + AVCodec *image_codec = avcodec_find_encoder(AV_CODEC_ID_PNG); + if (!image_codec) + return AVERROR_ENCODER_NOT_FOUND; - ret = avcodec_receive_packet(_ctx.frame_codec_context, pkt); - if (ret < 0) - return ret; + _ctx.frame_codec_context = avcodec_alloc_context3(image_codec); + if (!_ctx.frame_codec_context) + return AVERROR_EXTERNAL; - std::string enc_frame(reinterpret_cast(pkt->data), pkt->size); + _ctx.frame_codec_context->pix_fmt = dst_format; + _ctx.frame_codec_context->height = frame->height; + _ctx.frame_codec_context->width = frame->width; + _ctx.frame_codec_context->time_base = _fctx.video_stream->time_base; - _enc_frame_list.push_back(enc_frame); + ret = avcodec_open2(_ctx.frame_codec_context, image_codec, NULL); + if (ret < 0) + return ret; + } + + AVFrame *dst_frame = av_frame_alloc(); + if (!dst_frame) + return AVERROR_EXTERNAL; + if (src_format != dst_format) { + _ctx.sws_context = sws_getCachedContext( + _ctx.sws_context, frame->width, frame->height, src_format, frame->width, + frame->height, dst_format, SWS_BILINEAR, NULL, NULL, NULL); + + dst_frame->format = dst_format; + dst_frame->width = frame->width; + dst_frame->height = frame->height; + + ret = av_frame_get_buffer(dst_frame, 0); + if (ret < 0) + return ret; + } + + AVPacket *pkt = av_packet_alloc(); + if (!pkt) + return AVERROR_EXTERNAL; + + for (const auto &f : _frame_list) { + // We convert the pixel format of the decoded raw frame to + // 'dst_format', since the H264 stream is likely to have YUV as pixel + // format, however, not all image encoders support it. + if (src_format == dst_format) + av_frame_ref(dst_frame, f.frame); + else + sws_scale(_ctx.sws_context, f.frame->data, f.frame->linesize, 0, + f.frame->height, dst_frame->data, dst_frame->linesize); + + ret = avcodec_send_frame(_ctx.frame_codec_context, dst_frame); + if (ret < 0) + return ret; - if (src_format == dst_format) - av_frame_unref(dst_frame); - } + ret = avcodec_receive_packet(_ctx.frame_codec_context, pkt); + if (ret < 0) + return ret; - av_packet_unref(pkt); - av_frame_free(&dst_frame); + std::string enc_frame(reinterpret_cast(pkt->data), pkt->size); - return 0; -} + _enc_frame_list.push_back(enc_frame); -EncodedFrameList& KeyFrameDecoder::decode(const std::vector& frames) -{ - // We perform a cleanup on key-frame decoder's internal structures, in - // order to avoid processing frames decoded in a previous call to this - // method. - clear(); + if (src_format == dst_format) + av_frame_unref(dst_frame); + } - if (_interval_map.empty()) - throw VCLException(FFmpegDecodeFailed, - error_msg(AVERROR_EXTERNAL, "set_key_frames() is not invoked")); + av_packet_unref(pkt); + av_frame_free(&dst_frame); - int ret = populate_interval_map(frames); - if (ret != 0) - throw VCLException(FFmpegDecodeFailed, - error_msg(AVERROR_EXTERNAL, "populate_interval_map")); + return 0; +} - for (const auto& interval : _interval_map) { - if (interval.second.empty()) - continue; +EncodedFrameList &KeyFrameDecoder::decode(const std::vector &frames) { + // We perform a cleanup on key-frame decoder's internal structures, in + // order to avoid processing frames decoded in a previous call to this + // method. + clear(); - ret = decode_interval(interval.first.start, interval.first.end, - interval.second); - if (ret != 0) - throw VCLException(FFmpegDecodeFailed, - error_msg(AVERROR_EXTERNAL, "decode_interval")); - } + if (_interval_map.empty()) + throw VCLException( + FFmpegDecodeFailed, + error_msg(AVERROR_EXTERNAL, "set_key_frames() is not invoked")); + + int ret = populate_interval_map(frames); + if (ret != 0) + throw VCLException(FFmpegDecodeFailed, + error_msg(AVERROR_EXTERNAL, "populate_interval_map")); - ret = encode_frames(); + for (const auto &interval : _interval_map) { + if (interval.second.empty()) + continue; + + ret = decode_interval(interval.first.start, interval.first.end, + interval.second); if (ret != 0) - throw VCLException(FFmpegDecodeFailed, error_msg(ret, "encode_frames")); + throw VCLException(FFmpegDecodeFailed, + error_msg(AVERROR_EXTERNAL, "decode_interval")); + } + + ret = encode_frames(); + if (ret != 0) + throw VCLException(FFmpegDecodeFailed, error_msg(ret, "encode_frames")); - return _enc_frame_list; + return _enc_frame_list; } diff --git a/src/vcl/RemoteConnection.cc b/src/vcl/RemoteConnection.cc new file mode 100644 index 00000000..8272eb1d --- /dev/null +++ b/src/vcl/RemoteConnection.cc @@ -0,0 +1,328 @@ +/** + * @file RemoteConnection.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2022-2023 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file declares the C++ API for RemoteConnection, which allows users to + * connect to different file systems. At the moment, S3 is enabled. + */ + +#include "../../include/vcl/RemoteConnection.h" + +using namespace VCL; + +// CONSTRUCTOR +RemoteConnection::RemoteConnection() { + // LogEntry(__FUNCTION__); + _remote_connected = false; + _aws_client = nullptr; + _aws_sdk_options = nullptr; +} + +// DESTRUCTOR +RemoteConnection::~RemoteConnection() {} + +void RemoteConnection::start() { + // LogEntry(__FUNCTION__); + ConfigureAws(); +} + +void RemoteConnection::end() { + // LogEntry(__FUNCTION__); + ShutdownAws(); +} + +void RemoteConnection::ConfigureAws() { + // LogEntry(__FUNCTION__); + + _aws_sdk_options = new Aws::SDKOptions(); + Aws::InitAPI(*_aws_sdk_options); + + Aws::Client::ClientConfiguration clientConfig; + + // TODO: proxy / override settings should be user configurable + // use this block for AWS + // clientConfig.proxyHost = "proxy-dmz.intel.com"; + // clientConfig.proxyPort = 912; + // clientConfig.proxyScheme = Aws::Http::Scheme::HTTP; + + // use this override for MinIO + clientConfig.endpointOverride = "http://127.0.0.1:9000"; + + _aws_client = new Aws::S3::S3Client(clientConfig); + _remote_connected = true; +} + +// TODO make the log level configurable +// void RemoteConnection::SetLogLevelDebug() { +// //_aws_sdk_options.loggingOptions.logLevel = +// // Aws::Utils::Logging::LogLevel::Debug; +// } + +void RemoteConnection::ShutdownAws() { + // LogEntry(__FUNCTION__); + Aws::ShutdownAPI(*_aws_sdk_options); + _remote_connected = false; +} + +// image file, takes path to store and vector of data +// TODO: make the raw data a more efficient format? +void RemoteConnection::Write(const std::string &path, + std::vector data) { + if (_remote_connected) { + write_s3(path, data); + } else { + std::cerr << "WRITE: The RemoteConnection has not been started" + << std::endl; + } +} + +// video file (or any file on disk specified by full path) +// opens file, reads into memory, uploads to AWS +void RemoteConnection::Write(const std::string &filename) { + if (_remote_connected) { + write_s3(filename); + } else { + std::cerr << "WRITE: The RemoteConnection has not been started" + << std::endl; + } +} + +void RemoteConnection::RetrieveFile(const std::string &filename) { + if (_remote_connected) { + retrieve_file(filename); + } else { + std::cerr << "WRITE: The RemoteConnection has not been started" + << std::endl; + } +} + +std::vector +RemoteConnection::ListFilesInFolder(const std::string &folder_name) { + if (_remote_connected) { + return get_file_list(folder_name); + } else { + std::cerr << "WRITE: The RemoteConnection has not been started" + << std::endl; + return std::vector(); + } +} + +std::vector RemoteConnection::Read(const std::string &path) { + if (_remote_connected) { + return read_s3(path); + } else { + std::cerr << "READ: The RemoteConnection has not been started" << std::endl; + } + return std::vector(); +} + +void RemoteConnection::Read_Video(const std::string &path) { + if (_remote_connected) { + read_s3_video(path); + } else { + std::cerr << "READ_Video: The RemoteConnection has not been started" + << std::endl; + } +} + +void RemoteConnection::Remove_Object(const std::string &path) { + if (_remote_connected) { + return remove_s3_object(path); + } else { + std::cerr << "REMOVE: The RemoteConnection has not been started" + << std::endl; + } +} + +//########Private S3 Functions######## + +void RemoteConnection::write_s3(const std::string &filename) { + Aws::S3::Model::PutObjectRequest put_request; + put_request.SetBucket(_bucket_name); + put_request.SetKey(filename); + + std::shared_ptr inputData = + Aws::MakeShared("SampleAllocationTag", filename.c_str(), + std::ios_base::in | std::ios_base::binary); + + if (!*inputData) { + std::cerr << "Error unable to read file " << filename << std::endl; + return; + } + + put_request.SetBody(inputData); + + Aws::S3::Model::PutObjectOutcome outcome = + _aws_client->PutObject(put_request); + + if (!outcome.IsSuccess()) { + const Aws::S3::S3Error &err = outcome.GetError(); + std::cerr << "Error: PutObject: " << err.GetExceptionName() << ": " + << err.GetMessage() << std::endl; + } else { + std::cout << "Added object '" << filename << "' to bucket: " << _bucket_name + << std::endl; + } +} + +void RemoteConnection::write_s3(const std::string &path, + std::vector data) { + Aws::S3::Model::PutObjectRequest put_request; + put_request.SetBucket(_bucket_name); + put_request.SetKey(path); + + auto input_data = Aws::MakeShared("PutObjectInputStream"); + input_data->write(reinterpret_cast(data.data()), data.size()); + + put_request.SetBody(input_data); + Aws::S3::Model::PutObjectOutcome outcome = + _aws_client->PutObject(put_request); + + if (!outcome.IsSuccess()) { + const Aws::S3::S3Error &err = outcome.GetError(); + std::cerr << "Error: PutObject: " << err.GetExceptionName() << ": " + << err.GetMessage() << std::endl; + } else { + std::cout << "Added object '" << path << "' to bucket: " << _bucket_name + << std::endl; + } +} + +void RemoteConnection::read_s3_video(const std::string &file_path) { + Aws::S3::Model::GetObjectRequest request; + request.SetBucket(_bucket_name); + request.SetKey(file_path); + + Aws::S3::Model::GetObjectOutcome outcome = _aws_client->GetObject(request); + + if (!outcome.IsSuccess()) { + const Aws::S3::S3Error &err = outcome.GetError(); + std::cerr << "Error: GetObject: " << err.GetExceptionName() << ": " + << err.GetMessage() << std::endl; + } else { + std::cout << "Successfully retrieved '" << file_path << "' from '" + << _bucket_name << "'." << std::endl; + + auto &retrieved_file = outcome.GetResult().GetBody(); + std::ofstream output_file(file_path.c_str(), + std::ios::out | std::ios::binary); + output_file << retrieved_file.rdbuf(); + } +} + +std::vector +RemoteConnection::read_s3(const std::string &file_path) { + Aws::S3::Model::GetObjectRequest request; + request.SetBucket(_bucket_name); + request.SetKey(file_path); + + Aws::S3::Model::GetObjectOutcome outcome = _aws_client->GetObject(request); + + if (!outcome.IsSuccess()) { + const Aws::S3::S3Error &err = outcome.GetError(); + std::cerr << "Error: GetObject: " << err.GetExceptionName() << ": " + << err.GetMessage() << std::endl; + return std::vector(); + } else { + std::cout << "Successfully retrieved '" << file_path << "' from '" + << _bucket_name << "'." << std::endl; + + std::stringstream stream; + stream << outcome.GetResult().GetBody().rdbuf(); + std::string str_stream = stream.str(); + std::vector data(str_stream.begin(), str_stream.end()); + return data; + } +} + +void RemoteConnection::retrieve_file(const std::string &file_path) { + Aws::S3::Model::GetObjectRequest request; + request.SetBucket(_bucket_name); + request.SetKey(file_path); + + Aws::S3::Model::GetObjectOutcome outcome = _aws_client->GetObject(request); + + if (!outcome.IsSuccess()) { + const Aws::S3::S3Error &err = outcome.GetError(); + std::cerr << "Error: GetObject: " << err.GetExceptionName() << ": " + << err.GetMessage() << std::endl; + } else { + std::cout << "Successfully retrieved '" << file_path << "' from '" + << _bucket_name << "'." << std::endl; + + auto &retrieved_file = outcome.GetResult().GetBody(); + std::ofstream output_file(file_path.c_str(), + std::ios::out | std::ios::binary); + output_file << retrieved_file.rdbuf(); + } +} + +std::vector +RemoteConnection::get_file_list(const std::string &path) { + std::vector results; + + Aws::S3::Model::ListObjectsRequest request; + request.SetBucket(_bucket_name); + request.SetPrefix(path); + + Aws::S3::Model::ListObjectsOutcome outcome = + _aws_client->ListObjects(request); + + if (!outcome.IsSuccess()) { + std::cerr << "Error: ListObjects: " << outcome.GetError().GetMessage() + << std::endl; + } else { + Aws::Vector objects = + outcome.GetResult().GetContents(); + + for (Aws::S3::Model::Object &object : objects) { + results.push_back(object.GetKey()); + } + } + + return results; +} + +void RemoteConnection::remove_s3_object(const std::string &file_path) { + Aws::S3::Model::DeleteObjectRequest delete_request; + + delete_request.SetBucket(_bucket_name); + delete_request.SetKey(file_path); + + auto delete_object_outcome = _aws_client->DeleteObject(delete_request); + + if (!delete_object_outcome.IsSuccess()) { + const Aws::S3::S3Error &err = delete_object_outcome.GetError(); + std::cerr << "Error: DeleteObject: " << err.GetExceptionName() << ": " + << err.GetMessage() << std::endl; + } +} + +// void RemoteConnection::LogEntry(std::string functionName) { +// // std::cout << "Entering " << functionName << "()" << std::endl; +// } diff --git a/src/vcl/TDBDenseDescriptorSet.cc b/src/vcl/TDBDenseDescriptorSet.cc index f52e2f91..c1663cc2 100644 --- a/src/vcl/TDBDenseDescriptorSet.cc +++ b/src/vcl/TDBDenseDescriptorSet.cc @@ -29,207 +29,194 @@ * */ -#include -#include -#include -#include #include #include +#include +#include #include +#include +#include #include "TDBDescriptorSet.h" -#include +// #include -#define ATTRIBUTE_DESC "descriptor" +#define ATTRIBUTE_DESC "descriptor" #define ATTRIBUTE_LABEL "label" using namespace VCL; -TDBDenseDescriptorSet::TDBDenseDescriptorSet(const std::string &filename): - TDBDescriptorSet(filename), - _flag_buffer_updated(false) -{ - TDBObject descriptorSetObject(_set_path); - read_descriptor_metadata(); +TDBDenseDescriptorSet::TDBDenseDescriptorSet(const std::string &filename) + : TDBDescriptorSet(filename), _flag_buffer_updated(false) { + TDBObject descriptorSetObject(_set_path); + read_descriptor_metadata(); } TDBDenseDescriptorSet::TDBDenseDescriptorSet(const std::string &filename, - uint32_t dim, - DistanceMetric metric): - TDBDescriptorSet(filename, dim), - _flag_buffer_updated(true) -{ - TDBObject descriptorSetObject; - - descriptorSetObject.set_full_dimensions( - std::vector{"d"}, - std::vector{(MAX_DESC-1)}, - std::vector{0}, - 10); - std::string desc = ATTRIBUTE_DESC; - std::string label = ATTRIBUTE_LABEL; - descriptorSetObject.set_single_attribute(desc, VCL::CompressionType::LZ4, - (float)_dimensions); - descriptorSetObject.set_single_attribute(label, VCL::CompressionType::LZ4, - (long)1); - - std::vector num_values{_dimensions, 1}; - descriptorSetObject.set_schema_dense(_set_path, num_values); - write_descriptor_metadata(); + uint32_t dim, + DistanceMetric metric) + : TDBDescriptorSet(filename, dim), _flag_buffer_updated(true) { + TDBObject descriptorSetObject; + + descriptorSetObject.set_full_dimensions(std::vector{"d"}, + std::vector{(MAX_DESC - 1)}, + std::vector{0}, 10); + std::string desc = ATTRIBUTE_DESC; + std::string label = ATTRIBUTE_LABEL; + descriptorSetObject.set_single_attribute(desc, VCL::CompressionType::LZ4, + (float)_dimensions); + descriptorSetObject.set_single_attribute(label, VCL::CompressionType::LZ4, + (long)1); + + std::vector num_values{_dimensions, 1}; + descriptorSetObject.set_schema_dense(_set_path, num_values); + write_descriptor_metadata(); } -void TDBDenseDescriptorSet::load_buffer() -{ - try { +void TDBDenseDescriptorSet::load_buffer() { + try { - read_descriptor_metadata(); - - tiledb::Array array(_ctx, _set_path, TILEDB_READ); - { - _buffer.resize(_dimensions * _n_total); - _label_ids.resize(_n_total); - - tiledb::Query query(_ctx, array); - query.set_layout(TILEDB_ROW_MAJOR); - query.set_subarray({0, _n_total - 1}); - query.set_buffer(ATTRIBUTE_DESC, _buffer); - query.set_buffer(ATTRIBUTE_LABEL, _label_ids); - query.submit(); - } + read_descriptor_metadata(); - } catch (tiledb::TileDBError &e) { - throw VCLException(TileDBError, "Error: Reading Dense array"); + tiledb::Array array(_ctx, _set_path, TILEDB_READ); + { + _buffer.resize(_dimensions * _n_total); + _label_ids.resize(_n_total); + + tiledb::Query query(_ctx, array); + query.set_layout(TILEDB_ROW_MAJOR); + query.set_subarray({0, _n_total - 1}); + query.set_data_buffer(ATTRIBUTE_DESC, _buffer); + query.set_data_buffer(ATTRIBUTE_LABEL, _label_ids); + query.submit(); } - _flag_buffer_updated = true; + } catch (tiledb::TileDBError &e) { + throw VCLException(TileDBError, "Error: Reading Dense array"); + } + + _flag_buffer_updated = true; } -void TDBDenseDescriptorSet::read_descriptor_metadata() -{ - std::vector subarray = { METADATA_OFFSET, - (METADATA_OFFSET + 1)}; - std::vector values(2); +void TDBDenseDescriptorSet::read_descriptor_metadata() { + std::vector subarray = {METADATA_OFFSET, (METADATA_OFFSET + 1)}; + std::vector values(2); - tiledb::Array array(_ctx, _set_path, TILEDB_READ); - tiledb::Query md_read(_ctx, array, TILEDB_READ); + tiledb::Array array(_ctx, _set_path, TILEDB_READ); + tiledb::Query md_read(_ctx, array, TILEDB_READ); - md_read.set_subarray(subarray); - md_read.set_layout(TILEDB_ROW_MAJOR); + md_read.set_subarray(subarray); + md_read.set_layout(TILEDB_ROW_MAJOR); - md_read.set_buffer(ATTRIBUTE_LABEL, values); - md_read.submit(); - array.close(); + md_read.set_data_buffer(ATTRIBUTE_LABEL, values); + md_read.submit(); + array.close(); - _dimensions = values[0]; - _n_total = values[1]; + _dimensions = values[0]; + _n_total = values[1]; } -void TDBDenseDescriptorSet::write_descriptor_metadata() -{ - std::vector metadata; - metadata.push_back(_dimensions); - metadata.push_back(_n_total); - - // This is only here because tiledb requires all the - // attributes when writing. - std::vector aux_dims(_dimensions * 2, .0f); - - // Write metadata - tiledb::Array array(_ctx, _set_path, TILEDB_WRITE); - tiledb::Query query(_ctx, array); - query.set_layout(TILEDB_ROW_MAJOR); - query.set_subarray({METADATA_OFFSET, METADATA_OFFSET+1}); - query.set_buffer(ATTRIBUTE_LABEL, metadata); - query.set_buffer(ATTRIBUTE_DESC, aux_dims); - query.submit(); - query.finalize(); +void TDBDenseDescriptorSet::write_descriptor_metadata() { + std::vector metadata; + metadata.push_back(_dimensions); + metadata.push_back(_n_total); + + // This is only here because tiledb requires all the + // attributes when writing. + std::vector aux_dims(_dimensions * 2, .0f); + + // Write metadata + tiledb::Array array(_ctx, _set_path, TILEDB_WRITE); + tiledb::Query query(_ctx, array); + query.set_layout(TILEDB_ROW_MAJOR); + query.set_subarray({METADATA_OFFSET, METADATA_OFFSET + 1}); + query.set_data_buffer(ATTRIBUTE_LABEL, metadata); + query.set_data_buffer(ATTRIBUTE_DESC, aux_dims); + query.submit(); + query.finalize(); } -long TDBDenseDescriptorSet::add(float* descriptors, unsigned n, long* labels) -{ - try { - std::vector att_label; - long* labels_buffer = labels; - - if (labels == NULL) { - // By default, labels is -1 - att_label = std::vector (n, -1); - labels_buffer = att_label.data(); - } - - { - tiledb::Array array(_ctx, _set_path, TILEDB_WRITE); - tiledb::Query query(_ctx, array); - query.set_layout(TILEDB_ROW_MAJOR); - query.set_subarray({_n_total, _n_total + n-1}); - query.set_buffer(ATTRIBUTE_DESC, descriptors, n * _dimensions); - query.set_buffer(ATTRIBUTE_LABEL, labels_buffer, n); - query.submit(); - query.finalize(); - } - } catch (tiledb::TileDBError &e) { - _flag_buffer_updated = false; - throw VCLException(UnsupportedOperation, e.what()); - } - - // Write _n_total into tiledb - // This is good because we only write metadata - // (_n_total) after the other two writes succedded. - _n_total += n; - write_descriptor_metadata(); +long TDBDenseDescriptorSet::add(float *descriptors, unsigned n, long *labels) { + try { + std::vector att_label; + long *labels_buffer = labels; - // - n becase we already increase _n_total for writing metadata on tdb - long old_n_total = _n_total - n; + if (labels == NULL) { + // By default, labels is -1 + att_label = std::vector(n, -1); + labels_buffer = att_label.data(); + } - _buffer.resize((_n_total) * _dimensions); - std::memcpy(&_buffer[old_n_total * _dimensions], descriptors, - n * _dimensions * sizeof(float)); + { + tiledb::Array array(_ctx, _set_path, TILEDB_WRITE); + tiledb::Query query(_ctx, array); + query.set_layout(TILEDB_ROW_MAJOR); + query.set_subarray({_n_total, _n_total + n - 1}); + query.set_data_buffer(ATTRIBUTE_DESC, descriptors, n * _dimensions); + query.set_data_buffer(ATTRIBUTE_LABEL, labels_buffer, n); - if (labels != NULL) { - _label_ids.resize(_n_total); - std::memcpy(&_label_ids[old_n_total], labels, n * sizeof(long)); + query.submit(); + query.finalize(); } - - return old_n_total; + } catch (tiledb::TileDBError &e) { + _flag_buffer_updated = false; + throw VCLException(UnsupportedOperation, e.what()); + } + + // Write _n_total into tiledb + // This is good because we only write metadata + // (_n_total) after the other two writes succedded. + _n_total += n; + write_descriptor_metadata(); + + // - n becase we already increase _n_total for writing metadata on tdb + long old_n_total = _n_total - n; + + _buffer.resize((_n_total)*_dimensions); + std::memcpy(&_buffer[old_n_total * _dimensions], descriptors, + n * _dimensions * sizeof(float)); + + if (labels != NULL) { + _label_ids.resize(_n_total); + std::memcpy(&_label_ids[old_n_total], labels, n * sizeof(long)); + } + + return old_n_total; } -void TDBDenseDescriptorSet::search(float* query, - unsigned n_queries, unsigned k, - long* ids, float* distances) -{ - if (!_flag_buffer_updated) { - load_buffer(); - } +void TDBDenseDescriptorSet::search(float *query, unsigned n_queries, unsigned k, + long *ids, float *distances) { + if (!_flag_buffer_updated) { + load_buffer(); + } - std::vector d(_n_total); - std::vector idxs(_n_total); + std::vector d(_n_total); + std::vector idxs(_n_total); - for (int i = 0; i < n_queries; ++i) { + for (int i = 0; i < n_queries; ++i) { - compute_distances(query + i * _dimensions, d, _buffer); - std::iota(idxs.begin(), idxs.end(), 0); - std::partial_sort(idxs.begin(), idxs.begin() + k, idxs.end(), - [&d](size_t i1, size_t i2) { return d[i1] < d[i2]; }); + compute_distances(query + i * _dimensions, d, _buffer); + std::iota(idxs.begin(), idxs.end(), 0); + std::partial_sort(idxs.begin(), idxs.begin() + k, idxs.end(), + [&d](size_t i1, size_t i2) { return d[i1] < d[i2]; }); - for (int j = 0; j < k; ++j) { - ids [i * k + j] = idxs[j]; - distances[i * k + j] = d[idxs[j]]; - } + for (int j = 0; j < k; ++j) { + ids[i * k + j] = idxs[j]; + distances[i * k + j] = d[idxs[j]]; } + } } -void TDBDenseDescriptorSet::get_descriptors(long* ids, unsigned n, - float* descriptors) -{ - if (!_flag_buffer_updated) { - load_buffer(); - } - - for (int i = 0; i < n; ++i) { - long idx = ids[i] * _dimensions; - long offset = i *_dimensions; - std::memcpy(descriptors + offset, &_buffer[idx], - sizeof(float) * _dimensions); - } +void TDBDenseDescriptorSet::get_descriptors(long *ids, unsigned n, + float *descriptors) { + if (!_flag_buffer_updated) { + load_buffer(); + } + + for (int i = 0; i < n; ++i) { + long idx = ids[i] * _dimensions; + long offset = i * _dimensions; + std::memcpy(descriptors + offset, &_buffer[idx], + sizeof(float) * _dimensions); + } } diff --git a/src/vcl/TDBDescriptorSet.cc b/src/vcl/TDBDescriptorSet.cc index 3dfdc8db..0d5ef8d8 100644 --- a/src/vcl/TDBDescriptorSet.cc +++ b/src/vcl/TDBDescriptorSet.cc @@ -27,12 +27,12 @@ * */ -#include -#include -#include -#include #include #include +#include +#include +#include +#include // By default, we use OMP. // #define USE_COMPUTE_MKL @@ -52,125 +52,108 @@ using namespace VCL; -TDBDescriptorSet::TDBDescriptorSet(const std::string &filename): - DescriptorSetData(filename) -{ - read_labels_map(); +TDBDescriptorSet::TDBDescriptorSet(const std::string &filename) + : DescriptorSetData(filename) { + read_labels_map(); } -TDBDescriptorSet::TDBDescriptorSet(const std::string &filename, - uint32_t dim): - DescriptorSetData(filename, dim) -{ -} +TDBDescriptorSet::TDBDescriptorSet(const std::string &filename, uint32_t dim) + : DescriptorSetData(filename, dim) {} -TDBDescriptorSet::~TDBDescriptorSet() -{ -} +TDBDescriptorSet::~TDBDescriptorSet() {} -void TDBDescriptorSet::train() -{ - // For now, we just consolidate arrays which - // should make the reads faster (according to TileDB docs). - // There are more fancy tricks that can be implemented - // in the future, specially for the sparse arrays. - // Consolidation is needed since many of the insertions done - // through TileDB fragments. - - // Consolidate array - // tiledb::Array::consolidate(_tiledb_ctx, _set_path); +void TDBDescriptorSet::train() { + // For now, we just consolidate arrays which + // should make the reads faster (according to TileDB docs). + // There are more fancy tricks that can be implemented + // in the future, specially for the sparse arrays. + // Consolidation is needed since many of the insertions done + // through TileDB fragments. + + // Consolidate array + // tiledb::Array::consolidate(_tiledb_ctx, _set_path); } -void TDBDescriptorSet::compute_distances(float* q, - std::vector& d, - std::vector& data) -{ - size_t n = data.size() / _dimensions; +void TDBDescriptorSet::compute_distances(float *q, std::vector &d, + std::vector &data) { + size_t n = data.size() / _dimensions; - float* sub = new float[_dimensions * n]; + float *sub = new float[_dimensions * n]; #ifdef USE_COMPUTE_MKL - // Intel MKL - // #pragma omp parallel for - for (int i = 0; i < n; ++i) { - size_t idx = i * _dimensions; - vsSub(_dimensions, q, data.data() + idx, sub + idx); - d[i] = std::pow(cblas_snrm2(_dimensions, sub + idx, 1),2); - } + // Intel MKL + // #pragma omp parallel for + for (int i = 0; i < n; ++i) { + size_t idx = i * _dimensions; + vsSub(_dimensions, q, data.data() + idx, sub + idx); + d[i] = std::pow(cblas_snrm2(_dimensions, sub + idx, 1), 2); + } #endif #ifdef USE_COMPUTE_OMP - // Using RAW OpenMP / This can be optimized - #pragma omp parallel for - for (int i = 0; i < n; ++i) { - size_t idx = i * _dimensions; - - float sum = 0; - // #pragma omp parallel for // has to be a reduction - for (int j = 0; j < _dimensions; ++j) { - sum += std::pow(data[idx + j] - q[j], 2); - } - - d[i] = sum; // std::sqrt(sum); +// Using RAW OpenMP / This can be optimized +#pragma omp parallel for + for (int i = 0; i < n; ++i) { + size_t idx = i * _dimensions; + + float sum = 0; + // #pragma omp parallel for // has to be a reduction + for (int j = 0; j < _dimensions; ++j) { + sum += std::pow(data[idx + j] - q[j], 2); } + + d[i] = sum; // std::sqrt(sum); + } #endif - delete[] sub; + delete[] sub; } -void TDBDescriptorSet::classify(float* descriptors, unsigned n, - long* labels, unsigned quorum) -{ - float* distances = new float[n * quorum]; - long* ids_aux = new long [n * quorum]; - - search(descriptors, n, quorum, ids_aux, distances); - - for (int j = 0; j < n; ++j) { - - std::map map_voting; - long winner = -1; - unsigned max = 0; - for (int i = 0; i < quorum; ++i) { - long idx = ids_aux[quorum*j + i]; - if (idx < 0) - continue; // Means not found - - long label_id = _label_ids.at(idx); - map_voting[label_id] += 1; - if (max < map_voting[label_id]) { - max = map_voting[label_id]; - winner = label_id; - } - } - labels[j] = winner; +void TDBDescriptorSet::classify(float *descriptors, unsigned n, long *labels, + unsigned quorum) { + float *distances = new float[n * quorum]; + long *ids_aux = new long[n * quorum]; + + search(descriptors, n, quorum, ids_aux, distances); + + for (int j = 0; j < n; ++j) { + + std::map map_voting; + long winner = -1; + unsigned max = 0; + for (int i = 0; i < quorum; ++i) { + long idx = ids_aux[quorum * j + i]; + if (idx < 0) + continue; // Means not found + + long label_id = _label_ids.at(idx); + map_voting[label_id] += 1; + if (max < map_voting[label_id]) { + max = map_voting[label_id]; + winner = label_id; + } } - delete[] distances; - delete[] ids_aux; + labels[j] = winner; + } + delete[] distances; + delete[] ids_aux; } -void TDBDescriptorSet::get_labels(long* ids, unsigned n, long* labels) -{ - for (int i = 0; i < n; ++i){ - labels[i] = _label_ids[ids[i]]; - } +void TDBDescriptorSet::get_labels(long *ids, unsigned n, long *labels) { + for (int i = 0; i < n; ++i) { + labels[i] = _label_ids[ids[i]]; + } } -void TDBDescriptorSet::get_descriptors(long* ids, unsigned n, - float* descriptors) -{ - throw VCLException(UnsupportedOperation, - "get_descriptors Not implemented"); +void TDBDescriptorSet::get_descriptors(long *ids, unsigned n, + float *descriptors) { + throw VCLException(UnsupportedOperation, "get_descriptors Not implemented"); } -void TDBDescriptorSet::store() -{ - write_labels_map(); -} +void TDBDescriptorSet::store() { write_labels_map(); } -void TDBDescriptorSet::store(std::string filename) -{ - // TODO: Allow user to store in a different file, - // which is basically make a copy of the TileDB folder. - throw VCLException(UnsupportedOperation, "Unsupported operation"); +void TDBDescriptorSet::store(std::string filename) { + // TODO: Allow user to store in a different file, + // which is basically make a copy of the TileDB folder. + throw VCLException(UnsupportedOperation, "Unsupported operation"); } diff --git a/src/vcl/TDBDescriptorSet.h b/src/vcl/TDBDescriptorSet.h index edb16ae1..ff31d5e5 100644 --- a/src/vcl/TDBDescriptorSet.h +++ b/src/vcl/TDBDescriptorSet.h @@ -34,136 +34,131 @@ #pragma once +#include +#include #include #include #include -#include -#include #include -#include "vcl/Exception.h" #include "DescriptorSetData.h" #include "TDBObject.h" +#include "vcl/Exception.h" namespace VCL { - typedef std::vector DescBuffer; - typedef std::vector DistanceData; +typedef std::vector DescBuffer; +typedef std::vector DistanceData; - class TDBDescriptorSet: public DescriptorSet::DescriptorSetData, - public TDBObject { +class TDBDescriptorSet : public DescriptorSet::DescriptorSetData, + public TDBObject { - protected: - const unsigned long MAX_DESC = 100000; - const unsigned long METADATA_OFFSET = MAX_DESC - 2; +protected: + const unsigned long MAX_DESC = 100000; + const unsigned long METADATA_OFFSET = MAX_DESC - 2; - // this is caching data - std::vector _label_ids; // we need to move this + // this is caching data + std::vector _label_ids; // we need to move this - void compute_distances(float* q, DistanceData& d, DescBuffer& data); + void compute_distances(float *q, DistanceData &d, DescBuffer &data); - virtual void read_descriptor_metadata() = 0; - virtual void write_descriptor_metadata() = 0; + virtual void read_descriptor_metadata() = 0; + virtual void write_descriptor_metadata() = 0; - public: +public: + /** + * Loads an existing collection located at collection_path + * or created a new collection if it does not exist + * + * @param collection_path Full Path to the collection folder + */ + TDBDescriptorSet(const std::string &collection_path); - /** - * Loads an existing collection located at collection_path - * or created a new collection if it does not exist - * - * @param collection_path Full Path to the collection folder - */ - TDBDescriptorSet(const std::string &collection_path); + TDBDescriptorSet(const std::string &collection_path, unsigned dim); - TDBDescriptorSet(const std::string &collection_path, unsigned dim); + ~TDBDescriptorSet(); - ~TDBDescriptorSet(); + virtual long add(float *descriptors, unsigned n_descriptors, + long *classes) = 0; - virtual long add(float* descriptors, unsigned n_descriptors, long* classes) = 0; + virtual void train(); - virtual void train(); + virtual void train(float *descriptors, unsigned n) { train(); } - virtual void train(float* descriptors, unsigned n) { train(); } + bool is_trained() { return true; } - bool is_trained() { return true; } + virtual void search(float *query, unsigned n_queries, unsigned k, + long *descriptors, float *distances) = 0; - virtual void search(float* query, unsigned n_queries, unsigned k, - long* descriptors, float* distances) = 0; + virtual void classify(float *descriptors, unsigned n, long *labels, + unsigned quorum); - virtual void classify(float* descriptors, unsigned n, long* labels, - unsigned quorum); + virtual void get_descriptors(long *ids, unsigned n, float *descriptors); - virtual void get_descriptors(long* ids, unsigned n, - float* descriptors); + virtual void get_labels(long *ids, unsigned n, long *labels); - virtual void get_labels(long* ids, unsigned n, long* labels); - - void store(); - void store(std::string set_path); - }; - - class TDBDenseDescriptorSet : public TDBDescriptorSet { - - private: + void store(); + void store(std::string set_path); +}; - // This is for caching, accelerates searches fairly well. - bool _flag_buffer_updated; - std::vector _buffer; +class TDBDenseDescriptorSet : public TDBDescriptorSet { - void load_buffer(); - void read_descriptor_metadata(); - void write_descriptor_metadata(); +private: + // This is for caching, accelerates searches fairly well. + bool _flag_buffer_updated; + std::vector _buffer; - public: - TDBDenseDescriptorSet(const std::string &collection_path); + void load_buffer(); + void read_descriptor_metadata(); + void write_descriptor_metadata(); - TDBDenseDescriptorSet(const std::string &collection_path, - unsigned dim, DistanceMetric metric); +public: + TDBDenseDescriptorSet(const std::string &collection_path); - ~TDBDenseDescriptorSet() {}; + TDBDenseDescriptorSet(const std::string &collection_path, unsigned dim, + DistanceMetric metric); - long add(float* descriptors, unsigned n_descriptors, long* classes); + ~TDBDenseDescriptorSet(){}; - void search(float* query, unsigned n_queries, unsigned k, - long* descriptors, float* distances); + long add(float *descriptors, unsigned n_descriptors, long *classes); - void get_descriptors(long* ids, unsigned n, float* descriptors); - }; + void search(float *query, unsigned n_queries, unsigned k, long *descriptors, + float *distances); - class TDBSparseDescriptorSet : public TDBDescriptorSet { + void get_descriptors(long *ids, unsigned n, float *descriptors); +}; - private: +class TDBSparseDescriptorSet : public TDBDescriptorSet { - void read_descriptor_metadata(); - void write_descriptor_metadata(); +private: + void read_descriptor_metadata(); + void write_descriptor_metadata(); - void load_neighbors(float* query, unsigned k, - std::vector& descriptors, - std::vector& desc_ids, - std::vector& desc_labels); + void load_neighbors(float *query, unsigned k, std::vector &descriptors, + std::vector &desc_ids, + std::vector &desc_labels); - void search(float* query, unsigned n_queries, unsigned k, - long* descriptors, float* distances, long* labels); + void search(float *query, unsigned n_queries, unsigned k, long *descriptors, + float *distances, long *labels); - public: - TDBSparseDescriptorSet(const std::string &collection_path); +public: + TDBSparseDescriptorSet(const std::string &collection_path); - TDBSparseDescriptorSet(const std::string &collection_path, - unsigned dim, DistanceMetric metric); + TDBSparseDescriptorSet(const std::string &collection_path, unsigned dim, + DistanceMetric metric); - ~TDBSparseDescriptorSet() {}; + ~TDBSparseDescriptorSet(){}; - long add(float* descriptors, unsigned n_descriptors, long* classes); + long add(float *descriptors, unsigned n_descriptors, long *classes); - void search(float* query, unsigned n_queries, unsigned k, - long* descriptors, float* distances); + void search(float *query, unsigned n_queries, unsigned k, long *descriptors, + float *distances); - void classify(float* descriptors, unsigned n, long* labels, - unsigned quorum); + void classify(float *descriptors, unsigned n, long *labels, unsigned quorum); - void get_descriptors(long* ids, unsigned n, float* descriptors); + void get_descriptors(long *ids, unsigned n, float *descriptors); - void get_labels(long* ids, unsigned n, long* labels); - }; + void get_labels(long *ids, unsigned n, long *labels); }; +}; // namespace VCL diff --git a/src/vcl/TDBImage.cc b/src/vcl/TDBImage.cc index 0213b0c9..2225108e 100644 --- a/src/vcl/TDBImage.cc +++ b/src/vcl/TDBImage.cc @@ -27,765 +27,740 @@ * */ +#include #include #include -#include -#include +#include #include +#include #include -#include -#include "vcl/VCL.h" #include "TDBImage.h" #include "TDBObject.h" +#include "vcl/VCL.h" using namespace VCL; #define MAX_UCHAR 256 - /* *********************** */ - /* CONSTRUCTORS */ - /* *********************** */ -TDBImage::TDBImage() : TDBObject() -{ - _img_height = 0; - _img_width = 0; - _img_channels = 0; - _img_size = 0; +/* *********************** */ +/* CONSTRUCTORS */ +/* *********************** */ +TDBImage::TDBImage() : TDBObject() { + _img_height = 0; + _img_width = 0; + _img_channels = 0; + _img_size = 0; - _threshold = 0; + _threshold = 0; - set_num_dimensions(2); - set_default_attributes(); - set_default_dimensions(); + set_num_dimensions(2); + set_default_attributes(); + set_default_dimensions(); - _raw_data = NULL; + _raw_data = NULL; } -TDBImage::TDBImage(const std::string &image_id) : TDBObject(image_id) -{ - _img_height = 0; - _img_width = 0; - _img_channels = 0; - _img_size = 0; +TDBImage::TDBImage(const std::string &image_id) : TDBObject(image_id) { + _img_height = 0; + _img_width = 0; + _img_channels = 0; + _img_size = 0; - _threshold = 0; + _threshold = 0; - set_num_dimensions(2); - set_default_attributes(); - set_default_dimensions(); + set_num_dimensions(2); + set_default_attributes(); + set_default_dimensions(); - _raw_data = NULL; + _raw_data = NULL; } -template -TDBImage::TDBImage(T* buffer, long size) : TDBObject() -{ - _img_height = 0; - _img_width = 0; - _img_channels = 0; - _img_size = size; +TDBImage::TDBImage(const std::string &image_id, RemoteConnection &connection) + : TDBObject(image_id, connection) { - _threshold = 0; + _img_height = 0; + _img_width = 0; + _img_channels = 0; + _img_size = 0; - set_num_dimensions(2); - set_default_attributes(); - set_default_dimensions(); + _threshold = 0; - _raw_data = new unsigned char[size]; - std::memcpy(_raw_data, buffer, _img_size); + set_num_dimensions(2); + set_default_attributes(); + set_default_dimensions(); + + _raw_data = NULL; +} + +template TDBImage::TDBImage(T *buffer, long size) : TDBObject() { + _img_height = 0; + _img_width = 0; + _img_channels = 0; + _img_size = size; + + _threshold = 0; + + set_num_dimensions(2); + set_default_attributes(); + set_default_dimensions(); + + _raw_data = new unsigned char[size]; + std::memcpy(_raw_data, buffer, _img_size); } // OpenCV type CV_8UC1-4 -template TDBImage::TDBImage(unsigned char* buffer, long size); +template TDBImage::TDBImage(unsigned char *buffer, long size); // OpenCV type CV_8SC1-4 -template TDBImage::TDBImage(char* buffer, long size); +template TDBImage::TDBImage(char *buffer, long size); // OpenCV type CV_16UC1-4 -template TDBImage::TDBImage(unsigned short* buffer, long size); +template TDBImage::TDBImage(unsigned short *buffer, long size); // OpenCV type CV_16SC1-4 -template TDBImage::TDBImage(short* buffer, long size); +template TDBImage::TDBImage(short *buffer, long size); // OpenCV type CV_32SC1-4 -template TDBImage::TDBImage(int* buffer, long size); +template TDBImage::TDBImage(int *buffer, long size); // OpenCV type CV_32FC1-4 -template TDBImage::TDBImage(float* buffer, long size); +template TDBImage::TDBImage(float *buffer, long size); // OpenCV type CV_64FC1-4 -template TDBImage::TDBImage(double* buffer, long size); - - -TDBImage::TDBImage(TDBImage &tdb) : TDBObject(tdb) -{ - if ( !tdb.has_data() ) { - try { - tdb.read(); - } - catch ( VCL::Exception &e ) { - _raw_data = NULL; - } +template TDBImage::TDBImage(double *buffer, long size); + +TDBImage::TDBImage(TDBImage &tdb) : TDBObject(tdb) { + if (!tdb.has_data()) { + try { + tdb.read(); + } catch (VCL::Exception &e) { + _raw_data = NULL; } + } - set_equal(tdb); - set_image_data_equal(tdb); - _raw_data = 0; + set_equal(tdb); + set_image_data_equal(tdb); + _raw_data = 0; - if ( tdb.has_data() ) { - uint64_t size = _img_height * _img_width * _img_channels; - _raw_data = new unsigned char[size]; - std::memcpy(_raw_data, tdb._raw_data, size); - } + if (tdb.has_data()) { + uint64_t size = _img_height * _img_width * _img_channels; + _raw_data = new unsigned char[size]; + std::memcpy(_raw_data, tdb._raw_data, size); + } } -void TDBImage::operator=(TDBImage &tdb) -{ - unsigned char *temp = _raw_data; +void TDBImage::operator=(TDBImage &tdb) { + unsigned char *temp = _raw_data; - if ( !tdb.has_data() ) { - try { - tdb.read(); - } - catch ( VCL::Exception &e ) { - _raw_data = NULL; - } + if (!tdb.has_data()) { + try { + tdb.read(); + } catch (VCL::Exception &e) { + _raw_data = NULL; } + } - set_equal(tdb); - set_image_data_equal(tdb); - - if ( tdb.has_data() ) { - if (_raw_data != NULL) - delete [] _raw_data; - - uint64_t array_size = _img_height * _img_width * _img_channels; - _raw_data = new unsigned char[array_size]; - std::memcpy(_raw_data, tdb._raw_data, array_size); - } + set_equal(tdb); + set_image_data_equal(tdb); -} + if (tdb.has_data()) { + if (_raw_data != NULL) + delete[] _raw_data; -void TDBImage::set_image_data_equal(const TDBImage &tdb) -{ - _img_height = tdb._img_height; - _img_width = tdb._img_width; - _img_channels = tdb._img_channels; - _img_size = tdb._img_size; - _threshold = tdb._threshold; + uint64_t array_size = _img_height * _img_width * _img_channels; + _raw_data = new unsigned char[array_size]; + std::memcpy(_raw_data, tdb._raw_data, array_size); + } } -TDBImage::~TDBImage() -{ - delete [] _raw_data; +void TDBImage::set_image_data_equal(const TDBImage &tdb) { + _img_height = tdb._img_height; + _img_width = tdb._img_width; + _img_channels = tdb._img_channels; + _img_size = tdb._img_size; + _threshold = tdb._threshold; } +TDBImage::~TDBImage() { delete[] _raw_data; } - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* GET FUNCTIONS */ +/* *********************** */ -long TDBImage::get_image_size() -{ - if (_img_size == 0 && _name == "") { - throw VCLException(TileDBNotFound, "No data in TileDB object yet"); - } - else if (_img_size == 0 && _name != "") { - read_image_metadata(); - } +long TDBImage::get_image_size() { + if (_img_size == 0 && _name == "") { + throw VCLException(TileDBNotFound, "No data in TileDB object yet"); + } else if (_img_size == 0 && _name != "") { + read_image_metadata(); + } - return _img_size; + return _img_size; } -int TDBImage::get_image_height() -{ - if (_img_height == 0 && _name == "") - throw VCLException(TileDBNotFound, "No data in TileDB object yet"); - else if ( _img_height == 0 && _name != "") - read_image_metadata(); +int TDBImage::get_image_height() { + if (_img_height == 0 && _name == "") + throw VCLException(TileDBNotFound, "No data in TileDB object yet"); + else if (_img_height == 0 && _name != "") + read_image_metadata(); - return _img_height; + return _img_height; } -int TDBImage::get_image_width() -{ - if (_img_width == 0 && _name == "") - throw VCLException(TileDBNotFound, "No data in TileDB object yet"); - else if ( _img_width == 0 && _name != "") - read_image_metadata(); +int TDBImage::get_image_width() { + if (_img_width == 0 && _name == "") + throw VCLException(TileDBNotFound, "No data in TileDB object yet"); + else if (_img_width == 0 && _name != "") + read_image_metadata(); - return _img_width; + return _img_width; } -int TDBImage::get_image_channels() -{ - if (_img_channels == 0 && _name == "") - throw VCLException(TileDBNotFound, "No data in TileDB object yet"); - else if ( _img_channels == 0 && _name != "") - read_image_metadata(); +int TDBImage::get_image_channels() { + if (_img_channels == 0 && _name == "") + throw VCLException(TileDBNotFound, "No data in TileDB object yet"); + else if (_img_channels == 0 && _name != "") + read_image_metadata(); - return _img_channels; + return _img_channels; } -cv::Mat TDBImage::get_cvmat() -{ - if ( _raw_data == NULL ) - read(); +cv::Mat TDBImage::get_cvmat() { + if (_raw_data == NULL) + read(); - unsigned char* buffer = new unsigned char[_img_size]; + unsigned char *buffer = new unsigned char[_img_size]; - std::memcpy(buffer, _raw_data, _img_size); + std::memcpy(buffer, _raw_data, _img_size); - cv::Mat img_clone; + cv::Mat img_clone; - if ( _img_channels == 1 ) { - cv::Mat img(cv::Size(_img_width, _img_height), CV_8UC1, buffer); - img_clone = img.clone(); - } - else { - cv::Mat img(cv::Size(_img_width, _img_height), CV_8UC3, buffer); - img_clone = img.clone(); - } + if (_img_channels == 1) { + cv::Mat img(cv::Size(_img_width, _img_height), CV_8UC1, buffer); + img_clone = img.clone(); + } else { + cv::Mat img(cv::Size(_img_width, _img_height), CV_8UC3, buffer); + img_clone = img.clone(); + } - delete [] buffer; - return img_clone; + delete[] buffer; + return img_clone; } -template -void TDBImage::get_buffer(T* buffer, long buffer_size) -{ - if ( buffer_size != get_image_size() ) { - std::cout << "buffer size not equal to image size\n"; - std::cout << "buffer size: " << buffer_size << std::endl; - std::cout << "image size: " << _img_size << std::endl; - throw VCLException(SizeMismatch, buffer_size + " is not equal to " - + _img_size); - } +template void TDBImage::get_buffer(T *buffer, long buffer_size) { + if (buffer_size != get_image_size()) { + std::cout << "buffer size not equal to image size\n"; + std::cout << "buffer size: " << buffer_size << std::endl; + std::cout << "image size: " << _img_size << std::endl; + throw VCLException(SizeMismatch, + buffer_size + " is not equal to " + _img_size); + } - if ( _raw_data == NULL ) - read(); + if (_raw_data == NULL) + read(); - std::memcpy(buffer, _raw_data, buffer_size); + std::memcpy(buffer, _raw_data, buffer_size); } -template void TDBImage::get_buffer(unsigned char* buffer, long buffer_size); -template void TDBImage::get_buffer(char* buffer, long buffer_size); -template void TDBImage::get_buffer(unsigned short* buffer, long buffer_size); -template void TDBImage::get_buffer(short* buffer, long buffer_size); -template void TDBImage::get_buffer(int* buffer, long buffer_size); -template void TDBImage::get_buffer(float* buffer, long buffer_size); -template void TDBImage::get_buffer(double* buffer, long buffer_size); - +template void TDBImage::get_buffer(unsigned char *buffer, long buffer_size); +template void TDBImage::get_buffer(char *buffer, long buffer_size); +template void TDBImage::get_buffer(unsigned short *buffer, long buffer_size); +template void TDBImage::get_buffer(short *buffer, long buffer_size); +template void TDBImage::get_buffer(int *buffer, long buffer_size); +template void TDBImage::get_buffer(float *buffer, long buffer_size); +template void TDBImage::get_buffer(double *buffer, long buffer_size); - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* SET FUNCTIONS */ +/* *********************** */ -void TDBImage::set_image_properties(int height, int width, int channels) -{ - _img_height = height; - _img_width = width; - _img_channels = channels; - _img_size = _img_height * _img_width * _img_channels; +void TDBImage::set_image_properties(int height, int width, int channels) { + _img_height = height; + _img_width = width; + _img_channels = channels; + _img_size = _img_height * _img_width * _img_channels; } +void TDBImage::set_configuration(RemoteConnection *remote) { + if (!remote->connected()) + throw VCLException(SystemNotFound, "Remote Connection not initialized"); + set_config(remote); +} - /* *********************** */ - /* TDBIMAGE INTERACTION */ - /* *********************** */ -void TDBImage::write(const std::string &image_id, bool metadata) -{ - if ( _raw_data == NULL ) - throw VCLException(ObjectEmpty, "No data to be written"); +/* *********************** */ +/* TDBIMAGE INTERACTION */ +/* *********************** */ +void TDBImage::write(const std::string &image_id, bool metadata) { + if (_raw_data == NULL) + throw VCLException(ObjectEmpty, "No data to be written"); - std::string array_name = namespace_setup(image_id); + std::string array_name = namespace_setup(image_id); - std::vector num_values; - if ( _num_attributes == 1 && _img_channels == 3) - num_values.push_back(3); - else - num_values.push_back(1); - set_schema_dense(array_name, num_values); + std::vector num_values; + if (_num_attributes == 1 && _img_channels == 3) + num_values.push_back(3); + else + num_values.push_back(1); + set_schema_dense(array_name, num_values); - tiledb::Array array(_ctx, array_name, TILEDB_WRITE); + tiledb::Array array(_ctx, array_name, TILEDB_WRITE); - tiledb::Query write_query(_ctx, array, TILEDB_WRITE); + tiledb::Query write_query(_ctx, array, TILEDB_WRITE); - write_query.set_layout(TILEDB_ROW_MAJOR); + write_query.set_layout(TILEDB_ROW_MAJOR); - if ( _num_attributes == 1 ) { - write_image_metadata(array); - std::vector subarray = {1, _img_height, 0, _img_width - 1}; - write_query.set_subarray(subarray); - write_query.set_buffer(_attributes[0], _raw_data, _img_height * _img_width*_img_channels); + if (_num_attributes == 1) { + write_image_metadata(array); + std::vector subarray = {1, _img_height, 0, _img_width - 1}; + write_query.set_subarray(subarray); + write_query.set_data_buffer(_attributes[0], _raw_data, + _img_height * _img_width * _img_channels); + } else { + size_t buffer_size = _img_height * _img_width; + unsigned char *blue_buffer = new unsigned char[buffer_size]; + unsigned char *green_buffer = new unsigned char[buffer_size]; + unsigned char *red_buffer = new unsigned char[buffer_size]; + + int count = 0; + for (unsigned int i = 0; i < buffer_size; ++i) { + blue_buffer[i] = _raw_data[count]; + green_buffer[i] = _raw_data[count + 1]; + red_buffer[i] = _raw_data[count + 2]; } - else { - size_t buffer_size = _img_height*_img_width; - unsigned char* blue_buffer = new unsigned char[buffer_size]; - unsigned char* green_buffer = new unsigned char[buffer_size]; - unsigned char* red_buffer = new unsigned char[buffer_size]; - - int count = 0; - for ( int i = 0; i < buffer_size; ++i ) { - blue_buffer[i] = _raw_data[count]; - green_buffer[i] = _raw_data[count + 1]; - red_buffer[i] = _raw_data[count + 2]; - } - - write_query.set_buffer(_attributes[0], blue_buffer, buffer_size); - write_query.set_buffer(_attributes[1], green_buffer, buffer_size); - write_query.set_buffer(_attributes[2], red_buffer, buffer_size); + write_query.set_data_buffer(_attributes[0], blue_buffer, buffer_size); + write_query.set_data_buffer(_attributes[1], green_buffer, buffer_size); + write_query.set_data_buffer(_attributes[2], red_buffer, buffer_size); + } + + write_query.submit(); + write_query.finalize(); + array.close(); +} + +void TDBImage::write(const cv::Mat &cv_img, bool metadata) { + if (_group == "") + throw VCLException(ObjectNotFound, "Object path is not defined"); + if (_name == "") + throw VCLException(ObjectNotFound, "Object name is not defined"); + + std::string array_name = _group + _name; + if (tiledb::Object::object(_ctx, array_name).type() != + tiledb::Object::Type::Invalid) + tiledb::Object::remove(_ctx, array_name); + + set_dimension_lowerbounds(std::vector{0, 0}); + set_dimension_upperbounds(std::vector{(uint64_t)(cv_img.rows + 1), + (uint64_t)(cv_img.cols)}); + + _img_height = cv_img.rows; + _img_width = cv_img.cols; + _img_channels = cv_img.channels(); + _img_size = _img_height * _img_width * _img_channels; + + std::vector num_values; + if (_num_attributes == 1 && _img_channels == 3) + num_values.push_back(3); + else + num_values.push_back(1); + set_schema_dense(array_name, num_values); + + tiledb::Array array(_ctx, array_name, TILEDB_WRITE); + + write_image_metadata(array); + + tiledb::Query write_query(_ctx, array); + write_query.set_layout(TILEDB_ROW_MAJOR); + + std::vector subarray = {1, _img_height, 0, _img_width - 1}; + write_query.set_subarray(subarray); + + size_t buffer_size = _img_height * _img_width * _img_channels; + _raw_data = new unsigned char[buffer_size]; + + if (_num_attributes == 1) { + std::memcpy(_raw_data, cv_img.data, buffer_size); + write_query.set_data_buffer(_attributes[0], _raw_data, buffer_size); + } else { + std::vector channels(3); + cv::split(cv_img, channels); + size_t size = _img_height * _img_width; + unsigned char *blue_buffer = new unsigned char[size]; + unsigned char *green_buffer = new unsigned char[size]; + unsigned char *red_buffer = new unsigned char[size]; + + const unsigned char *bp; + for (unsigned int i = 0; i < _img_height; ++i) { + bp = channels[0].ptr(i); + unsigned char *b = &blue_buffer[i * _img_width]; + std::memcpy(b, bp, _img_width); + } + + const unsigned char *gp; + for (int i = 0; i < _img_height; ++i) { + gp = channels[1].ptr(i); + unsigned char *g = &green_buffer[i * _img_width]; + std::memcpy(g, gp, _img_width); } - write_query.submit(); - write_query.finalize(); - array.close(); + const unsigned char *rp; + for (unsigned int i = 0; i < _img_height; ++i) { + rp = channels[2].ptr(i); + unsigned char *r = &red_buffer[i * _img_width]; + std::memcpy(r, rp, _img_width); + } + write_query.set_data_buffer(_attributes[0], blue_buffer, buffer_size); + write_query.set_data_buffer(_attributes[1], green_buffer, buffer_size); + write_query.set_data_buffer(_attributes[2], red_buffer, buffer_size); + + delete[] blue_buffer; + delete[] green_buffer; + delete[] red_buffer; + } + + write_query.submit(); + write_query.finalize(); + array.close(); } +void TDBImage::read() { + if (_raw_data == NULL) { + if (_img_height == 0) + read_image_metadata(); -void TDBImage::write(const cv::Mat &cv_img, bool metadata) -{ - if ( _group == "" ) - throw VCLException(ObjectNotFound, "Object path is not defined"); - if ( _name == "" ) - throw VCLException(ObjectNotFound, "Object name is not defined"); + // {start row, end row, start col, end col} + std::vector subarray = {1, _img_height, 0, _img_width - 1}; + read_from_tdb(subarray); + } +} + +void TDBImage::read(const Rectangle &rect) { + if (_raw_data == NULL) { - std::string array_name = _group + _name; - if ( tiledb::Object::object(_ctx, array_name).type() != tiledb::Object::Type::Invalid) - tiledb::Object::remove(_ctx, array_name); + if (_img_height == 0) + read_image_metadata(); - set_dimension_lowerbounds(std::vector{0, 0}); - set_dimension_upperbounds(std::vector{(uint64_t)(cv_img.rows + 1), - (uint64_t)(cv_img.cols)}); + if (_img_height < rect.height + rect.y || _img_width < rect.width + rect.x) + throw VCLException(SizeMismatch, + "Requested area is not within the image"); - _img_height = cv_img.rows; - _img_width = cv_img.cols; - _img_channels = cv_img.channels(); + _img_height = rect.height; + _img_width = rect.width; _img_size = _img_height * _img_width * _img_channels; - std::vector num_values; - if ( _num_attributes == 1 && _img_channels == 3) - num_values.push_back(3); - else - num_values.push_back(1); - set_schema_dense(array_name, num_values); + std::vector subarray; - tiledb::Array array(_ctx, array_name, TILEDB_WRITE); + subarray.push_back(rect.x); // start row + subarray.push_back(rect.x + rect.height); // end row + subarray.push_back(rect.y); // start column + subarray.push_back(rect.y + rect.width); // end column - write_image_metadata(array); + read_from_tdb(subarray); + } +} - tiledb::Query write_query(_ctx, array); - write_query.set_layout(TILEDB_ROW_MAJOR); +void TDBImage::resize(const Rectangle &rect) { + if (_raw_data == NULL) + read(); - std::vector subarray = {1, _img_height, 0, _img_width - 1}; - write_query.set_subarray(subarray); + int r, c; - size_t buffer_size = _img_height * _img_width * _img_channels; - _raw_data = new unsigned char[buffer_size]; + int data_index = 0; + unsigned char *image_buffer = + new unsigned char[rect.height * rect.width * _img_channels]; + memset(image_buffer, 0, rect.height * rect.width * _img_channels); - if ( _num_attributes == 1 ) { - std::memcpy(_raw_data, cv_img.data, buffer_size); - write_query.set_buffer(_attributes[0], _raw_data, buffer_size); - } - else { - std::vector channels(3); - cv::split(cv_img, channels); - size_t size = _img_height * _img_width; - unsigned char* blue_buffer = new unsigned char[size]; - unsigned char* green_buffer = new unsigned char[size]; - unsigned char* red_buffer = new unsigned char[size]; - - const unsigned char* bp; - for ( int i = 0; i < _img_height; ++i ) { - bp = channels[0].ptr(i); - unsigned char* b = &blue_buffer[i * _img_width]; - std::memcpy(b, bp, _img_width); - } - - const unsigned char* gp; - for ( int i = 0; i < _img_height; ++i ) { - gp = channels[1].ptr(i); - unsigned char* g = &green_buffer[i * _img_width]; - std::memcpy(g, gp, _img_width); - } - - const unsigned char* rp; - for ( int i = 0; i < _img_height; ++i ) { - rp = channels[2].ptr(i); - unsigned char* r = &red_buffer[i * _img_width]; - std::memcpy(r, rp, _img_width); - } - - write_query.set_buffer(_attributes[0], blue_buffer, buffer_size); - write_query.set_buffer(_attributes[1], green_buffer, buffer_size); - write_query.set_buffer(_attributes[2], red_buffer, buffer_size); - - delete [] blue_buffer; - delete [] green_buffer; - delete [] red_buffer; - } - - write_query.submit(); - write_query.finalize(); - array.close(); -} + float row_ratio = _img_height / float(rect.height); + float column_ratio = _img_width / float(rect.width); -void TDBImage::read() -{ - if ( _raw_data == NULL ) - { - if ( _img_height == 0 ) - read_image_metadata(); + for (r = 0; r < rect.height; ++r) { + float scale_r = (r + 0.5) * row_ratio - 0.5; - // {start row, end row, start col, end col} - std::vector subarray = {1, _img_height, 0, _img_width - 1}; - read_from_tdb(subarray); - } -} + for (c = 0; c < rect.width; ++c) { + float scale_c = (c + 0.5) * column_ratio - 0.5; -void TDBImage::read(const Rectangle &rect) -{ - if (_raw_data == NULL) { + data_index = rect.width * r * _img_channels + c * _img_channels; - if ( _img_height == 0 ) - read_image_metadata(); + get_index_value(image_buffer, data_index, scale_r, scale_c); + } + } - if ( _img_height < rect.height + rect.y || _img_width < rect.width + rect.x ) - throw VCLException(SizeMismatch, "Requested area is not within the image"); + _img_height = rect.height; + _img_width = rect.width; + _img_size = _img_height * _img_width * _img_channels; + std::vector values = {_img_height + 1, _img_width}; + set_dimension_upperbounds(values); - _img_height = rect.height; - _img_width = rect.width; - _img_size = _img_height * _img_width * _img_channels; + _raw_data = new unsigned char[_img_size]; + std::memcpy(_raw_data, image_buffer, _img_size); - std::vector subarray; + delete[] image_buffer; +} - subarray.push_back(rect.x); // start row - subarray.push_back(rect.x + rect.height); // end row - subarray.push_back(rect.y); // start column - subarray.push_back(rect.y + rect.width); //end column +void TDBImage::threshold(int value) { + if (_raw_data == NULL) { + _threshold = value; + read(); + } else { + int length = _img_height * _img_width * _img_channels; - read_from_tdb(subarray); + for (int i = 0; i < length; ++i) { + if (_raw_data[i] <= value) + _raw_data[i] = 0; } + } } -void TDBImage::resize(const Rectangle &rect) -{ - if ( _raw_data == NULL ) - read(); - - int r, c; +bool TDBImage::has_data() { + if (_raw_data == NULL) + return false; + else + return true; +} - int data_index = 0; - unsigned char* image_buffer = new unsigned char[rect.height * rect.width * _img_channels]; - memset(image_buffer, 0, rect.height * rect.width * _img_channels); +void TDBImage::delete_image() { + delete _raw_data; + _raw_data = NULL; + delete_object(); +} - float row_ratio = _img_height / float(rect.height); - float column_ratio = _img_width / float(rect.width); +/* *********************** */ +/* PRIVATE GET FUNCTIONS */ +/* *********************** */ +void TDBImage::get_tile_coordinates(int64_t *subarray, int current_row_tile, + int current_column_tile) { + int row_start = current_row_tile * _tile_dimension[0]; + int column_start = current_column_tile * _tile_dimension[1]; + int row_end = row_start + _tile_dimension[0]; + int column_end = column_start + _tile_dimension[1]; - for ( r = 0; r < rect.height; ++r ) { - float scale_r = ( r + 0.5 ) * row_ratio - 0.5; + if (row_end > _img_height) + row_end = (_img_height - row_start) + row_start; - for ( c = 0; c < rect.width; ++c ) { - float scale_c = ( c + 0.5 ) * column_ratio - 0.5; + if (column_end > _img_width) + column_end = (_img_width - column_start) + column_start; - data_index = rect.width * r * _img_channels + c * _img_channels; + subarray[0] = row_start; + subarray[1] = row_end; + subarray[2] = column_start; + subarray[3] = column_end; +} - get_index_value(image_buffer, data_index, scale_r, scale_c); - } - } +void TDBImage::get_index_value(unsigned char *image_buffer, int index, + float scale_r, float scale_c) { + int column_left = floor(scale_c); + int column_right = floor(scale_c + 1); + int row_top = floor(scale_r); + int row_bottom = floor(scale_r + 1); - _img_height = rect.height; - _img_width = rect.width; - _img_size = _img_height * _img_width * _img_channels; - std::vector values = {_img_height + 1, _img_width}; - set_dimension_upperbounds(values); + if (column_left < 0) + column_left = 0; + if (column_right > _img_width - 1) + column_right = _img_width - 1; - _raw_data = new unsigned char[_img_size]; - std::memcpy(_raw_data, image_buffer, _img_size); + if (row_top < 0) + row_top = 0; + if (row_bottom > _img_height - 1) + row_bottom = _img_height - 1; - delete [] image_buffer; -} + long top_left_index = get_index(row_top, column_left) * _img_channels; + long top_right_index = get_index(row_top, column_right) * _img_channels; + long bottom_left_index = get_index(row_bottom, column_left) * _img_channels; + long bottom_right_index = get_index(row_bottom, column_right) * _img_channels; -void TDBImage::threshold(int value) -{ - if ( _raw_data == NULL ) { - _threshold = value; - read(); - } - else { - int length = _img_height * _img_width * _img_channels; + for (int x = 0; x < _img_channels; ++x) { + unsigned char top_left = _raw_data[top_left_index + x]; + unsigned char top_right = _raw_data[top_right_index + x]; + unsigned char bottom_left = _raw_data[bottom_left_index + x]; + unsigned char bottom_right = _raw_data[bottom_right_index + x]; - for ( int i = 0; i < length; ++i ) { - if ( _raw_data[i] <= value ) - _raw_data[i] = 0; - } - } -} + double top = linear_interpolation(column_left, top_left, column_right, + top_right, scale_c); + double bottom = linear_interpolation(column_left, bottom_left, column_right, + bottom_right, scale_c); + double middle = + linear_interpolation(row_top, top, row_bottom, bottom, scale_r); -bool TDBImage::has_data() -{ - if ( _raw_data == NULL ) - return false; - else - return true; -} - -void TDBImage::delete_image() -{ - delete _raw_data; - _raw_data = NULL; - delete_object(); -} - - /* *********************** */ - /* PRIVATE GET FUNCTIONS */ - /* *********************** */ -void TDBImage::get_tile_coordinates(int64_t* subarray, int current_row_tile, int current_column_tile) -{ - int row_start = current_row_tile * _tile_dimension[0]; - int column_start = current_column_tile * _tile_dimension[1]; - int row_end = row_start + _tile_dimension[0]; - int column_end = column_start + _tile_dimension[1]; - - if (row_end > _img_height) - row_end = (_img_height - row_start) + row_start; - - if (column_end > _img_width) - column_end = (_img_width - column_start) + column_start; - - subarray[0] = row_start; - subarray[1] = row_end; - subarray[2] = column_start; - subarray[3] = column_end; -} - -void TDBImage::get_index_value(unsigned char* image_buffer, int index, - float scale_r, float scale_c) -{ - int column_left = floor(scale_c); - int column_right = floor(scale_c + 1); - int row_top = floor(scale_r); - int row_bottom = floor(scale_r + 1); - - if ( column_left < 0 ) - column_left = 0; - if ( column_right > _img_width - 1 ) - column_right = _img_width - 1; - - if ( row_top < 0 ) - row_top = 0; - if ( row_bottom > _img_height - 1 ) - row_bottom = _img_height - 1; - - long top_left_index = get_index(row_top, column_left) * _img_channels; - long top_right_index = get_index(row_top, column_right) * _img_channels; - long bottom_left_index = get_index(row_bottom, column_left) * _img_channels; - long bottom_right_index = get_index(row_bottom, column_right) * _img_channels; - - for ( int x = 0; x < _img_channels; ++x ) { - unsigned char top_left = _raw_data[top_left_index + x]; - unsigned char top_right = _raw_data[top_right_index + x]; - unsigned char bottom_left = _raw_data[bottom_left_index + x]; - unsigned char bottom_right = _raw_data[bottom_right_index + x]; - - double top = linear_interpolation(column_left, top_left, column_right, top_right, scale_c); - double bottom = linear_interpolation(column_left, bottom_left, column_right, bottom_right, scale_c); - double middle = linear_interpolation(row_top, top, row_bottom, bottom, scale_r); - - // we want the middle of the pixel - unsigned char pixel_value = floor(middle + 0.5); - image_buffer[ index + x ] = pixel_value; - } + // we want the middle of the pixel + unsigned char pixel_value = floor(middle + 0.5); + image_buffer[index + x] = pixel_value; + } } -long TDBImage::get_index(int row, int column) const -{ - int tile_width = get_tile_width(column, _img_width / _tile_dimension[1]); - int tile_height = get_tile_height(row, _img_height / _tile_dimension[0]); +long TDBImage::get_index(int row, int column) const { + int tile_width = get_tile_width(column, _img_width / _tile_dimension[1]); + int tile_height = get_tile_height(row, _img_height / _tile_dimension[0]); - long tile_size = tile_width * tile_height; + long tile_size = tile_width * tile_height; - long current_tile_row = row % long(_tile_dimension[0]); - long current_row_tile = row / long(_tile_dimension[0]); - long current_column_tile = column / long(_tile_dimension[1]); - long current_tile_column = column % long(_tile_dimension[1]); + long current_tile_row = row % long(_tile_dimension[0]); + long current_row_tile = row / long(_tile_dimension[0]); + long current_column_tile = column / long(_tile_dimension[1]); + long current_tile_column = column % long(_tile_dimension[1]); - long full_row_tile = _img_width * _tile_dimension[0]; + long full_row_tile = _img_width * _tile_dimension[0]; - long row_index = current_row_tile * full_row_tile + current_tile_row * tile_width; - long column_index = current_column_tile * tile_size + current_tile_column; + long row_index = + current_row_tile * full_row_tile + current_tile_row * tile_width; + long column_index = current_column_tile * tile_size + current_tile_column; - return row_index + column_index; + return row_index + column_index; } -int TDBImage::get_tile_height(int row, int number_tiles) const -{ - int tile_height = int(_tile_dimension[0]); +int TDBImage::get_tile_height(int row, int number_tiles) const { + int tile_height = int(_tile_dimension[0]); - if ( row / _tile_dimension[0] == number_tiles ) - tile_height = _img_height - (number_tiles) * _tile_dimension[0]; + if (row / _tile_dimension[0] == (unsigned int)number_tiles) + tile_height = _img_height - (number_tiles)*_tile_dimension[0]; - return tile_height; + return tile_height; } -int TDBImage::get_tile_width(int column, int number_tiles) const -{ - int tile_width = int(_tile_dimension[1]); +int TDBImage::get_tile_width(int column, int number_tiles) const { + int tile_width = int(_tile_dimension[1]); - if ( column / _tile_dimension[1] == number_tiles ) - tile_width = _img_width - (number_tiles) * _tile_dimension[1]; + if (column / _tile_dimension[1] == (unsigned int)number_tiles) + tile_width = _img_width - (number_tiles)*_tile_dimension[1]; - return tile_width; + return tile_width; } - - /* *********************** */ - /* PRIVATE SET FUNCTIONS */ - /* *********************** */ -void TDBImage::set_default_dimensions() -{ - _dimension_names.push_back("height"); - _dimension_names.push_back("width"); +/* *********************** */ +/* PRIVATE SET FUNCTIONS */ +/* *********************** */ +void TDBImage::set_default_dimensions() { + _dimension_names.push_back("height"); + _dimension_names.push_back("width"); } -void TDBImage::set_default_attributes() -{ - _attributes.clear(); - switch (_num_attributes) { - case 1: { - _attributes.push_back("pixel"); - break; - } - case 3: { - _attributes.push_back("blue"); - _attributes.push_back("green"); - _attributes.push_back("red"); - break; - } - } +void TDBImage::set_default_attributes() { + _attributes.clear(); + switch (_num_attributes) { + case 1: { + _attributes.push_back("pixel"); + break; + } + case 3: { + _attributes.push_back("blue"); + _attributes.push_back("green"); + _attributes.push_back("red"); + break; + } + } } +/* *********************** */ +/* TDBIMAGE SETUP */ +/* *********************** */ +std::string TDBImage::namespace_setup(const std::string &image_id) { + size_t pos = get_path_delimiter(image_id); - /* *********************** */ - /* TDBIMAGE SETUP */ - /* *********************** */ -std::string TDBImage::namespace_setup(const std::string &image_id) -{ - size_t pos = get_path_delimiter(image_id); - - _group = get_group(image_id, pos); - _name = get_name(image_id, pos); + _group = get_group(image_id, pos); + _name = get_name(image_id, pos); - return _group + _name; + return _group + _name; } - /* *********************** */ - /* METADATA INTERACTION */ - /* *********************** */ -void TDBImage::write_image_metadata(tiledb::Array &array) -{ - std::vector metadata; +/* *********************** */ +/* METADATA INTERACTION */ +/* *********************** */ +void TDBImage::write_image_metadata(tiledb::Array &array) { + std::vector metadata; - metadata.emplace_back((unsigned char)_img_channels / MAX_UCHAR); - metadata.emplace_back((unsigned char)_img_channels % MAX_UCHAR); - metadata.emplace_back((unsigned char)(_img_height / MAX_UCHAR)); - metadata.emplace_back((unsigned char)(_img_height % MAX_UCHAR)); - metadata.emplace_back((unsigned char)(_img_width / MAX_UCHAR)); - metadata.emplace_back((unsigned char)(_img_width % MAX_UCHAR)); + metadata.emplace_back((unsigned char)_img_channels / MAX_UCHAR); + metadata.emplace_back((unsigned char)_img_channels % MAX_UCHAR); + metadata.emplace_back((unsigned char)(_img_height / MAX_UCHAR)); + metadata.emplace_back((unsigned char)(_img_height % MAX_UCHAR)); + metadata.emplace_back((unsigned char)(_img_width / MAX_UCHAR)); + metadata.emplace_back((unsigned char)(_img_width % MAX_UCHAR)); - std::vector subarray = {0, 0, 0, 1}; + std::vector subarray = {0, 0, 0, 1}; - tiledb::Query md_write(_ctx, array); - md_write.set_subarray(subarray); - md_write.set_layout(TILEDB_ROW_MAJOR); - md_write.set_buffer(_attributes[_num_attributes - 1], metadata); + tiledb::Query md_write(_ctx, array); + md_write.set_subarray(subarray); + md_write.set_layout(TILEDB_ROW_MAJOR); + md_write.set_data_buffer(_attributes[_num_attributes - 1], metadata); - md_write.submit(); + md_write.submit(); } -void TDBImage::read_image_metadata() -{ - std::vector metadata(3); +void TDBImage::read_image_metadata() { + std::vector metadata(3); - std::string md_name = _group + _name; - std::vector subarray = {0, 0, 0, 1}; - std::string attr = _attributes[_num_attributes - 1]; - read_metadata(md_name, subarray, metadata, attr); + std::string md_name = _group + _name; + std::vector subarray = {0, 0, 0, 1}; + std::string attr = _attributes[_num_attributes - 1]; + read_metadata(md_name, subarray, metadata, attr); - _img_height = metadata[1]; - _img_width = metadata[2]; - _img_channels = metadata[0]; + _img_height = metadata[1]; + _img_width = metadata[2]; + _img_channels = metadata[0]; - _img_size = _img_height * _img_width * _img_channels; + _img_size = _img_height * _img_width * _img_channels; - set_dimension_lowerbounds(std::vector{0, 0}); - set_dimension_upperbounds(std::vector{(_img_height + 1), - (_img_width)}); + set_dimension_lowerbounds(std::vector{0, 0}); + set_dimension_upperbounds( + std::vector{(_img_height + 1), (_img_width)}); } +/* *********************** */ +/* DATA MANIPULATION */ +/* *********************** */ +void TDBImage::read_from_tdb(std::vector subarray) { + std::string array_name = _group + _name; - /* *********************** */ - /* DATA MANIPULATION */ - /* *********************** */ -void TDBImage::read_from_tdb(std::vector subarray) -{ - std::string array_name = _group + _name; - - set_from_schema(array_name); + set_from_schema(array_name); - tiledb::Array array(_ctx, array_name, TILEDB_READ); + tiledb::Array array(_ctx, array_name, TILEDB_READ); - tiledb::Query read_query(_ctx, array, TILEDB_READ); - read_query.set_layout(TILEDB_ROW_MAJOR); - read_query.set_subarray(subarray); + tiledb::Query read_query(_ctx, array, TILEDB_READ); + read_query.set_layout(TILEDB_ROW_MAJOR); + read_query.set_subarray(subarray); - if ( _num_attributes == 1 ) { - int buffer_size = _img_height * _img_width * _img_channels; - _raw_data = new unsigned char[buffer_size]; + if (_num_attributes == 1) { + int buffer_size = _img_height * _img_width * _img_channels; + _raw_data = new unsigned char[buffer_size]; - read_query.set_buffer(_attributes[0], _raw_data, buffer_size); - read_query.submit(); + read_query.set_data_buffer(_attributes[0], _raw_data, buffer_size); + read_query.submit(); + } + + else { + int buffer_size = _img_height * _img_width; + _raw_data = new unsigned char[buffer_size * _img_channels]; + unsigned char *blue_buffer = new unsigned char[buffer_size]; + unsigned char *green_buffer = new unsigned char[buffer_size]; + unsigned char *red_buffer = new unsigned char[buffer_size]; + + read_query.set_data_buffer(_attributes[0], blue_buffer, buffer_size); + read_query.set_data_buffer(_attributes[1], green_buffer, buffer_size); + read_query.set_data_buffer(_attributes[2], red_buffer, buffer_size); + + read_query.submit(); + + int count = 0; + for (int i = 0; i < buffer_size; ++i) { + _raw_data[count] = blue_buffer[i]; + _raw_data[count + 1] = green_buffer[i]; + _raw_data[count + 2] = red_buffer[i]; + count += 3; } - else { - int buffer_size = _img_height * _img_width; - _raw_data = new unsigned char[buffer_size * _img_channels]; - unsigned char* blue_buffer = new unsigned char[buffer_size]; - unsigned char* green_buffer = new unsigned char[buffer_size]; - unsigned char* red_buffer = new unsigned char[buffer_size]; - - read_query.set_buffer(_attributes[0], blue_buffer, buffer_size); - read_query.set_buffer(_attributes[1], green_buffer, buffer_size); - read_query.set_buffer(_attributes[2], red_buffer, buffer_size); - - read_query.submit(); - - int count = 0; - for (int i = 0; i < buffer_size; ++i) { - _raw_data[count] = blue_buffer[i]; - _raw_data[count + 1] = green_buffer[i]; - _raw_data[count + 2] = red_buffer[i]; - count += 3; - } - - delete [] blue_buffer; - delete [] green_buffer; - delete [] red_buffer; - } + delete[] blue_buffer; + delete[] green_buffer; + delete[] red_buffer; + } - array.close(); + array.close(); } - /* *********************** */ - /* MATH FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* MATH FUNCTIONS */ +/* *********************** */ double TDBImage::linear_interpolation(double x1, double val1, double x2, - double val2, double x) -{ + double val2, double x) { - if ( x1 == x2 ) - return val1; + if (x1 == x2) + return val1; - double value = val2 - val1; - double multiply = x - x1; - double divide = x2 - x1; + double value = val2 - val1; + double multiply = x - x1; + double divide = x2 - x1; - return val1 + (value/divide * multiply); + return val1 + (value / divide * multiply); } diff --git a/src/vcl/TDBImage.h b/src/vcl/TDBImage.h index 38c65f6f..1433b74a 100644 --- a/src/vcl/TDBImage.h +++ b/src/vcl/TDBImage.h @@ -34,357 +34,352 @@ #include +#include "TDBObject.h" #include "vcl/Exception.h" #include -#include "TDBObject.h" namespace VCL { - /** - * Uses the OpenCV Rect class to define an area in the image - * (starting x coordinate, starting y coordinate, height, width) - */ - typedef cv::Rect Rectangle; - - class TDBImage : public TDBObject { - - /* *********************** */ - /* VARIABLES */ - /* *********************** */ - private: - // Image dimensions - uint64_t _img_height, _img_width, _img_channels; - long _img_size; - - // threshold value - int _threshold; - - // raw data of the image - unsigned char* _raw_data; - std::vector _full_array; - - public: - /* *********************** */ - /* CONSTRUCTORS */ - /* *********************** */ - /** - * Creates a empty TDBImage - */ - TDBImage(); - - /** - * Creates a TDBImage from an object id - * - * @param image_id The path of the TDBImage - */ - TDBImage(const std::string &image_id); - - /** - * Creates a TDBImage from a buffer of raw data - * - * @param buffer The raw pixel data - * @param size The length of the buffer - */ - template TDBImage(T* buffer, long size); - - /** - * Creates a TDBImage object from an existing TDBImage - * - * @param tdb A reference to an existing TDBImage - */ - TDBImage(TDBImage &tdb); - - /** - * Sets a TDBImage object equal to another TDBImage - * - * @param tdb A reference to an existing TDBImage - */ - void operator=(TDBImage &tdb); - - - ~TDBImage(); - - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ - /** - * Gets the size of the image - * - * @return The size of the image (height x width x channels) - */ - long get_image_size(); - - /** - * Gets the height of the image (number of rows) - * - * @return The height of the image - */ - int get_image_height(); - - /** - * Gets the width of the image (number of columns) - * - * @return The width of the image - */ - int get_image_width(); - - /** - * Gets the number of channels in the image. A color image has - * three channels (green, blue, red), a black and white image - * has one - * - * @return The number of channels - */ - int get_image_channels(); - - /** - * Gets an OpenCV Mat that contains the image data - * - * @return An OpenCV Mat - */ - cv::Mat get_cvmat(); - - /** - * Gets the raw data from the TDBImage - * - * @param buffer A buffer (of any type) that will contain the raw - * data when the function ends - * @param buffer_size The length of buffer (not in bytes) - */ - template void get_buffer(T* buffer, long buffer_size); - - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ - /** - * Sets the height (number of rows), width (number of columns), and - * number of channels in the image. Used when the metadata is not - * stored in TileDB - * - * @param height Height of the image - * @param width Width of the image - * @param channels Number of channels in the image - */ - void set_image_properties(int height, int width, int channels); - - - /* *********************** */ - /* TDBIMAGE INTERACTION */ - /* *********************** */ - /** - * Writes the raw data in the TDBImage to the given object id - * - * @param image_id The object id where the data is to be written - * @param metadata A flag indicating whether the metadata - * should be stored in TileDB or not. Defaults to true - */ - void write(const std::string &image_id, bool metadata = true); - - /** - * Writes the data in the OpenCV Mat to a location specified - * by the existing TDBImage path variables - * - * @param cv_img The OpenCV Mat containing the image data - * @param metadata A flag indicating whether the metadata - * should be stored in TileDB or not. Defaults to true - */ - void write(const cv::Mat &cv_img, bool metadata = true); - - /** - * Reads the raw data from the location specified by the existing - * TDBImage path variables - */ - void read(); - - /** - * Reads a subset of the raw data from the location specified - * by the existing TDBImage path variables - * - * @param rect A Rectangle structure containing the coordinates - * and size of the subset of data to be read (starting x coordinate, - * starting y coordinate, height, width) - * @see Image.h for more details on Rectangle - */ - void read(const Rectangle &rect); - - /** - * Resizes the image to the height and width specified in - * the Rectangle using bilinear interpolation - * - * @param rect A Rectangle structure containing height and - * width to resize the image to - * @see Image.h for more details on Rectangle - */ - void resize(const Rectangle &rect); - - /** - * Sets pixel values less than or equal to the specified - * value to zero - * - * @param value The threshold under which pixel values should - * be set to zero - */ - void threshold(int value); - - /** - * Checks to see if the TDBImage is pointing to data - * - * @return True if there is data, false if there is not - */ - bool has_data(); - - /** - * Deletes the object from TileDB - * - * @param object_id The object id where the data is written - */ - void delete_image(); - - - - private: - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ - - /** - * Gets the coordinates in an array given the current tile - * - * @param subarray An array in which the coordinates will be stored - * @param current_column_tile The current column tile - * @param current_row_tile The current row tile - */ - void get_tile_coordinates(int64_t* subarray, int current_column_tile, - int current_row_tile); - - /** - * Used for resizing, gets the value of the calculated index - * - * @param image_buffer A buffer to store the resized image in - * @param index The current index into the image_buffer - * @param scale_r The row to be used to calculate the index into - * the raw data - * @param scale_c The column to be used to calculate the index into - * the raw data - */ - void get_index_value(unsigned char* image_buffer, int index, - float scale_r, float scale_c); - - /** - * Used for resizing, calculates the index in the raw data where the - * value found at [row, column] in the image can be found - * - * @param row The row index - * @param column The column index - * @return The index in the raw data where [row, column] is - */ - long get_index(int row, int column) const; - - /** - * Used for resizing, calculates the height of the current tile (used - * when the image height is not the same as the array height) - * - * @param row The row index - * @param number_tiles The number of row tiles in the image - * @return The height of the current tile - */ - int get_tile_height(int row, int number_tiles) const; - - /** - * Used for resizing, calculates the width of the current tile (used - * when the image width is not the same as the array width) - * - * @param column The column index - * @param number_tiles The number of column tiles in the image - * @return The width of the current tile - */ - int get_tile_width(int column, int number_tiles) const; - - - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ - /** - * Sets the names of the dimensions to the default of - * "height" and "width" - */ - void set_default_dimensions(); - - /** - * Sets the names of the attributes to the default of - * "pixel" if one attribute and "green", "blue", and - * "red" if two - */ - void set_default_attributes(); - - /** - * Sets the private members of one TDBImage object equal to - * another - * - * @param tdb Another TDBImage object - */ - void set_image_data_equal(const TDBImage &tdb); - - - /* *********************** */ - /* TDBIMAGE SETUP */ - /* *********************** */ - /** - * Determines the TileDB group and array name - * from the image id - * - * @param image_id The full path of the image or the full path of - * where to store the image - * @return The name of the TileDB array - */ - std::string namespace_setup(const std::string &image_id); - - - /* *********************** */ - /* METADATA INTERACTION */ - /* *********************** */ - - /** - * Writes the metadata of the TDBImage - * - * @param array The tiledb::Array to which data is being written - */ - void write_image_metadata(tiledb::Array &array); - - /** - * Reads the metadata at the existing TDBImage path variables - */ - void read_image_metadata(); - - - /* *********************** */ - /* DATA MANIPULATION */ - /* *********************** */ - - /** - * Reads the specified subarray from the array at the existing - * TDBImage path variables (can be the full array) - * - * @param subarray An array of the coordinates of the subarray - * to read - */ - void read_from_tdb(std::vector subarray); - - - /* *********************** */ - /* MATH FUNCTIONS */ - /* *********************** */ - /** - * Linearly interpolates two data points - * - * @param x1 The first reference point - * @param val1 The value at the first reference point - * @param x2 The second reference point - * @param val2 The value at the second reference point - * @param x The desired point - * @return The value at the desired point - */ - double linear_interpolation(double x1, double val1, double x2, - double val2, double x); - }; +/** + * Uses the OpenCV Rect class to define an area in the image + * (starting x coordinate, starting y coordinate, height, width) + */ +typedef cv::Rect Rectangle; + +class TDBImage : public TDBObject { + + /* *********************** */ + /* VARIABLES */ + /* *********************** */ +private: + // Image dimensions + uint64_t _img_height, _img_width, _img_channels; + long _img_size; + + // threshold value + int _threshold; + + // raw data of the image + unsigned char *_raw_data; + std::vector _full_array; + +public: + /* *********************** */ + /* CONSTRUCTORS */ + /* *********************** */ + /** + * Creates a empty TDBImage + */ + TDBImage(); + + /** + * Creates a TDBImage from an object id + * + * @param image_id The path of the TDBImage + */ + TDBImage(const std::string &image_id); + + TDBImage(const std::string &image_id, RemoteConnection &connection); + + /** + * Creates a TDBImage from a buffer of raw data + * + * @param buffer The raw pixel data + * @param size The length of the buffer + */ + template TDBImage(T *buffer, long size); + + /** + * Creates a TDBImage object from an existing TDBImage + * + * @param tdb A reference to an existing TDBImage + */ + TDBImage(TDBImage &tdb); + + /** + * Sets a TDBImage object equal to another TDBImage + * + * @param tdb A reference to an existing TDBImage + */ + void operator=(TDBImage &tdb); + + ~TDBImage(); + + /* *********************** */ + /* GET FUNCTIONS */ + /* *********************** */ + /** + * Gets the size of the image + * + * @return The size of the image (height x width x channels) + */ + long get_image_size(); + + /** + * Gets the height of the image (number of rows) + * + * @return The height of the image + */ + int get_image_height(); + + /** + * Gets the width of the image (number of columns) + * + * @return The width of the image + */ + int get_image_width(); + + /** + * Gets the number of channels in the image. A color image has + * three channels (green, blue, red), a black and white image + * has one + * + * @return The number of channels + */ + int get_image_channels(); + + /** + * Gets an OpenCV Mat that contains the image data + * + * @return An OpenCV Mat + */ + cv::Mat get_cvmat(); + + /** + * Gets the raw data from the TDBImage + * + * @param buffer A buffer (of any type) that will contain the raw + * data when the function ends + * @param buffer_size The length of buffer (not in bytes) + */ + template void get_buffer(T *buffer, long buffer_size); + + /* *********************** */ + /* SET FUNCTIONS */ + /* *********************** */ + /** + * Sets the height (number of rows), width (number of columns), and + * number of channels in the image. Used when the metadata is not + * stored in TileDB + * + * @param height Height of the image + * @param width Width of the image + * @param channels Number of channels in the image + */ + void set_image_properties(int height, int width, int channels); + + void set_configuration(RemoteConnection *remote); + + /* *********************** */ + /* TDBIMAGE INTERACTION */ + /* *********************** */ + /** + * Writes the raw data in the TDBImage to the given object id + * + * @param image_id The object id where the data is to be written + * @param metadata A flag indicating whether the metadata + * should be stored in TileDB or not. Defaults to true + */ + void write(const std::string &image_id, bool metadata = true); + + /** + * Writes the data in the OpenCV Mat to a location specified + * by the existing TDBImage path variables + * + * @param cv_img The OpenCV Mat containing the image data + * @param metadata A flag indicating whether the metadata + * should be stored in TileDB or not. Defaults to true + */ + void write(const cv::Mat &cv_img, bool metadata = true); + + /** + * Reads the raw data from the location specified by the existing + * TDBImage path variables + */ + void read(); + + /** + * Reads a subset of the raw data from the location specified + * by the existing TDBImage path variables + * + * @param rect A Rectangle structure containing the coordinates + * and size of the subset of data to be read (starting x coordinate, + * starting y coordinate, height, width) + * @see Image.h for more details on Rectangle + */ + void read(const Rectangle &rect); + + /** + * Resizes the image to the height and width specified in + * the Rectangle using bilinear interpolation + * + * @param rect A Rectangle structure containing height and + * width to resize the image to + * @see Image.h for more details on Rectangle + */ + void resize(const Rectangle &rect); + + /** + * Sets pixel values less than or equal to the specified + * value to zero + * + * @param value The threshold under which pixel values should + * be set to zero + */ + void threshold(int value); + + /** + * Checks to see if the TDBImage is pointing to data + * + * @return True if there is data, false if there is not + */ + bool has_data(); + + /** + * Deletes the object from TileDB + * + * @param object_id The object id where the data is written + */ + void delete_image(); + +private: + /* *********************** */ + /* GET FUNCTIONS */ + /* *********************** */ + + /** + * Gets the coordinates in an array given the current tile + * + * @param subarray An array in which the coordinates will be stored + * @param current_column_tile The current column tile + * @param current_row_tile The current row tile + */ + void get_tile_coordinates(int64_t *subarray, int current_column_tile, + int current_row_tile); + + /** + * Used for resizing, gets the value of the calculated index + * + * @param image_buffer A buffer to store the resized image in + * @param index The current index into the image_buffer + * @param scale_r The row to be used to calculate the index into + * the raw data + * @param scale_c The column to be used to calculate the index into + * the raw data + */ + void get_index_value(unsigned char *image_buffer, int index, float scale_r, + float scale_c); + + /** + * Used for resizing, calculates the index in the raw data where the + * value found at [row, column] in the image can be found + * + * @param row The row index + * @param column The column index + * @return The index in the raw data where [row, column] is + */ + long get_index(int row, int column) const; + + /** + * Used for resizing, calculates the height of the current tile (used + * when the image height is not the same as the array height) + * + * @param row The row index + * @param number_tiles The number of row tiles in the image + * @return The height of the current tile + */ + int get_tile_height(int row, int number_tiles) const; + + /** + * Used for resizing, calculates the width of the current tile (used + * when the image width is not the same as the array width) + * + * @param column The column index + * @param number_tiles The number of column tiles in the image + * @return The width of the current tile + */ + int get_tile_width(int column, int number_tiles) const; + + /* *********************** */ + /* SET FUNCTIONS */ + /* *********************** */ + /** + * Sets the names of the dimensions to the default of + * "height" and "width" + */ + void set_default_dimensions(); + + /** + * Sets the names of the attributes to the default of + * "pixel" if one attribute and "green", "blue", and + * "red" if two + */ + void set_default_attributes(); + + /** + * Sets the private members of one TDBImage object equal to + * another + * + * @param tdb Another TDBImage object + */ + void set_image_data_equal(const TDBImage &tdb); + + /* *********************** */ + /* TDBIMAGE SETUP */ + /* *********************** */ + /** + * Determines the TileDB group and array name + * from the image id + * + * @param image_id The full path of the image or the full path of + * where to store the image + * @return The name of the TileDB array + */ + std::string namespace_setup(const std::string &image_id); + + /* *********************** */ + /* METADATA INTERACTION */ + /* *********************** */ + + /** + * Writes the metadata of the TDBImage + * + * @param array The tiledb::Array to which data is being written + */ + void write_image_metadata(tiledb::Array &array); + + /** + * Reads the metadata at the existing TDBImage path variables + */ + void read_image_metadata(); + + /* *********************** */ + /* DATA MANIPULATION */ + /* *********************** */ + + /** + * Reads the specified subarray from the array at the existing + * TDBImage path variables (can be the full array) + * + * @param subarray An array of the coordinates of the subarray + * to read + */ + void read_from_tdb(std::vector subarray); + + /* *********************** */ + /* MATH FUNCTIONS */ + /* *********************** */ + /** + * Linearly interpolates two data points + * + * @param x1 The first reference point + * @param val1 The value at the first reference point + * @param x2 The second reference point + * @param val2 The value at the second reference point + * @param x The desired point + * @return The value at the desired point + */ + double linear_interpolation(double x1, double val1, double x2, double val2, + double x); }; +}; // namespace VCL diff --git a/src/vcl/TDBObject.cc b/src/vcl/TDBObject.cc index d75e1634..357840a8 100644 --- a/src/vcl/TDBObject.cc +++ b/src/vcl/TDBObject.cc @@ -27,553 +27,610 @@ * */ +#include +#include #include -#include #include +#include #include -#include -#include -#include "vcl/Exception.h" #include "TDBObject.h" +#include "vcl/Exception.h" using namespace VCL; #define UCHAR_MAX 256 - /* *********************** */ - /* CONSTRUCTORS */ - /* *********************** */ +/* *********************** */ +/* CONSTRUCTORS */ +/* *********************** */ -TDBObject::TDBObject() : - _config(NULL) -{ +TDBObject::TDBObject() : _config(NULL) { _num_dimensions = 0; _tile_capacity = 0; _group = ""; - _name = ""; - - // set default values - _num_attributes = 1; - const char* attr = "value"; - _attributes.push_back(attr); - _compressed = CompressionType::LZ4; - _min_tile_dimension = 4; - _extent = -1; + _name = ""; + + // set default values + _num_attributes = 1; + const char *attr = "value"; + _attributes.push_back(attr); + _compressed = CompressionType::LZ4; + _min_tile_dimension = 4; + _extent = -1; } -TDBObject::TDBObject(const std::string &object_id) : - _config(NULL) -{ +TDBObject::TDBObject(const std::string &object_id) : _config(NULL) { _num_dimensions = 0; _tile_capacity = 0; size_t pos = get_path_delimiter(object_id); - _group = get_group(object_id, pos); - _name = get_name(object_id, pos); + _group = get_group(object_id, pos); + _name = get_name(object_id, pos); - // set default values - _num_attributes = 1; - const char* attr = "value"; - _attributes.push_back(attr); - _compressed = CompressionType::LZ4; - _min_tile_dimension = 4; - _extent = -1; + // set default values + _num_attributes = 1; + const char *attr = "value"; + _attributes.push_back(attr); + _compressed = CompressionType::LZ4; + _min_tile_dimension = 4; + _extent = -1; } -TDBObject::TDBObject(const TDBObject &tdb) : - _config(NULL) -{ +TDBObject::TDBObject(const std::string &object_id, RemoteConnection &connection) + : _config(NULL) { + set_config(&connection); + + _num_dimensions = 0; + _tile_capacity = 0; + + size_t pos = get_path_delimiter(object_id); + + _group = get_group(object_id, pos); + _name = get_name(object_id, pos); + + // set default values + _num_attributes = 1; + const char *attr = "value"; + _attributes.push_back(attr); + _compressed = CompressionType::LZ4; + _min_tile_dimension = 4; + _extent = -1; +} + +TDBObject::TDBObject(const TDBObject &tdb) : _config(NULL) { _num_dimensions = 0; _tile_capacity = 0; _config = tdb._config; - _ctx = tdb._ctx; + _ctx = tdb._ctx; - set_equal(tdb); + set_equal(tdb); } -TDBObject& TDBObject::operator=(const TDBObject &tdb) -{ - _config = tdb._config; - _ctx = tdb._ctx; +TDBObject &TDBObject::operator=(const TDBObject &tdb) { + _config = tdb._config; + _ctx = tdb._ctx; - reset_arrays(); + reset_arrays(); - set_equal(tdb); + set_equal(tdb); - return *this; + return *this; } -void TDBObject::set_equal(const TDBObject &tdb) -{ - _group = tdb._group; +void TDBObject::set_equal(const TDBObject &tdb) { + _group = tdb._group; - _num_attributes = tdb._num_attributes; + _num_attributes = tdb._num_attributes; - _attributes.clear(); - _attributes = tdb._attributes; + _attributes.clear(); + _attributes = tdb._attributes; - _num_dimensions = tdb._num_dimensions; - _dimension_names.clear(); - _lower_dimensions.clear(); - _upper_dimensions.clear(); + _num_dimensions = tdb._num_dimensions; + _dimension_names.clear(); + _lower_dimensions.clear(); + _upper_dimensions.clear(); - _dimension_names = tdb._dimension_names; - _upper_dimensions = tdb._upper_dimensions; - _lower_dimensions = tdb._lower_dimensions; + _dimension_names = tdb._dimension_names; + _upper_dimensions = tdb._upper_dimensions; + _lower_dimensions = tdb._lower_dimensions; - _compressed = tdb._compressed; - _min_tile_dimension = tdb._min_tile_dimension; - _array_dimension = tdb._array_dimension; - _tile_dimension = tdb._tile_dimension; + _compressed = tdb._compressed; + _min_tile_dimension = tdb._min_tile_dimension; + _array_dimension = tdb._array_dimension; + _tile_dimension = tdb._tile_dimension; - _config = tdb._config; - _extent = tdb._extent; + _config = tdb._config; + _extent = tdb._extent; } -TDBObject::~TDBObject() -{ - reset_arrays(); -} +TDBObject::~TDBObject() { reset_arrays(); } -void TDBObject::reset_arrays() -{ - _attributes.clear(); - _attributes.shrink_to_fit(); - _dimension_names.clear(); - _dimension_names.shrink_to_fit(); - _lower_dimensions.clear(); - _upper_dimensions.clear(); - _lower_dimensions.shrink_to_fit(); - _upper_dimensions.shrink_to_fit(); +void TDBObject::reset_arrays() { + _attributes.clear(); + _attributes.shrink_to_fit(); + _dimension_names.clear(); + _dimension_names.shrink_to_fit(); + _lower_dimensions.clear(); + _upper_dimensions.clear(); + _lower_dimensions.shrink_to_fit(); + _upper_dimensions.shrink_to_fit(); } -void TDBObject::delete_object() -{ - std::string object_id = _group + _name; - - tiledb::Object::remove(_ctx, object_id); +void TDBObject::delete_object() { + std::string object_id = _group + _name; + tiledb::Object::remove(_ctx, object_id); } - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* GET FUNCTIONS */ +/* *********************** */ -std::string TDBObject::get_object_id() const -{ - return _group + _name; -} +std::string TDBObject::get_object_id() const { return _group + _name; } - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* SET FUNCTIONS */ +/* *********************** */ -void TDBObject::set_num_dimensions(int num) -{ - _num_dimensions = num; -} +void TDBObject::set_num_dimensions(int num) { _num_dimensions = num; } -void TDBObject::set_dimension_names(const std::vector &dimensions) -{ - _num_dimensions = dimensions.size(); - _dimension_names = dimensions; +void TDBObject::set_dimension_names( + const std::vector &dimensions) { + _num_dimensions = dimensions.size(); + _dimension_names = dimensions; } -void TDBObject::set_dimension_lowerbounds(const std::vector &dimensions) -{ - _lower_dimensions = dimensions; +void TDBObject::set_dimension_lowerbounds( + const std::vector &dimensions) { + _lower_dimensions = dimensions; } -void TDBObject::set_dimension_upperbounds(const std::vector &dimensions) -{ - _upper_dimensions = dimensions; +void TDBObject::set_dimension_upperbounds( + const std::vector &dimensions) { + _upper_dimensions = dimensions; } template void TDBObject::set_full_dimensions(const std::vector &names, - const std::vector &upper_dims, const std::vector &lower_dims, int extent) -{ - _num_dimensions = names.size(); - for (int i = 0; i < names.size(); ++i) { - auto dim = tiledb::Dimension::create(_ctx, names[i], {{lower_dims[i], upper_dims[i]}}, extent); - _full_dimensions.push_back(dim); - } -} -template void TDBObject::set_full_dimensions(const std::vector &names, - const std::vector &upper_dims, const std::vector &lower_dims, int extent); -template void TDBObject::set_full_dimensions(const std::vector &names, - const std::vector &upper_dims, const std::vector &lower_dims, int extent); - -void TDBObject::set_minimum(int dimension) -{ - _min_tile_dimension = dimension; + const std::vector &upper_dims, + const std::vector &lower_dims, + int extent) { + _num_dimensions = names.size(); + for (int i = 0; i < names.size(); ++i) { + auto dim = tiledb::Dimension::create( + _ctx, names[i], {{lower_dims[i], upper_dims[i]}}, extent); + _full_dimensions.push_back(dim); + } +} +template void +TDBObject::set_full_dimensions(const std::vector &names, + const std::vector &upper_dims, + const std::vector &lower_dims, + int extent); +template void TDBObject::set_full_dimensions( + const std::vector &names, const std::vector &upper_dims, + const std::vector &lower_dims, int extent); + +void TDBObject::set_minimum(int dimension) { _min_tile_dimension = dimension; } + +void TDBObject::set_num_attributes(int num) { _num_attributes = num; } + +void TDBObject::set_attributes(const std::vector &attributes) { + _attributes.clear(); + std::vector charArrays; + + // Convert string values to C-style strings and store in charArrays + for (auto x = 0; x < attributes.size(); ++x) { + char *charArray = + new char[attributes[x].length() + 1]; // +1 for null terminator + std::strcpy(charArray, attributes[x].c_str()); + charArrays.push_back(charArray); + } + + // Add the char arrays to _attributes vector + for (auto x = 0; x < charArrays.size(); ++x) { + _attributes.push_back(charArrays[x]); + } } -void TDBObject::set_num_attributes(int num) -{ - _num_attributes = num; -} - -void TDBObject::set_attributes(const std::vector &attributes) -{ - _attributes.clear(); +template +void TDBObject::set_single_attribute(std::string &attribute, + CompressionType compressor, + T cell_val_num) { - for (int x = 0; x < attributes.size(); ++x){ - _attributes.push_back(const_cast(attributes[x].c_str())); - } + tiledb::FilterList filter_list(_ctx); + tiledb::Filter filter = convert_to_tiledb(); + filter_list.add_filter(filter); + auto a = tiledb::Attribute::create(_ctx, attribute, filter_list); + a.set_cell_val_num((long)cell_val_num); + _full_attributes.push_back(a); } +template void TDBObject::set_single_attribute(std::string &attribute, + CompressionType compressor, + int cell_val_num); +template void TDBObject::set_single_attribute(std::string &attribute, + CompressionType compressor, + uint64_t cell_val_num); +template void TDBObject::set_single_attribute(std::string &attribute, + CompressionType compressor, + long cell_val_num); +template void TDBObject::set_single_attribute(std::string &attribute, + CompressionType compressor, + float cell_val_num); +template void TDBObject::set_single_attribute(std::string &attribute, + CompressionType compressor, + unsigned char cell_val_num); -template -void TDBObject::set_single_attribute(std::string &attribute, CompressionType compressor, T cell_val_num) -{ - _compressed = compressor; - auto a = tiledb::Attribute::create(_ctx, attribute, convert_to_tiledb()); - a.set_cell_val_num((long)cell_val_num); - _full_attributes.push_back(a); -} -template void TDBObject::set_single_attribute(std::string &attribute, CompressionType compressor, int cell_val_num); -template void TDBObject::set_single_attribute(std::string &attribute, CompressionType compressor, uint64_t cell_val_num); -template void TDBObject::set_single_attribute(std::string &attribute, CompressionType compressor, long cell_val_num); -template void TDBObject::set_single_attribute(std::string &attribute, CompressionType compressor, float cell_val_num); -template void TDBObject::set_single_attribute(std::string &attribute, CompressionType compressor, unsigned char cell_val_num); - -void TDBObject::set_compression(CompressionType comp) -{ - _compressed = comp; +void TDBObject::set_compression(CompressionType comp) { _compressed = comp; } + +void TDBObject::set_config(RemoteConnection *remote) { + // TODO: Implement this } - /* *********************** */ - /* PROTECTED GET FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* PROTECTED GET FUNCTIONS */ +/* *********************** */ -size_t TDBObject::get_path_delimiter(const std::string &filename) const -{ - std::string delimiter = "/"; +size_t TDBObject::get_path_delimiter(const std::string &filename) const { + std::string delimiter = "/"; - size_t pos = filename.rfind(delimiter); - if (pos == filename.length() - 1) { - std::string file = filename.substr(0, pos); - pos = file.rfind(delimiter); - } + size_t pos = filename.rfind(delimiter); + if (pos == filename.length() - 1) { + std::string file = filename.substr(0, pos); + pos = file.rfind(delimiter); + } - return pos; + return pos; } -std::string TDBObject::get_group(const std::string &filename, size_t pos) const -{ - std::string group = filename.substr(0, pos + 1); +std::string TDBObject::get_group(const std::string &filename, + size_t pos) const { + std::string group = filename.substr(0, pos + 1); - if ( tiledb::Object::object(_ctx, group).type() != tiledb::Object::Type::Group ) { - tiledb::create_group(_ctx, group); - } + if (tiledb::Object::object(_ctx, group).type() != + tiledb::Object::Type::Group) { + tiledb::create_group(_ctx, group); + } - return group; + return group; } -std::string TDBObject::get_name(const std::string &filename, size_t pos) const -{ - std::string id = filename.substr(pos + 1); - return id; +std::string TDBObject::get_name(const std::string &filename, size_t pos) const { + std::string id = filename.substr(pos + 1); + return id; } - /* *********************** */ - /* PROTECTED SET FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* PROTECTED SET FUNCTIONS */ +/* *********************** */ template -void TDBObject::set_schema_attributes(tiledb::ArraySchema& array_schema, std::vector &cell_val_num) -{ - if (_full_attributes.empty()) { - for (int x = 0; x < _attributes.size(); ++x) { - auto compressor = convert_to_tiledb(); - auto attr = tiledb::Attribute::create(_ctx, _attributes[x], compressor); - attr.set_cell_val_num(cell_val_num[x]); - array_schema.add_attribute(attr); - } - } - else { - for (int x = 0; x < _full_attributes.size(); ++x) { - array_schema.add_attribute(_full_attributes[x]); - } +void TDBObject::set_schema_attributes(tiledb::ArraySchema &array_schema, + std::vector &cell_val_num) { + if (_full_attributes.empty()) { + for (int x = 0; x < _attributes.size(); ++x) { + tiledb::FilterList filter_list(_ctx); + filter_list.add_filter(convert_to_tiledb()); + + auto attr = + tiledb::Attribute::create(_ctx, _attributes[x], filter_list); + attr.set_cell_val_num(cell_val_num[x]); + array_schema.add_attribute(attr); } -} -template void TDBObject::set_schema_attributes(tiledb::ArraySchema& array_schema, std::vector &cell_val_num); -template void TDBObject::set_schema_attributes(tiledb::ArraySchema& array_schema, std::vector &cell_val_num); -template void TDBObject::set_schema_attributes(tiledb::ArraySchema& array_schema, std::vector &cell_val_num); -template void TDBObject::set_schema_attributes(tiledb::ArraySchema& array_schema, std::vector &cell_val_num); - -void TDBObject::set_schema_dimensions(tiledb::ArraySchema& array_schema) -{ - tiledb::Domain domain(_ctx); - - if (_extent == -1) - find_tile_extents(); - else { - _tile_dimension.clear(); - for (int x = 0; x < _num_dimensions; ++x) { - _tile_dimension[x] = _extent; - } + } else { + for (int x = 0; x < _full_attributes.size(); ++x) { + array_schema.add_attribute(_full_attributes[x]); } - - uint64_t domains[_num_dimensions][2]; - int y = 0; + } +} +template void +TDBObject::set_schema_attributes(tiledb::ArraySchema &array_schema, + std::vector &cell_val_num); +template void +TDBObject::set_schema_attributes(tiledb::ArraySchema &array_schema, + std::vector &cell_val_num); +template void +TDBObject::set_schema_attributes(tiledb::ArraySchema &array_schema, + std::vector &cell_val_num); +template void +TDBObject::set_schema_attributes(tiledb::ArraySchema &array_schema, + std::vector &cell_val_num); + +void TDBObject::set_schema_dimensions(tiledb::ArraySchema &array_schema) { + tiledb::Domain domain(_ctx); + + if (_extent == -1) + find_tile_extents(); + else { + _tile_dimension.clear(); for (int x = 0; x < _num_dimensions; ++x) { - if (!_lower_dimensions.empty()) - domains[x][0] = _lower_dimensions[y]; - else - domains[x][0] = 0; - domains[x][1] = _array_dimension[y]; - ++y; + _tile_dimension[x] = _extent; } + } - for (int x = 0; x < _num_dimensions; ++x) { - auto dim = tiledb::Dimension::create(_ctx, - _dimension_names[x].c_str(), {domains[x][0], domains[x][1]}, - _tile_dimension[x]); - domain.add_dimension(dim); - } + uint64_t domains[_num_dimensions][2]; + int y = 0; + for (int x = 0; x < _num_dimensions; ++x) { + if (!_lower_dimensions.empty()) + domains[x][0] = _lower_dimensions[y]; + else + domains[x][0] = 0; + domains[x][1] = _array_dimension[y]; + ++y; + } + + for (int x = 0; x < _num_dimensions; ++x) { + auto dim = tiledb::Dimension::create( + _ctx, _dimension_names[x].c_str(), {domains[x][0], domains[x][1]}, + _tile_dimension[x]); + domain.add_dimension(dim); + } - array_schema.set_domain(domain); + array_schema.set_domain(domain); } -void TDBObject::set_schema_domain(tiledb::ArraySchema& array_schema) -{ - tiledb::Domain domain(_ctx); +void TDBObject::set_schema_domain(tiledb::ArraySchema &array_schema) { + tiledb::Domain domain(_ctx); - for (int x = 0; x < _full_dimensions.size(); ++x) { - domain.add_dimension(_full_dimensions[x]); - } + for (int x = 0; x < _full_dimensions.size(); ++x) { + domain.add_dimension(_full_dimensions[x]); + } - array_schema.set_domain(domain); + array_schema.set_domain(domain); } template -void TDBObject::set_schema_dense(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order) -{ - tiledb::ArraySchema array_schema(_ctx, TILEDB_DENSE); - set_schema(cell_val_num, object_id, tile_order, data_order, array_schema); - - try { - array_schema.check(); - } catch (tiledb::TileDBError &e) { - throw VCLException(TileDBError, "Error creating TDB schema"); - } - - tiledb::Array::create(object_id, array_schema); -} -template void TDBObject::set_schema_dense(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order); -template void TDBObject::set_schema_dense(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order); -template void TDBObject::set_schema_dense(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order); -template void TDBObject::set_schema_dense(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order); +void TDBObject::set_schema_dense(const std::string &object_id, + std::vector &cell_val_num, ORDER tile_order, + ORDER data_order) { + tiledb::ArraySchema array_schema(_ctx, TILEDB_DENSE); + set_schema(cell_val_num, object_id, tile_order, data_order, array_schema); + + try { + array_schema.check(); + } catch (tiledb::TileDBError &e) { + throw VCLException(TileDBError, "Error creating TDB schema"); + } + + tiledb::Array::create(object_id, array_schema); +} +template void +TDBObject::set_schema_dense(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order); +template void TDBObject::set_schema_dense(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order); +template void TDBObject::set_schema_dense(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order); +template void TDBObject::set_schema_dense(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order); template -void TDBObject::set_schema_sparse(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order) -{ - tiledb::ArraySchema array_schema(_ctx, TILEDB_SPARSE); - set_schema(cell_val_num, object_id, tile_order, data_order, array_schema); - array_schema.set_capacity(_tile_capacity); - - try { - array_schema.check(); - } catch (tiledb::TileDBError &e) { - throw VCLException(TileDBError, "Error creating TDB schema"); - } - - tiledb::Array::create(object_id, array_schema); -} -template void TDBObject::set_schema_sparse(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order); -template void TDBObject::set_schema_sparse(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order); -template void TDBObject::set_schema_sparse(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order); -template void TDBObject::set_schema_sparse(const std::string& object_id, std::vector &cell_val_num, - ORDER tile_order, ORDER data_order); +void TDBObject::set_schema_sparse(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order) { + tiledb::ArraySchema array_schema(_ctx, TILEDB_SPARSE); + set_schema(cell_val_num, object_id, tile_order, data_order, array_schema); + array_schema.set_capacity(_tile_capacity); + + try { + array_schema.check(); + } catch (tiledb::TileDBError &e) { + throw VCLException(TileDBError, "Error creating TDB schema"); + } + + tiledb::Array::create(object_id, array_schema); +} +template void +TDBObject::set_schema_sparse(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order); +template void TDBObject::set_schema_sparse(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order); +template void TDBObject::set_schema_sparse(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order); +template void TDBObject::set_schema_sparse(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order, ORDER data_order); template -void TDBObject::set_schema(std::vector &cell_val_num, const std::string& object_id, - ORDER tile_order, ORDER data_order, - tiledb::ArraySchema& array_schema) -{ - if (tile_order == ORDER::ROW) - array_schema.set_tile_order(TILEDB_ROW_MAJOR); - else if (tile_order == ORDER::COLUMN) - array_schema.set_tile_order(TILEDB_COL_MAJOR); - else - array_schema.set_tile_order(TILEDB_GLOBAL_ORDER); - - if (data_order == ORDER::ROW) - array_schema.set_cell_order(TILEDB_ROW_MAJOR); - else if (tile_order == ORDER::COLUMN) - array_schema.set_cell_order(TILEDB_COL_MAJOR); - else - array_schema.set_tile_order(TILEDB_GLOBAL_ORDER); - - set_schema_attributes(array_schema, cell_val_num); - - if (_full_dimensions.empty()) - set_schema_dimensions(array_schema); - else - set_schema_domain(array_schema); -} -template void TDBObject::set_schema(std::vector &cell_val_num, const std::string& object_id, - ORDER tile_order, ORDER data_order, tiledb::ArraySchema& array_schema); -template void TDBObject::set_schema(std::vector &cell_val_num, const std::string& object_id, - ORDER tile_order, ORDER data_order, tiledb::ArraySchema& array_schema); -template void TDBObject::set_schema(std::vector &cell_val_num, const std::string& object_id, - ORDER tile_order, ORDER data_order, tiledb::ArraySchema& array_schema); -template void TDBObject::set_schema(std::vector &cell_val_num, const std::string& object_id, - ORDER tile_order, ORDER data_order, tiledb::ArraySchema& array_schema); - -void TDBObject::set_from_schema(const std::string &object_id) -{ - tiledb::ArraySchema array_schema(_ctx, object_id); - - _num_attributes = array_schema.attribute_num(); - - tiledb::Domain domain = array_schema.domain(); - _num_dimensions = domain.ndim(); - - std::vector dimensions = domain.dimensions(); - for (int i = 0; i < dimensions.size(); ++i) { - _tile_dimension.push_back(dimensions[i].tile_extent()); - - std::pair domain = dimensions[i].domain(); - _array_dimension.push_back(domain.second + 1); - _upper_dimensions.push_back(domain.second + 1); - _lower_dimensions.push_back(domain.first); - } -} - - /* *********************** */ - /* METADATA INTERACTION */ - /* *********************** */ +void TDBObject::set_schema(std::vector &cell_val_num, + const std::string &object_id, ORDER tile_order, + ORDER data_order, + tiledb::ArraySchema &array_schema) { + for (const T &value : cell_val_num) { + // Access the value using the reference + } + + if (tile_order == ORDER::ROW) + array_schema.set_tile_order(TILEDB_ROW_MAJOR); + else if (tile_order == ORDER::COLUMN) + array_schema.set_tile_order(TILEDB_COL_MAJOR); + else + array_schema.set_tile_order(TILEDB_GLOBAL_ORDER); + + if (data_order == ORDER::ROW) + array_schema.set_cell_order(TILEDB_ROW_MAJOR); + else if (tile_order == ORDER::COLUMN) + array_schema.set_cell_order(TILEDB_COL_MAJOR); + else + array_schema.set_tile_order(TILEDB_GLOBAL_ORDER); + + set_schema_attributes(array_schema, cell_val_num); + + if (_full_dimensions.empty()) + set_schema_dimensions(array_schema); + else + set_schema_domain(array_schema); +} +template void TDBObject::set_schema(std::vector &cell_val_num, + const std::string &object_id, + ORDER tile_order, ORDER data_order, + tiledb::ArraySchema &array_schema); +template void TDBObject::set_schema(std::vector &cell_val_num, + const std::string &object_id, + ORDER tile_order, ORDER data_order, + tiledb::ArraySchema &array_schema); +template void TDBObject::set_schema(std::vector &cell_val_num, + const std::string &object_id, + ORDER tile_order, ORDER data_order, + tiledb::ArraySchema &array_schema); +template void TDBObject::set_schema(std::vector &cell_val_num, + const std::string &object_id, + ORDER tile_order, ORDER data_order, + tiledb::ArraySchema &array_schema); + +void TDBObject::set_from_schema(const std::string &object_id) { + tiledb::ArraySchema array_schema(_ctx, object_id); + + _num_attributes = array_schema.attribute_num(); + + tiledb::Domain domain = array_schema.domain(); + _num_dimensions = domain.ndim(); + + std::vector dimensions = domain.dimensions(); + for (int i = 0; i < dimensions.size(); ++i) { + _tile_dimension.push_back(dimensions[i].tile_extent()); + + std::pair domain = dimensions[i].domain(); + _array_dimension.push_back(domain.second + 1); + _upper_dimensions.push_back(domain.second + 1); + _lower_dimensions.push_back(domain.first); + } +} + +/* *********************** */ +/* METADATA INTERACTION */ +/* *********************** */ template void TDBObject::read_metadata(const std::string &array_name, const std::vector &subarray, std::vector &values, - std::string &attribute) -{ - try { - tiledb::Array array(_ctx, array_name, TILEDB_READ); - tiledb::Query md_read(_ctx, array, TILEDB_READ); - - md_read.set_subarray(subarray); - md_read.set_layout(TILEDB_ROW_MAJOR); - - std::vector temp_values(values.size()*2); - md_read.set_buffer(attribute, temp_values); - md_read.submit(); - array.close(); - - int j = 0; - for(int i = 0; i < temp_values.size(); ++i) { - uint64_t val = (uint64_t)temp_values[i] * UCHAR_MAX + (uint64_t)temp_values[i+1]; - values[j] = val; - ++i; - ++j; - } - } - catch (tiledb::TileDBError& e) { - throw VCLException(TileDBNotFound, "No data in TileDB object yet"); + std::string &attribute) { + try { + + tiledb::Array array(_ctx, array_name, TILEDB_READ); + tiledb::Query md_read(_ctx, array, TILEDB_READ); + md_read.set_subarray(subarray); + md_read.set_layout(TILEDB_ROW_MAJOR); + + std::vector temp_values(values.size() * 2); + md_read.set_data_buffer(attribute, temp_values); + md_read.submit(); + array.close(); + + int j = 0; + for (int i = 0; i < temp_values.size(); ++i) { + uint64_t val = + (uint64_t)temp_values[i] * UCHAR_MAX + (uint64_t)temp_values[i + 1]; + values[j] = val; + ++i; + ++j; } + } catch (tiledb::TileDBError &e) { + throw VCLException(TileDBNotFound, "No data in TileDB object yet"); + } } template void TDBObject::read_metadata(const std::string &array_name, - const std::vector &subarray, - std::vector &values, - std::string &attribute); + const std::vector &subarray, + std::vector &values, + std::string &attribute); template void TDBObject::read_metadata(const std::string &array_name, - const std::vector &subarray, - std::vector &values, - std::string &attribute); + const std::vector &subarray, + std::vector &values, + std::string &attribute); template void TDBObject::read_metadata(const std::string &array_name, - const std::vector &subarray, - std::vector &values, - std::string &attribute); - -void TDBObject::find_tile_extents() -{ - _array_dimension.clear(); - _tile_dimension.clear(); - for (int x = 0; x < _num_dimensions; ++x) { - int dimension = _upper_dimensions[x] - _lower_dimensions[x]; - int num_tiles = 0; - - int gf_dimension = greatest_factor(dimension); - - while ( gf_dimension == 1 ) { - dimension = dimension + 1; - gf_dimension = greatest_factor(dimension); - } - - _array_dimension.push_back(dimension - _lower_dimensions[x]); - _tile_dimension.push_back(gf_dimension); + const std::vector &subarray, + std::vector &values, + std::string &attribute); + +void TDBObject::find_tile_extents() { + _array_dimension.clear(); + _tile_dimension.clear(); + for (int x = 0; x < _num_dimensions; ++x) { + int dimension = _upper_dimensions[x] - _lower_dimensions[x]; + int num_tiles = 0; + + int gf_dimension = greatest_factor(dimension); + + while (gf_dimension == 1) { + dimension = dimension + 1; + gf_dimension = greatest_factor(dimension); } -} - -tiledb::Compressor TDBObject::convert_to_tiledb() -{ - switch(static_cast(_compressed)) { - case 0: - return tiledb::Compressor(TILEDB_NO_COMPRESSION, -1); - case 1: - return tiledb::Compressor(TILEDB_GZIP, -1); - case 2: - return tiledb::Compressor(TILEDB_ZSTD, -1); - case 3: - return tiledb::Compressor(TILEDB_LZ4, -1); - case 4: - return tiledb::Compressor(TILEDB_BLOSC_LZ, -1); - case 5: - return tiledb::Compressor(TILEDB_BLOSC_LZ4, -1); - case 6: - return tiledb::Compressor(TILEDB_BLOSC_LZ4HC, -1); - case 7: - return tiledb::Compressor(TILEDB_BLOSC_SNAPPY, -1); - case 8: - return tiledb::Compressor(TILEDB_BLOSC_ZLIB, -1); - case 9: - return tiledb::Compressor(TILEDB_BLOSC_ZSTD, -1); - case 10: - return tiledb::Compressor(TILEDB_RLE, -1); - case 11: - return tiledb::Compressor(TILEDB_BZIP2, -1); - case 12: - return tiledb::Compressor(TILEDB_DOUBLE_DELTA, -1); - default: - throw VCLException(TileDBError, "Compression type not supported.\n"); - } -} - - /* *********************** */ - /* PRIVATE FUNCTIONS */ - /* *********************** */ - -void TDBObject::set_types(int* types) -{ - for ( int i = 0; i < _num_attributes; ++i ) { - types[i] = TILEDB_CHAR; - } -} - -int TDBObject::greatest_factor(int a) -{ - int b = a; - while (b > 1) { - if (a % b == 0 && a / b >= _min_tile_dimension) { - return b; - } - --b; + _array_dimension.push_back(dimension - _lower_dimensions[x]); + _tile_dimension.push_back(gf_dimension); + } +} + +tiledb::Filter TDBObject::convert_to_tiledb() { + tiledb::Filter f(_ctx, TILEDB_FILTER_ZSTD); + + int level = -1; + + switch (static_cast(_compressed)) { + case 0: + f = tiledb::Filter(_ctx, TILEDB_FILTER_NONE); + f.set_option(TILEDB_COMPRESSION_LEVEL, &level); + break; + case 1: + f = tiledb::Filter(_ctx, TILEDB_FILTER_GZIP); + f.set_option(TILEDB_COMPRESSION_LEVEL, &level); + break; + case 2: + f = tiledb::Filter(_ctx, TILEDB_FILTER_ZSTD); + f.set_option(TILEDB_COMPRESSION_LEVEL, &level); + break; + case 3: + f = tiledb::Filter(_ctx, TILEDB_FILTER_LZ4); + f.set_option(TILEDB_COMPRESSION_LEVEL, &level); + break; + + case 4: + f = tiledb::Filter(_ctx, TILEDB_FILTER_RLE); + f.set_option(TILEDB_COMPRESSION_LEVEL, &level); + break; + case 5: + f = tiledb::Filter(_ctx, TILEDB_FILTER_BZIP2); + f.set_option(TILEDB_COMPRESSION_LEVEL, &level); + break; + case 6: + f = tiledb::Filter(_ctx, TILEDB_FILTER_DOUBLE_DELTA); + f.set_option(TILEDB_COMPRESSION_LEVEL, &level); + break; + default: + throw VCLException(TileDBError, "Compression type not supported.\n"); + } + + return f; +} + +/* *********************** */ +/* PRIVATE FUNCTIONS */ +/* *********************** */ + +void TDBObject::set_types(int *types) { + for (int i = 0; i < _num_attributes; ++i) { + types[i] = TILEDB_CHAR; + } +} + +int TDBObject::greatest_factor(int a) { + int b = a; + + while (b > 1) { + if (a % b == 0 && a / b >= _min_tile_dimension) { + return b; } - return b; + --b; + } + return b; } diff --git a/src/vcl/TDBObject.h b/src/vcl/TDBObject.h index 440e5446..898b90c6 100644 --- a/src/vcl/TDBObject.h +++ b/src/vcl/TDBObject.h @@ -34,388 +34,397 @@ #include +#include #include #include -#include -#include #include "vcl/Exception.h" +#include "vcl/RemoteConnection.h" #include "vcl/utils.h" +#include namespace VCL { - class TDBObject { - - /* *********************** */ - /* VARIABLES */ - /* *********************** */ - protected: - // Path variables - std::string _group; - std::string _name; - - // Dimensions (defines the type of TDBObject, should be set in inherited class) - int _num_dimensions; - std::vector _dimension_names; - std::vector _lower_dimensions; - std::vector _upper_dimensions; - std::vector _full_dimensions; - std::vector _full_attributes; - - // Attributes (number of values in a cell) - int _num_attributes; - std::vector _attributes; - - // Compression type - CompressionType _compressed; - int _min_tile_dimension; - - int _extent; - int _tile_capacity; - - // TileDB variables - std::vector _array_dimension; - std::vector _tile_dimension; - tiledb::Context _ctx; - - tiledb::Config _config; - - public: - /* *********************** */ - /* ENUMS */ - /* *********************** */ - enum ORDER { ROW, COLUMN, GLOBAL }; - - /* *********************** */ - /* CONSTRUCTORS */ - /* *********************** */ - /** - * Creates a empty TDBObject - */ - TDBObject(); - - /** - * Creates a TDBObject from an object id - * - * @param object_id The path of the TDBObject - */ - TDBObject(const std::string &object_id); - - /** - * Creates a TDBObject from an existing TDBObject - * - * @param tdb A reference to an existing TDBObject - */ - TDBObject(const TDBObject &tdb); - - /** - * Sets a TDBObject equal to another TDBObject - * - * @param tdb A reference to an existing TDBObject - * @return The current TDBObject - */ - TDBObject& operator=(const TDBObject &tdb); - - /** - * TDBObject destructor - */ - ~TDBObject(); - - - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ - /** - * Gets the path to the TDBObject - * - * @return The string containing the full path to the TDBObject - */ - std::string get_object_id() const; - - - /* *********************** */ - /* SCHEMA */ - /* *********************** */ - /** - * Sets the number of dimensions in the TDBObject, specific - * to the type of TDBObject it will be (Vector objects have - * one dimension, Image objects have two dimensions, - * Volume objects have 3) - * - * @param num_dimensions The number of dimensions - */ - void set_num_dimensions(int num_dimensions); - - /** - * Sets the names of the dimensions in the TDBObject - * - * @param dimensions A vector of strings that define the - * names of the dimensions - */ - void set_dimension_names(const std::vector &dimensions); - - /** - * Sets the values of the dimensions in the TDBObject - * - * @param dimensions A vector of integers that define the - * largest value of each dimension - */ - void set_dimension_upperbounds(const std::vector &dimensions); - - /** - * Sets the values of the dimensions in the TDBObject - * - * @param dimensions A vector of integers that define the - * smallest value of each dimension - */ - void set_dimension_lowerbounds(const std::vector &dimensions); - - /** - * Sets dimensions for the TDBObject using TileDB Dimensions - * - * @param names A vector of names for each dimension - * @param upper_dims A vector of the upper value for each dimension - * @param lower_dims A vector of the lower value for each dimension - * @param extent The tile extent to use - * @note Use this when your domains are not integer values - */ - template - void set_full_dimensions(const std::vector &names, - const std::vector &upper_dims, const std::vector &lower_dims, - int extent); - - /** - * Sets an attribute for the TDBObject using TileDB Attributes - * - * @param attribute The name of the attribute - * @param compressor The type of compression to use - * @param cell_val_num The number of values per cell, in the data type the attribute should be - * @note Use this when you want to have different data types for each attribute - */ - template - void set_single_attribute(std::string &attribute, CompressionType compressor, T cell_val_num); - - /** - * Sets the minimum tile dimension - * - * @param min The minimum number of tiles per dimension - */ - void set_minimum(int dimension); - - /** - * Sets the number of attributes in the TDBObject, which defines - * how the array is stored. Default is usually one - * - * @param num_attributes The number of attributes - */ - void set_num_attributes(int num_attributes); - - /** - * Sets the names of attributes in the TDBObject - * - * @param attributes A vector of strings that define the - * names of the attributes - */ - void set_attributes(const std::vector &attributes); - - /** - * Sets the type of compression to be used when compressing - * the TDBObject - * - * @param comp The compression type - * @see Image.h for details on CompressionType - */ - void set_compression(CompressionType comp); - - /** - * Sets the tile extents in the TDBObject - * - * @param extent The tile extent - */ - void set_extent(int extent) { _extent = extent; }; - - /** - * Sets the tile capacity in a sparse TDBObject - * - * @param capacity The tile capacity - */ - void set_capacity(int capacity) { _tile_capacity = capacity; }; - - /** - * Determines the TileDB schema variables and sets the - * schema for writing a dense TileDB array - * - * @param object_id The full path to the TileDB array - * @param cell_val_num The number of values per cell in the array - * @param tile_order The order in which to store tiles (row, column) - * @param data_order The order in which to store data within a tile (row, column) - */ - template - void set_schema_dense(const std::string &object_id, std::vector &cell_val_num, - ORDER tile_order = ORDER::ROW, ORDER data_order = ORDER::ROW); - - /** - * Determines the TileDB schema variables and sets the - * schema for writing a sparse TileDB array - * - * @param object_id The full path to the TileDB array - * @param cell_val_num The number of values per cell in the array - * @param tile_order The order in which to store tiles (row, column) - * @param data_order The order in which to store data within a tile (row, column) - */ - template - void set_schema_sparse(const std::string &object_id, std::vector &cell_val_num, - ORDER tile_order = ORDER::ROW, ORDER data_order = ORDER::ROW); - - /* *********************** */ - /* TDBOBJECT INTERACTION */ - /* *********************** */ - - /** - * Deletes the object from TileDB - */ - void delete_object(); - - /* *********************** */ - /* METADATA INTERACTION */ - /* *********************** */ - - /** - * Reads the TDBObject metadata - * - * @param array_name The full path to the TileDB array - * @param subarray A vector indicating where in the array - * the metadata is stored - * @param values A vector in which to store the metadata values - */ - template - void read_metadata(const std::string &metadata, - const std::vector &subarray, - std::vector &values, - std::string &attribute); - - - protected: - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ - /** - * Gets the location of the last / in an object id - * - * @param object_id A string - * @return The location of the last / in the given string - */ - size_t get_path_delimiter(const std::string &object_id) const; - - /** - * Gets the parent directory of a file (the TileDB group) - * and tries to create the directory if it does not exist - * - * @param filename The full path of the file - * @param pos The location of the last / in the filename - * @return The name of the TileDB group - */ - std::string get_group(const std::string &filename, size_t pos) const; - - /** - * Gets the name of a file (the TileDB array) - * - * @param filename The full path of the file - * @param pos The location of the last / in the filename - * @return The name of the TileDB array - */ - std::string get_name(const std::string &filename, size_t pos) const; - - - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ - /** - * Sets the member variables of one TDBObject equal to another - * - * @param tdb The TDBOjbect to set the current TDBObject's - * variables equal to - */ - void set_equal(const TDBObject &tdb); - - /** - * Sets the TDBObject values from an array schema - * - * @param object_id The full path to the TileDB array - */ - void set_from_schema(const std::string &object_id); - - - private: - /** - * Sets the TileDB type of the attribute values, currently - * all are unsigned characters - * - * @param types An array to be filled with the attribute - * value types - */ - void set_types(int* types); - - /** - * Finds the greatest factor of a number - * - * @param a The number to factor - * @return The greatest factor of a - */ - int greatest_factor(int a); - - /** - * Resets the arrays that are members of this class - */ - void reset_arrays(); - - /** - * Sets the TileDB schema dimensions to the appropriate values - * - * @param array_schema The TileDB array schema - */ - void set_schema_dimensions(tiledb::ArraySchema& array_schema); - - /** - * Sets the TileDB schema domain - * - * @param array_schema The TileDB array schema - */ - void set_schema_domain(tiledb::ArraySchema& array_schema); - - /** - * Sets the TileDB schema attributes to the appropriate values - * - * @param array_schema The TileDB array schema - * @param cell_val_num The number of values per cell - */ - template - void set_schema_attributes(tiledb::ArraySchema& array_schema, - std::vector &cell_val_num); - - /** - * Sets the TileDB schema - * - * @param cell_val_num The number of values per cell - * @param object_id The full path to the TileDB array - * @param array_schema The TileDB array schema - */ - template - void set_schema(std::vector &cell_val_num, const std::string &object_id, - ORDER tile_order, ORDER data_order, - tiledb::ArraySchema& array_schema); - - /** - * Converts the VCL CompressionType to TileDB compression - */ - tiledb::Compressor convert_to_tiledb(); - - /** - * Determines the size of the TDBObject array as well as - * the size of the tiles. Currently tiles have the same - * length in all dimensions, and the minimum number of - * tiles is 100 - */ - void find_tile_extents(); - }; +class TDBObject { + + /* *********************** */ + /* VARIABLES */ + /* *********************** */ +protected: + // Path variables + std::string _group; + std::string _name; + + // Dimensions (defines the type of TDBObject, should be set in inherited + // class) + int _num_dimensions; + std::vector _dimension_names; + std::vector _lower_dimensions; + std::vector _upper_dimensions; + std::vector _full_dimensions; + std::vector _full_attributes; + + // Attributes (number of values in a cell) + int _num_attributes; + std::vector _attributes; + + // Compression type + CompressionType _compressed; + int _min_tile_dimension; + + int _extent; + int _tile_capacity; + + // TileDB variables + std::vector _array_dimension; + std::vector _tile_dimension; + tiledb::Context _ctx; + + tiledb::Config _config; + +public: + /* *********************** */ + /* ENUMS */ + /* *********************** */ + enum ORDER { ROW, COLUMN, GLOBAL }; + + /* *********************** */ + /* CONSTRUCTORS */ + /* *********************** */ + /** + * Creates a empty TDBObject + */ + TDBObject(); + + /** + * Creates a TDBObject from an object id + * + * @param object_id The path of the TDBObject + */ + TDBObject(const std::string &object_id); + + TDBObject(const std::string &object_id, RemoteConnection &connection); + + /** + * Creates a TDBObject from an existing TDBObject + * + * @param tdb A reference to an existing TDBObject + */ + TDBObject(const TDBObject &tdb); + + /** + * Sets a TDBObject equal to another TDBObject + * + * @param tdb A reference to an existing TDBObject + * @return The current TDBObject + */ + TDBObject &operator=(const TDBObject &tdb); + + /** + * TDBObject destructor + */ + ~TDBObject(); + + /* *********************** */ + /* GET FUNCTIONS */ + /* *********************** */ + /** + * Gets the path to the TDBObject + * + * @return The string containing the full path to the TDBObject + */ + std::string get_object_id() const; + + /* *********************** */ + /* SCHEMA */ + /* *********************** */ + /** + * Sets the number of dimensions in the TDBObject, specific + * to the type of TDBObject it will be (Vector objects have + * one dimension, Image objects have two dimensions, + * Volume objects have 3) + * + * @param num_dimensions The number of dimensions + */ + void set_num_dimensions(int num_dimensions); + + /** + * Sets the names of the dimensions in the TDBObject + * + * @param dimensions A vector of strings that define the + * names of the dimensions + */ + void set_dimension_names(const std::vector &dimensions); + + /** + * Sets the values of the dimensions in the TDBObject + * + * @param dimensions A vector of integers that define the + * largest value of each dimension + */ + void set_dimension_upperbounds(const std::vector &dimensions); + + /** + * Sets the values of the dimensions in the TDBObject + * + * @param dimensions A vector of integers that define the + * smallest value of each dimension + */ + void set_dimension_lowerbounds(const std::vector &dimensions); + + /** + * Sets dimensions for the TDBObject using TileDB Dimensions + * + * @param names A vector of names for each dimension + * @param upper_dims A vector of the upper value for each dimension + * @param lower_dims A vector of the lower value for each dimension + * @param extent The tile extent to use + * @note Use this when your domains are not integer values + */ + template + void set_full_dimensions(const std::vector &names, + const std::vector &upper_dims, + const std::vector &lower_dims, int extent); + + /** + * Sets an attribute for the TDBObject using TileDB Attributes + * + * @param attribute The name of the attribute + * @param compressor The type of compression to use + * @param cell_val_num The number of values per cell, in the data type the + * attribute should be + * @note Use this when you want to have different data types for each + * attribute + */ + template + void set_single_attribute(std::string &attribute, CompressionType compressor, + T cell_val_num); + + /** + * Sets the minimum tile dimension + * + * @param min The minimum number of tiles per dimension + */ + void set_minimum(int dimension); + + /** + * Sets the number of attributes in the TDBObject, which defines + * how the array is stored. Default is usually one + * + * @param num_attributes The number of attributes + */ + void set_num_attributes(int num_attributes); + + /** + * Sets the names of attributes in the TDBObject + * + * @param attributes A vector of strings that define the + * names of the attributes + */ + void set_attributes(const std::vector &attributes); + + /** + * Sets the type of compression to be used when compressing + * the TDBObject + * + * @param comp The compression type + * @see Image.h for details on CompressionType + */ + void set_compression(CompressionType comp); + + void set_config(RemoteConnection *remote); + + /** + * Sets the tile extents in the TDBObject + * + * @param extent The tile extent + */ + void set_extent(int extent) { _extent = extent; }; + + /** + * Sets the tile capacity in a sparse TDBObject + * + * @param capacity The tile capacity + */ + void set_capacity(int capacity) { _tile_capacity = capacity; }; + + /** + * Determines the TileDB schema variables and sets the + * schema for writing a dense TileDB array + * + * @param object_id The full path to the TileDB array + * @param cell_val_num The number of values per cell in the array + * @param tile_order The order in which to store tiles (row, column) + * @param data_order The order in which to store data within a tile (row, + * column) + */ + template + void set_schema_dense(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order = ORDER::ROW, + ORDER data_order = ORDER::ROW); + + /** + * Determines the TileDB schema variables and sets the + * schema for writing a sparse TileDB array + * + * @param object_id The full path to the TileDB array + * @param cell_val_num The number of values per cell in the array + * @param tile_order The order in which to store tiles (row, column) + * @param data_order The order in which to store data within a tile (row, + * column) + */ + template + void set_schema_sparse(const std::string &object_id, + std::vector &cell_val_num, + ORDER tile_order = ORDER::ROW, + ORDER data_order = ORDER::ROW); + + /* *********************** */ + /* TDBOBJECT INTERACTION */ + /* *********************** */ + + /** + * Deletes the object from TileDB + */ + void delete_object(); + + /* *********************** */ + /* METADATA INTERACTION */ + /* *********************** */ + + /** + * Reads the TDBObject metadata + * + * @param array_name The full path to the TileDB array + * @param subarray A vector indicating where in the array + * the metadata is stored + * @param values A vector in which to store the metadata values + */ + template + void read_metadata(const std::string &metadata, + const std::vector &subarray, + std::vector &values, std::string &attribute); + +protected: + /* *********************** */ + /* GET FUNCTIONS */ + /* *********************** */ + /** + * Gets the location of the last / in an object id + * + * @param object_id A string + * @return The location of the last / in the given string + */ + size_t get_path_delimiter(const std::string &object_id) const; + + /** + * Gets the parent directory of a file (the TileDB group) + * and tries to create the directory if it does not exist + * + * @param filename The full path of the file + * @param pos The location of the last / in the filename + * @return The name of the TileDB group + */ + std::string get_group(const std::string &filename, size_t pos) const; + + /** + * Gets the name of a file (the TileDB array) + * + * @param filename The full path of the file + * @param pos The location of the last / in the filename + * @return The name of the TileDB array + */ + std::string get_name(const std::string &filename, size_t pos) const; + + /* *********************** */ + /* SET FUNCTIONS */ + /* *********************** */ + /** + * Sets the member variables of one TDBObject equal to another + * + * @param tdb The TDBOjbect to set the current TDBObject's + * variables equal to + */ + void set_equal(const TDBObject &tdb); + + /** + * Sets the TDBObject values from an array schema + * + * @param object_id The full path to the TileDB array + */ + void set_from_schema(const std::string &object_id); + +private: + /** + * Sets the TileDB type of the attribute values, currently + * all are unsigned characters + * + * @param types An array to be filled with the attribute + * value types + */ + void set_types(int *types); + + /** + * Finds the greatest factor of a number + * + * @param a The number to factor + * @return The greatest factor of a + */ + int greatest_factor(int a); + + /** + * Resets the arrays that are members of this class + */ + void reset_arrays(); + + /** + * Sets the TileDB schema dimensions to the appropriate values + * + * @param array_schema The TileDB array schema + */ + void set_schema_dimensions(tiledb::ArraySchema &array_schema); + + /** + * Sets the TileDB schema domain + * + * @param array_schema The TileDB array schema + */ + void set_schema_domain(tiledb::ArraySchema &array_schema); + + /** + * Sets the TileDB schema attributes to the appropriate values + * + * @param array_schema The TileDB array schema + * @param cell_val_num The number of values per cell + */ + template + void set_schema_attributes(tiledb::ArraySchema &array_schema, + std::vector &cell_val_num); + + /** + * Sets the TileDB schema + * + * @param cell_val_num The number of values per cell + * @param object_id The full path to the TileDB array + * @param array_schema The TileDB array schema + */ + template + void set_schema(std::vector &cell_val_num, const std::string &object_id, + ORDER tile_order, ORDER data_order, + tiledb::ArraySchema &array_schema); + + /** + * Converts the VCL CompressionType to TileDB compression + */ + tiledb::Filter convert_to_tiledb(); + + /** + * Determines the size of the TDBObject array as well as + * the size of the tiles. Currently tiles have the same + * length in all dimensions, and the minimum number of + * tiles is 100 + */ + void find_tile_extents(); }; +}; // namespace VCL diff --git a/src/vcl/TDBSparseDescriptorSet.cc b/src/vcl/TDBSparseDescriptorSet.cc index 2eff6af7..7f091ece 100644 --- a/src/vcl/TDBSparseDescriptorSet.cc +++ b/src/vcl/TDBSparseDescriptorSet.cc @@ -27,430 +27,417 @@ * */ -#include -#include -#include -#include #include #include +#include +#include #include +#include +#include #include "TDBDescriptorSet.h" #include -#define ATTRIBUTE_SPARSE_ID "id" +#define ATTRIBUTE_SPARSE_ID "id" #define ATTRIBUTE_SPARSE_LABEL "label" - #define DIMENSION_LOWER_LIMIT -10000 #define DIMENSION_UPPER_LIMIT 10000 #define DIMENSION_TILE_SIZE 250 using namespace VCL; -TDBSparseDescriptorSet::TDBSparseDescriptorSet(const std::string &filename): - TDBDescriptorSet(filename) -{ - _name = "unnecessary_name"; - TDBObject descriptorSetObject(_set_path); - read_descriptor_metadata(); +TDBSparseDescriptorSet::TDBSparseDescriptorSet(const std::string &filename) + : TDBDescriptorSet(filename) { + _name = "unnecessary_name"; + TDBObject descriptorSetObject(_set_path); + read_descriptor_metadata(); } -TDBSparseDescriptorSet::TDBSparseDescriptorSet( - const std::string &filename, - uint32_t dim, - DistanceMetric metric): - TDBDescriptorSet(filename, dim) -{ - _name = "unnecessary_name"; - - std::vector names; - std::vector uppers; - std::vector lowers; - TDBObject descriptorSetObject; - - for (int i = 0; i < _dimensions; ++i) { - names.push_back("dim_" + std::to_string(i)); - lowers.push_back(DIMENSION_LOWER_LIMIT); +TDBSparseDescriptorSet::TDBSparseDescriptorSet(const std::string &filename, + uint32_t dim, + DistanceMetric metric) + : TDBDescriptorSet(filename, dim) { + _name = "unnecessary_name"; + + std::vector names; + std::vector uppers; + std::vector lowers; + TDBObject descriptorSetObject; + + for (int i = 0; i < _dimensions; ++i) { + names.push_back("dim_" + std::to_string(i)); + lowers.push_back(DIMENSION_LOWER_LIMIT); + + if (i == 0) { + // First dimension is incresed to store metadata, + // as descriptors will always have at least 1 dim. + uppers.push_back(DIMENSION_UPPER_LIMIT + DIMENSION_TILE_SIZE); + } else + uppers.push_back(DIMENSION_UPPER_LIMIT); + } + + descriptorSetObject.set_full_dimensions(names, uppers, lowers, + DIMENSION_TILE_SIZE); + descriptorSetObject.set_capacity(100); + descriptorSetObject.set_compression(VCL::CompressionType::LZ4); + descriptorSetObject.set_attributes( + std::vector{ATTRIBUTE_SPARSE_ID, ATTRIBUTE_SPARSE_LABEL}); + + std::vector num_values{1, 1}; + descriptorSetObject.set_schema_sparse(_set_path, num_values); + write_descriptor_metadata(); +} - if (i == 0) { - // First dimension is incresed to store metadata, - // as descriptors will always have at least 1 dim. - uppers.push_back(DIMENSION_UPPER_LIMIT + DIMENSION_TILE_SIZE); - } - else - uppers.push_back(DIMENSION_UPPER_LIMIT); - } +void TDBSparseDescriptorSet::read_descriptor_metadata() { + tiledb::Array array(_ctx, _set_path, TILEDB_READ); + _dimensions = array.schema().domain().ndim(); + std::vector coords(_dimensions * 2, DIMENSION_UPPER_LIMIT); + coords[0] += 1.0f; + coords[1] += 1.0f; + + tiledb::Query md_read(_ctx, array, TILEDB_READ); + std::vector id_val(DIMENSION_UPPER_LIMIT); + std::vector label_val(DIMENSION_UPPER_LIMIT); + md_read.set_subarray(coords); + md_read.set_layout(TILEDB_ROW_MAJOR); + md_read.set_data_buffer(ATTRIBUTE_SPARSE_ID, id_val); + md_read.set_data_buffer(ATTRIBUTE_SPARSE_LABEL, label_val); + + md_read.submit(); + array.close(); + + _dimensions = id_val[0]; + _n_total = label_val[0]; +} - descriptorSetObject.set_full_dimensions(names, uppers, lowers, DIMENSION_TILE_SIZE); - descriptorSetObject.set_capacity(100); - descriptorSetObject.set_compression(VCL::CompressionType::LZ4); - descriptorSetObject.set_attributes(std::vector{ATTRIBUTE_SPARSE_ID, ATTRIBUTE_SPARSE_LABEL}); +void TDBSparseDescriptorSet::write_descriptor_metadata() { + std::vector coords(_dimensions, DIMENSION_UPPER_LIMIT); + coords[0] += 1.0f; - std::vector num_values{1, 1}; - descriptorSetObject.set_schema_sparse(_set_path, num_values); + long dims = _dimensions; + long n_total = _n_total; + tiledb::Array array(_ctx, _set_path, TILEDB_WRITE); + tiledb::Query query(_ctx, array); + query.set_layout(TILEDB_UNORDERED); + query.set_data_buffer(ATTRIBUTE_SPARSE_ID, &dims, 1); + query.set_data_buffer(ATTRIBUTE_SPARSE_LABEL, &n_total, 1); - write_descriptor_metadata(); -} + query.set_data_buffer(TILEDB_COORDS, coords.data(), coords.size()); -void TDBSparseDescriptorSet::read_descriptor_metadata() -{ - tiledb::Array array(_ctx, _set_path, TILEDB_READ); - _dimensions = array.schema().domain().ndim(); - std::vector coords(_dimensions * 2, DIMENSION_UPPER_LIMIT); - coords[0] += 1.0f; - coords[1] += 1.0f; - - auto max_elements = array.max_buffer_elements(coords); - std::vector id_val(max_elements[ATTRIBUTE_SPARSE_ID].second); - std::vector label_val(max_elements[ATTRIBUTE_SPARSE_LABEL].second); - - tiledb::Query md_read(_ctx, array, TILEDB_READ); - - md_read.set_subarray(coords); - md_read.set_layout(TILEDB_ROW_MAJOR); - md_read.set_buffer(ATTRIBUTE_SPARSE_ID, id_val); - md_read.set_buffer(ATTRIBUTE_SPARSE_LABEL, label_val); - md_read.submit(); - array.close(); - - _dimensions = id_val[0]; - _n_total = label_val[0]; -} + query.submit(); -void TDBSparseDescriptorSet::write_descriptor_metadata() -{ - std::vector coords(_dimensions, DIMENSION_UPPER_LIMIT); - coords[0] += 1.0f; + query.finalize(); - long dims = _dimensions; - long n_total = _n_total; - // We use the ID attribute to store _dimension - // and the LABEL attibute to store _n_total; - tiledb::Array array(_ctx, _set_path, TILEDB_WRITE); - tiledb::Query query(_ctx, array); - query.set_layout(TILEDB_GLOBAL_ORDER); - query.set_buffer(ATTRIBUTE_SPARSE_ID, &dims, 1); - query.set_buffer(ATTRIBUTE_SPARSE_LABEL, &n_total, 1); - query.set_buffer(TILEDB_COORDS, coords); - query.submit(); - query.finalize(); - array.close(); + array.close(); } -long TDBSparseDescriptorSet::add(float* descriptors, unsigned n, long* labels) -{ - try { - std::vector att_id(n); - std::iota(att_id.begin(), att_id.end(), _n_total); +long TDBSparseDescriptorSet::add(float *descriptors, unsigned int n, + long *labels) { + try { + std::vector att_id(n); + std::iota(att_id.begin(), att_id.end(), _n_total); - std::vector att_label; + std::vector att_label; - long* labels_for_query = labels; + long *labels_for_query = labels; - if (labels == NULL) { - // By default, labels is -1 - att_label = std::vector (n, -1); - labels_for_query = att_label.data(); - } + if (labels == NULL) { + // By default, labels is -1 + att_label = std::vector(n, -1); + labels_for_query = att_label.data(); + } - { - tiledb::Array array(_ctx, _set_path, TILEDB_WRITE); - tiledb::Query query(_ctx, array); - query.set_layout(TILEDB_GLOBAL_ORDER); - query.set_buffer(ATTRIBUTE_SPARSE_ID, att_id); - query.set_buffer(ATTRIBUTE_SPARSE_LABEL, labels_for_query, n); - query.set_buffer(TILEDB_COORDS, descriptors, n * _dimensions); - query.submit(); - query.finalize(); - array.close(); - } - } catch (tiledb::TileDBError &e) { - throw VCLException(UnsupportedOperation, "TileDBError, check logs"); + { + tiledb::Array array(_ctx, _set_path, TILEDB_WRITE); + tiledb::Query query(_ctx, array); + // query.set_layout(TILEDB_GLOBAL_ORDER); + query.set_data_buffer(ATTRIBUTE_SPARSE_ID, att_id); + query.set_data_buffer(ATTRIBUTE_SPARSE_LABEL, labels_for_query, n); + query.set_data_buffer(TILEDB_COORDS, descriptors, n * _dimensions); + + query.submit(); + query.finalize(); + array.close(); } + } catch (tiledb::TileDBError &e) { + throw VCLException(UnsupportedOperation, "TileDBError, check logs"); + } - write_descriptor_metadata(); - _n_total += n; - return _n_total - n; + write_descriptor_metadata(); + _n_total += n; + return _n_total - n; } -void TDBSparseDescriptorSet::load_neighbors(float* q, unsigned k, - std::vector& descriptors, - std::vector& desc_ids, - std::vector& desc_labels) -{ - bool flag_found = true; - long found = 0; - int attempt = 0; +void TDBSparseDescriptorSet::load_neighbors(float *q, unsigned k, + std::vector &descriptors, + std::vector &desc_ids, + std::vector &desc_labels) { + bool flag_found = true; + long found = 0; + int attempt = 0; - tiledb::Array array(_ctx, _set_path, TILEDB_READ); + tiledb::Array array(_ctx, _set_path, TILEDB_READ); - while (found < k) { - // Calculate maximum buffer elements for the - // query results per attribute + while (found < k) { + // Calculate maximum buffer elements for the + // query results per attribute - std::vector subarray(_dimensions * 2); + std::vector subarray(_dimensions * 2); - float space = std::pow(2, 4 + attempt++); + float space = std::pow(2, 4 + attempt++); - if (space >= (DIMENSION_UPPER_LIMIT - DIMENSION_LOWER_LIMIT) / 2) { - flag_found = false; - break; - } + if (space >= (DIMENSION_UPPER_LIMIT - DIMENSION_LOWER_LIMIT) / 2) { + flag_found = false; + break; + } - #pragma omp parallel for - for (int i = 0; i < _dimensions; ++i) { - subarray[2*i+0] = (q[i] - space) > DIMENSION_LOWER_LIMIT ? - (q[i] - space) : DIMENSION_LOWER_LIMIT; - subarray[2*i+1] = (q[i] + space) < DIMENSION_UPPER_LIMIT ? - (q[i] + space) : DIMENSION_UPPER_LIMIT; - } +#pragma omp parallel for + for (int i = 0; i < _dimensions; ++i) { + subarray[2 * i + 0] = (q[i] - space) > DIMENSION_LOWER_LIMIT + ? (q[i] - space) + : DIMENSION_LOWER_LIMIT; + subarray[2 * i + 1] = (q[i] + space) < DIMENSION_UPPER_LIMIT + ? (q[i] + space) + : DIMENSION_UPPER_LIMIT; + } - auto max_sizes = array.max_buffer_elements(subarray); + // Create query - // Prepare cell buffers - descriptors.resize(max_sizes[TILEDB_COORDS].second); - desc_ids.resize(max_sizes[ATTRIBUTE_SPARSE_ID].second); - desc_labels.resize(max_sizes[ATTRIBUTE_SPARSE_LABEL].second); + tiledb::Query query(_ctx, array); - // Create query - tiledb::Query query(_ctx, array); - query.set_layout(TILEDB_ROW_MAJOR).set_subarray(subarray); - query.set_buffer(ATTRIBUTE_SPARSE_LABEL, desc_labels); - query.set_buffer(ATTRIBUTE_SPARSE_ID, desc_ids); - query.set_buffer(TILEDB_COORDS, descriptors); + descriptors.resize(query.est_result_size(TILEDB_COORDS)); + desc_ids.resize(query.est_result_size(ATTRIBUTE_SPARSE_ID)); + desc_labels.resize(query.est_result_size(ATTRIBUTE_SPARSE_LABEL)); + query.set_layout(TILEDB_ROW_MAJOR); + query.set_subarray(subarray) + .set_data_buffer(ATTRIBUTE_SPARSE_LABEL, desc_labels) + .set_data_buffer(ATTRIBUTE_SPARSE_ID, desc_ids) + .set_data_buffer(TILEDB_COORDS, descriptors); - // Submit query - query.submit(); + query.submit(); - auto result_el = query.result_buffer_elements(); - found = result_el[ATTRIBUTE_SPARSE_ID].second; + auto result_el = query.result_buffer_elements(); + found = result_el[ATTRIBUTE_SPARSE_ID].second; - descriptors.resize(found * _dimensions); - desc_ids.resize(found); - desc_labels.resize(found); - } + descriptors.resize(found * _dimensions); + desc_ids.resize(found); + desc_labels.resize(found); + } - array.close(); + array.close(); - if (flag_found == false) { - desc_ids.clear(); - desc_labels.clear(); - descriptors.clear(); - } + if (flag_found == false) { + desc_ids.clear(); + desc_labels.clear(); + descriptors.clear(); + } } -void TDBSparseDescriptorSet::classify(float* descriptors, unsigned n, - long* labels, unsigned quorum) -{ - float* distances = new float[n * quorum]; - long* ids_aux = new long [n * quorum]; - long* labels_aux = new long [n * quorum]; - - search(descriptors, n, quorum, ids_aux, distances, labels_aux); - - for (int j = 0; j < n; ++j) { - - std::map map_voting; - long winner = -1; - unsigned max = 0; - for (int i = 0; i < quorum; ++i) { - long idx = ids_aux[quorum*j + i]; - if (idx < 0) - continue; // Means not found - - long label_id = labels_aux[quorum*j + i]; - map_voting[label_id] += 1; - if (max < map_voting[label_id]) { - max = map_voting[label_id]; - winner = label_id; - } - } - labels[j] = winner; +void TDBSparseDescriptorSet::classify(float *descriptors, unsigned n, + long *labels, unsigned quorum) { + float *distances = new float[n * quorum]; + long *ids_aux = new long[n * quorum]; + long *labels_aux = new long[n * quorum]; + + search(descriptors, n, quorum, ids_aux, distances, labels_aux); + + for (int j = 0; j < n; ++j) { + + std::map map_voting; + long winner = -1; + unsigned max = 0; + for (int i = 0; i < quorum; ++i) { + long idx = ids_aux[quorum * j + i]; + if (idx < 0) + continue; // Means not found + + long label_id = labels_aux[quorum * j + i]; + map_voting[label_id] += 1; + if (max < map_voting[label_id]) { + max = map_voting[label_id]; + winner = label_id; + } } - delete[] distances; - delete[] ids_aux; - delete[] labels_aux; + labels[j] = winner; + } + delete[] distances; + delete[] ids_aux; + delete[] labels_aux; } -void TDBSparseDescriptorSet::search(float* query, unsigned n, unsigned k, - long* ids, float* distances, long* labels) -{ - std::vector descs; - std::vector desc_ids; - std::vector desc_labels; +void TDBSparseDescriptorSet::search(float *query, unsigned n, unsigned k, + long *ids, float *distances, long *labels) { + std::vector descs; + std::vector desc_ids; + std::vector desc_labels; - for (int i = 0; i < n; ++i) { + for (int i = 0; i < n; ++i) { - load_neighbors(query + i * _dimensions, k, descs, desc_ids, desc_labels); - unsigned found = desc_ids.size(); + load_neighbors(query + i * _dimensions, k, descs, desc_ids, desc_labels); - std::vector d(found); - std::vector idxs(found); + unsigned found = desc_ids.size(); + std::vector d(found); + std::vector idxs(found); - compute_distances(query + i * _dimensions, d, descs); + compute_distances(query + i * _dimensions, d, descs); - std::iota(idxs.begin(), idxs.end(), 0); - std::partial_sort(idxs.begin(), idxs.begin() + k, idxs.end(), - [&d](size_t i1, size_t i2) { return d[i1] < d[i2]; }); + std::iota(idxs.begin(), idxs.end(), 0); + std::partial_sort(idxs.begin(), idxs.begin() + k, idxs.end(), + [&d](size_t i1, size_t i2) { return d[i1] < d[i2]; }); - for (int j = 0; j < std::min(k, found); ++j) { - ids [i * k + j] = desc_ids[idxs[j]]; - distances[i * k + j] = d[idxs[j]]; - } + for (int j = 0; j < std::min(k, found); ++j) { + ids[i * k + j] = desc_ids[idxs[j]]; + distances[i * k + j] = d[idxs[j]]; + } - if ( k > found) { - for (int j = found; j < k; ++j) { - ids [i * k + j] = -1; - distances[i * k + j] = -1; - } - } + if (k > found) { + for (int j = found; j < k; ++j) { + ids[i * k + j] = -1; + distances[i * k + j] = -1; + } + } - // Include labels, needed for faster classify - // because it already gets the labels from the load_neighbor() - if (labels != NULL) { - for (int j = 0; j < std::min(k, found); ++j) { - labels [i * k + j] = desc_labels[idxs[j]]; - } - - if ( k > found) { - for (int j = found; j < k; ++j) { - labels [i * k + j] = -1; - } - } + // Include labels, needed for faster classify + // because it already gets the labels from the load_neighbor() + if (labels != NULL) { + for (int j = 0; j < std::min(k, found); ++j) { + labels[i * k + j] = desc_labels[idxs[j]]; + } + + if (k > found) { + for (int j = found; j < k; ++j) { + labels[i * k + j] = -1; } + } } + } } -void TDBSparseDescriptorSet::search(float* query, unsigned n, unsigned k, - long* ids, float* distances) -{ - search(query, n, k, ids, distances, NULL); +void TDBSparseDescriptorSet::search(float *query, unsigned n, unsigned k, + long *ids, float *distances) { + search(query, n, k, ids, distances, NULL); } -void TDBSparseDescriptorSet::get_descriptors(long* ids, unsigned n, - float* descriptors) -{ - std::vector subarray(_dimensions * 2); +void TDBSparseDescriptorSet::get_descriptors(long *ids, unsigned n, + float *descriptors) { + std::vector subarray(_dimensions * 2); - float space = 20; + float space = 20; - #pragma omp parallel for - for (int i = 0; i < _dimensions; ++i) { - subarray[2*i+0] = DIMENSION_LOWER_LIMIT; - subarray[2*i+1] = DIMENSION_UPPER_LIMIT; - } +#pragma omp parallel for + for (int i = 0; i < _dimensions; ++i) { + subarray[2 * i + 0] = DIMENSION_LOWER_LIMIT; + subarray[2 * i + 1] = DIMENSION_UPPER_LIMIT; + } - tiledb::Array array(_ctx, _set_path, TILEDB_READ); - auto max_sizes = array.max_buffer_elements(subarray); + tiledb::Array array(_ctx, _set_path, TILEDB_READ); - // Prepare cell buffers - std::vector buffer; - buffer.resize(max_sizes[TILEDB_COORDS].second); - std::vector desc_ids; - desc_ids.resize(max_sizes[ATTRIBUTE_SPARSE_ID].second); + std::vector buffer; - // Create query - tiledb::Query query(_ctx, array); - query.set_layout(TILEDB_ROW_MAJOR); - query.set_subarray(subarray); - query.set_buffer(ATTRIBUTE_SPARSE_ID, desc_ids); - query.set_buffer(TILEDB_COORDS, buffer); + std::vector desc_ids; - // Submit query - query.submit(); + // Create query + tiledb::Query query(_ctx, array); + desc_ids.resize(query.est_result_size(ATTRIBUTE_SPARSE_ID)); + buffer.resize(query.est_result_size(TILEDB_COORDS)); + query.set_layout(TILEDB_ROW_MAJOR); + query.set_subarray(subarray); + query.set_data_buffer(ATTRIBUTE_SPARSE_ID, desc_ids); + query.set_data_buffer(TILEDB_COORDS, buffer); - // Print cell values (assumes all attributes are read) - auto result_el = query.result_buffer_elements(); - unsigned n_found = result_el[ATTRIBUTE_SPARSE_ID].second; - - buffer.resize(n_found * _dimensions); - desc_ids.resize(n_found); - - // This is the worst algorithm ever, EVER. - // This is O(n), can be implemented using a binary search. - // We need to sort the desc_ids for this, need a trade off. - - for (int i = 0; i < n; ++i) { - long offset = i *_dimensions; - long id_q = ids[i]; - bool found = false; - - for (int j = 0; j < desc_ids.size(); ++j) { - if (id_q == desc_ids[j]) { - std::memcpy(descriptors + offset, - &buffer[j * _dimensions], - sizeof(float) * _dimensions); - found = true; - break; - } - } + // Submit query + query.submit(); - if (found) { - continue; - } + // Print cell values (assumes all attributes are read) + auto result_el = query.result_buffer_elements(); + unsigned n_found = result_el[ATTRIBUTE_SPARSE_ID].second; - for (int j = 0; j < _dimensions; ++j) { - descriptors[offset+j] = -1; - } + buffer.resize(n_found * _dimensions); + desc_ids.resize(n_found); + + // This is the worst algorithm ever, EVER. + // This is O(n), can be implemented using a binary search. + // We need to sort the desc_ids for this, need a trade off. + + for (int i = 0; i < n; ++i) { + long offset = i * _dimensions; + long id_q = ids[i]; + bool found = false; + + for (int j = 0; j < desc_ids.size(); ++j) { + if (id_q == desc_ids[j]) { + std::memcpy(descriptors + offset, &buffer[j * _dimensions], + sizeof(float) * _dimensions); + found = true; + break; + } } -} -void TDBSparseDescriptorSet::get_labels(long* ids, unsigned n, long* labels) -{ - std::vector subarray(_dimensions * 2); + if (found) { + continue; + } - #pragma omp parallel for - for (int i = 0; i < _dimensions; ++i) { - subarray[2*i+0] = DIMENSION_LOWER_LIMIT; - subarray[2*i+1] = DIMENSION_UPPER_LIMIT; + for (int j = 0; j < _dimensions; ++j) { + descriptors[offset + j] = -1; } + } +} - tiledb::Array array(_ctx, _set_path, TILEDB_READ); - auto max_sizes = array.max_buffer_elements(subarray); +void TDBSparseDescriptorSet::get_labels(long *ids, unsigned n, long *labels) { + std::vector subarray(_dimensions * 2); - // Prepare cell buffers - std::vector desc_ids; - desc_ids.resize(max_sizes[ATTRIBUTE_SPARSE_ID].second); - std::vector desc_labels; - desc_labels.resize(max_sizes[ATTRIBUTE_SPARSE_LABEL].second); +#pragma omp parallel for + for (int i = 0; i < _dimensions; ++i) { + subarray[2 * i + 0] = DIMENSION_LOWER_LIMIT; + subarray[2 * i + 1] = DIMENSION_UPPER_LIMIT; + } - // Create query - tiledb::Query query(_ctx, array); - query.set_layout(TILEDB_ROW_MAJOR).set_subarray(subarray); - query.set_buffer(ATTRIBUTE_SPARSE_LABEL, desc_labels); - query.set_buffer(ATTRIBUTE_SPARSE_ID, desc_ids); + tiledb::Array array(_ctx, _set_path, TILEDB_READ); - // Submit query - query.submit(); + // auto max_sizes = array.max_buffer_elements(subarray); - // Print cell values (assumes all attributes are read) - auto result_el = query.result_buffer_elements(); - unsigned n_found = result_el[ATTRIBUTE_SPARSE_ID].second; - - desc_ids.resize(n_found); - desc_labels.resize(n_found); - - // This is the worst algo ever, EVER. - // This is O(n), can be implemented using a binary search. - // We need to sort the desc_ids for this, need a trade off. - - for (int i = 0; i < n; ++i) { - long offset = i *_dimensions; - long id_q = ids[i]; - bool found = false; - - for (int j = 0; j < desc_ids.size(); ++j) { - if (id_q == desc_ids[j]) { - labels[i] = desc_labels[j]; - found = true; - break; - } - } + // Create query + tiledb::Query query(_ctx, array); + std::vector desc_ids; + std::vector desc_labels; + desc_ids.resize(query.est_result_size(ATTRIBUTE_SPARSE_ID)); + desc_labels.resize(query.est_result_size(ATTRIBUTE_SPARSE_LABEL)); - if (found) { - continue; - } + query.set_layout(TILEDB_ROW_MAJOR).set_subarray(subarray); + query.set_data_buffer(ATTRIBUTE_SPARSE_LABEL, desc_labels); + query.set_data_buffer(ATTRIBUTE_SPARSE_ID, desc_ids); + + // Submit query + query.submit(); + + // Print cell values (assumes all attributes are read) + auto result_el = query.result_buffer_elements(); + unsigned n_found = result_el[ATTRIBUTE_SPARSE_ID].second; + + desc_ids.resize(n_found); + desc_labels.resize(n_found); + + // This is the worst algo ever, EVER. + // This is O(n), can be implemented using a binary search. + // We need to sort the desc_ids for this, need a trade off. - labels[i] = -1; + for (int i = 0; i < n; ++i) { + long offset = i * _dimensions; + long id_q = ids[i]; + bool found = false; + + for (int j = 0; j < desc_ids.size(); ++j) { + if (id_q == desc_ids[j]) { + labels[i] = desc_labels[j]; + found = true; + break; + } + } + + if (found) { + continue; } + + labels[i] = -1; + } } diff --git a/src/vcl/Video.cc b/src/vcl/Video.cc index d5430c7e..797bc82f 100644 --- a/src/vcl/Video.cc +++ b/src/vcl/Video.cc @@ -27,683 +27,637 @@ * */ -#include #include +#include #include "vcl/Video.h" using namespace VCL; - /* *********************** */ - /* CONSTRUCTORS */ - /* *********************** */ +/* *********************** */ +/* CONSTRUCTORS */ +/* *********************** */ -Video::Video() : - _size({.width = 0, .height = 0, .frame_count = 0}), - _fps(0), - _video_id(""), - _flag_stored(true), - _codec(Video::Codec::NOCODEC), - _video_read(nullptr) -{ -} +Video::Video() + : _size({.width = 0, .height = 0, .frame_count = 0}), _fps(0), + _video_id(""), _flag_stored(true), _codec(Video::Codec::NOCODEC), + _video_read(nullptr), _remote(nullptr) {} -Video::Video(const std::string& video_id) : - Video() -{ - _video_id = video_id; +Video::Video(const std::string &video_id) : Video() { + _video_id = video_id; + _remote = nullptr; } -Video::Video(void* buffer, long size) : - Video() -{ - std::string uname = create_unique("/tmp/tmp/", "vclvideoblob"); - std::ofstream outfile(uname, std::ofstream::binary); +Video::Video(void *buffer, long size) : Video() { + std::string uname = create_unique("/tmp/tmp/", "vclvideoblob"); + std::ofstream outfile(uname, std::ofstream::binary); + _remote = nullptr; - if (outfile.is_open()) { - outfile.write((char*)buffer, size); - outfile.close(); - } - else - throw VCLException(OpenFailed, "Cannot create temporary file"); + if (outfile.is_open()) { + outfile.write((char *)buffer, size); + outfile.close(); + } else + throw VCLException(OpenFailed, "Cannot create temporary file"); - _video_id = uname; + _video_id = uname; } -Video::Video(const Video &video) -{ - _video_id = video._video_id; +Video::Video(const Video &video) { + _video_id = video._video_id; + _remote = nullptr; - _size = video._size; + _size = video._size; - _fps = video._fps; - _codec = video._codec; + _fps = video._fps; + _codec = video._codec; - _video_id = video.get_video_id(); - _codec = video.get_codec(); + _video_id = video.get_video_id(); + _codec = video.get_codec(); - _flag_stored = video._flag_stored; + _flag_stored = video._flag_stored; - //_frames = video._frames; - _operations = video._operations; + //_frames = video._frames; + _operations = video._operations; - _video_read = video._video_read; + _video_read = video._video_read; - for (const auto& op : video._operations) - _operations.push_back(op); + for (const auto &op : video._operations) + _operations.push_back(op); } -Video& Video::operator=(Video vid) -{ - swap(vid); - return *this; +Video &Video::operator=(Video vid) { + swap(vid); + return *this; } -Video::~Video() -{ - _video_read = nullptr; - _operations.clear(); - _key_frame_decoder.reset(); +Video::~Video() { + _video_read = nullptr; + _operations.clear(); + _key_frame_decoder.reset(); } - /* *********************** */ - /* GET FUNCTIONS */ - /* *********************** */ +/* *********************** */ +/* GET FUNCTIONS */ +/* *********************** */ -std::string Video::get_video_id() const -{ - return _video_id; -} +std::string Video::get_video_id() const { return _video_id; } -Video::Codec Video::get_codec() const -{ - return _codec; -} +Video::Codec Video::get_codec() const { return _codec; } -Image* Video::read_frame(int index) { - if (_video_read == nullptr) { - throw VCLException(UnsupportedOperation, "Video file not opened"); - } +Image *Video::read_frame(int index) { + if (_video_read == nullptr) { + throw VCLException(UnsupportedOperation, "Video file not opened"); + } - Image* pframe = _video_read->read_frame(index); - if (pframe == nullptr) _video_read = nullptr; // Reaching the end, close the input video - return pframe; + Image *pframe = _video_read->read_frame(index); + if (pframe == nullptr) + _video_read = nullptr; // Reaching the end, close the input video + return pframe; } // FIXME video read object is not released correctly. -cv::Mat Video::get_frame(unsigned frame_number) -{ - cv::Mat frame; - - if (_key_frame_decoder == nullptr) { - bool new_read = false; - std::shared_ptr video_read; - //_video_read not initialized, the current function is called directly - if (_video_read == nullptr) { - video_read = std::make_shared(this); - // open the video file - (*video_read)(0); - new_read = true; - } - // _video_read initialized, the current function is called by get_frames - else { - video_read = _video_read; - } - VCL::Image* pframe = video_read->read_frame(frame_number); - if (new_read) { - _video_read = nullptr; - } - if (pframe == nullptr) - throw VCLException(OutOfBounds, "Frame requested is out of bounds"); - - frame = pframe->get_cvmat(); - } - else { - - std::vector frame_list = {frame_number}; - EncodedFrameList list = _key_frame_decoder->decode(frame_list); +cv::Mat Video::get_frame(unsigned frame_number) { + cv::Mat frame; - auto& f = list[0]; - VCL::Image tmp((void*)&f[0], f.length()); - frame = tmp.get_cvmat(); - } - - return frame; -} - -// FIXME video read object is not released correctly. -std::vector Video::get_frames(std::vector frame_list) -{ - std::vector image_list; - - if (frame_list.size() < 1) { - return image_list; - } - - if (_key_frame_decoder == nullptr) { - // Key frame information is not available: video will be decoded using - // OpenCV. - _video_read = std::make_shared(this); - // open the video file - (*_video_read)(0); - - for (const auto& f : frame_list) - image_list.push_back(get_frame(f)); - - _video_read = nullptr; + if (_key_frame_decoder == nullptr) { + bool new_read = false; + std::shared_ptr video_read; + //_video_read not initialized, the current function is called directly + if (_video_read == nullptr) { + video_read = std::make_shared(this); + // open the video file + (*video_read)(0); + new_read = true; } + // _video_read initialized, the current function is called by get_frames else { - // Key frame information is set, video will be partially decoded using - // _key_frame_decoder object. - - EncodedFrameList list = _key_frame_decoder->decode(frame_list); - - for (const auto& f : list) { - VCL::Image tmp((void*)&f[0], f.length()); - image_list.push_back(tmp.get_cvmat()); - } + video_read = _video_read; + } + VCL::Image *pframe = video_read->read_frame(frame_number); + if (new_read) { + _video_read = nullptr; } + if (pframe == nullptr) + throw VCLException(OutOfBounds, "Frame requested is out of bounds"); - return image_list; -} + frame = pframe->get_cvmat(); + } else { -long Video::get_frame_count() -{ - perform_operations(); - return _size.frame_count; -} + std::vector frame_list = {frame_number}; + EncodedFrameList list = _key_frame_decoder->decode(frame_list); -float Video::get_fps() -{ - return _fps; -} + auto &f = list[0]; + VCL::Image tmp((void *)&f[0], f.length()); + frame = tmp.get_cvmat(); + } -cv::Size Video::get_frame_size() -{ - perform_operations(); - cv::Size dims((int) _size.width, - (int) _size.height); - return dims; + return frame; } -Video::VideoSize Video::get_size() -{ - perform_operations(); - return _size; -} +// FIXME video read object is not released correctly. +std::vector Video::get_frames(std::vector frame_list) { + std::vector image_list; -std::vector Video::get_encoded() -{ - if (_flag_stored == false) - throw VCLException(ObjectEmpty, "Object not written"); + if (frame_list.size() < 1) { + return image_list; + } - std::ifstream ifile(_video_id, std::ifstream::in); - ifile.seekg(0, std::ios::end); - size_t encoded_size = (long)ifile.tellg(); - ifile.seekg(0, std::ios::beg); + if (_key_frame_decoder == nullptr) { + // Key frame information is not available: video will be decoded using + // OpenCV. + _video_read = std::make_shared(this); + // open the video file + (*_video_read)(0); - std::vector encoded(encoded_size); + for (const auto &f : frame_list) + image_list.push_back(get_frame(f)); - ifile.read((char*)encoded.data(), encoded_size); - ifile.close(); + _video_read = nullptr; + } else { + // Key frame information is set, video will be partially decoded using + // _key_frame_decoder object. - return encoded; -} + EncodedFrameList list = _key_frame_decoder->decode(frame_list); -const KeyFrameList& Video::get_key_frame_list() -{ - if (_key_frame_list.empty()) { - VCL::KeyFrameParser parser(_video_id); - _key_frame_list = parser.parse(); + for (const auto &f : list) { + VCL::Image tmp((void *)&f[0], f.length()); + image_list.push_back(tmp.get_cvmat()); } + } - set_key_frame_list(_key_frame_list); - return _key_frame_list; + return image_list; } - /* *********************** */ - /* SET FUNCTIONS */ - /* *********************** */ - -void Video::set_video_id(const std::string &video_id) -{ - _video_id = video_id; +long Video::get_frame_count() { + perform_operations(); + return _size.frame_count; } -void Video::set_codec(Video::Codec codec) -{ - _codec = codec; +float Video::get_fps() { return _fps; } + +cv::Size Video::get_frame_size() { + perform_operations(); + cv::Size dims((int)_size.width, (int)_size.height); + return dims; } -void Video::set_dimensions(const cv::Size& dimensions) -{ - _size.height = dimensions.height; - _size.width = dimensions.width; +Video::VideoSize Video::get_size() { + perform_operations(); + return _size; } -void Video::set_key_frame_list(KeyFrameList& key_frames) -{ - if (_key_frame_decoder == nullptr) { - _key_frame_decoder = std::unique_ptr( - new VCL::KeyFrameDecoder(_video_id)); - } +std::vector Video::get_encoded() { + if (_flag_stored == false) + throw VCLException(ObjectEmpty, "Object not written"); - _key_frame_decoder->set_key_frames(key_frames); -} - - /* *********************** */ - /* UTILITIES */ - /* *********************** */ - -void Video::perform_operations() -{ - try - { - // At this point, there are three different potential callees: - // - // - An object is instantiated through the default constructor with - // no name: an exception is thrown as no operations can be applied. - // - // - An object is instantiated through one-arg string constructor, - // but has no operations set explicitely (i.e. when calling - // get_frame_count()): a 'read' operation is pushed to the head of - // the queue. - // - // - An object is instantiated through any of the non-default - // constructors, and has pushed operations explicitely: a 'read' - // operation is pushed to the head of the queue. - if (_operations.empty() || _operations.front()->get_type() != READ) { - //&& !is_read()) { - if (_video_id.empty()) - throw VCLException(OpenFailed, "video_id is not initialized"); - _operations.push_front(std::make_shared(this)); - } - - if (_operations.size() == 1) { - // If only read operation exists, we should add another operation to - // avoid the useless loop. - _operations.push_back(std::make_shared(this, Video::FRAMES, 0, 0, 1)); - } - - for (const auto& op : _operations) { - if ( op == NULL ) - throw VCLException(ObjectEmpty, "Nothing to be done"); - } - - Video::OperationResult res = PASS; - for (int index = 0; res != BREAK; index++) { - for (const auto& op : _operations) { - res = (*op)(index); - if (res != PASS) break; - } - } - - for (const auto& op : _operations) { - op->finalize(); - } - // FIXME Do we need to clear _operations when some exception happened? - // Right now, we assume that we should have another try and hence the - // vector _operations should be kept. - } catch( cv::Exception& e ) { - throw VCLException(OpenCVError, e.what()); - } + std::ifstream ifile(_video_id, std::ifstream::in); + ifile.seekg(0, std::ios::end); + size_t encoded_size = (long)ifile.tellg(); + ifile.seekg(0, std::ios::beg); - _operations.clear(); -} + std::vector encoded(encoded_size); -void Video::swap(Video& rhs) noexcept -{ - using std::swap; + ifile.read((char *)encoded.data(), encoded_size); + ifile.close(); - swap(_video_id, rhs._video_id); - swap(_flag_stored, rhs._flag_stored); - //swap(_frames, rhs._frames); - swap(_size, rhs._size); - swap(_fps, rhs._fps); - swap(_codec, rhs._codec); - swap(_operations, rhs._operations); - swap(_video_read, rhs._video_read); + return encoded; } - /* *********************** */ - /* VIDEO INTERACTION */ - /* *********************** */ +const KeyFrameList &Video::get_key_frame_list() { + if (_key_frame_list.empty()) { + VCL::KeyFrameParser parser(_video_id); + _key_frame_list = parser.parse(); + } -void Video::resize(int width, int height) -{ - _flag_stored = false; - _operations.push_back(std::make_shared(this, cv::Size(width, height))); + set_key_frame_list(_key_frame_list); + return _key_frame_list; } -void Video::interval(Video::Unit u, int start, int stop, int step) -{ - _flag_stored = false; - _operations.push_back(std::make_shared(this, u, start, stop, step)); -} +/* *********************** */ +/* SET FUNCTIONS */ +/* *********************** */ -void Video::crop(const Rectangle &rect) -{ - _flag_stored = false; - _operations.push_back(std::make_shared(this, rect)); -} +void Video::set_video_id(const std::string &video_id) { _video_id = video_id; } -void Video::threshold(int value) -{ - _flag_stored = false; - _operations.push_back(std::make_shared(this, value)); -} +void Video::set_codec(Video::Codec codec) { _codec = codec; } -void Video::store(const std::string &video_id, Video::Codec video_codec) -{ - // out_name cannot be assigned to _video_id here as the read operation - // may be pending and the input file name is needed for the read. - _operations.push_back(std::make_shared(this, video_id, video_codec)); - perform_operations(); +void Video::set_dimensions(const cv::Size &dimensions) { + _size.height = dimensions.height; + _size.width = dimensions.width; } -void Video::store() -{ - if (_codec == NOCODEC || _video_id.empty()) { - throw VCLException(ObjectEmpty, "Cannot write video without codec" - "or ID"); - } - store(_video_id, _codec); -} +void Video::set_key_frame_list(KeyFrameList &key_frames) { + if (_key_frame_decoder == nullptr) { + _key_frame_decoder = + std::unique_ptr(new VCL::KeyFrameDecoder(_video_id)); + } -void Video::delete_video() -{ - if (exists(_video_id)) { - std::remove(_video_id.c_str()); - } + _key_frame_decoder->set_key_frames(key_frames); } - /* *********************** */ - /* READ OPERATION */ - /* *********************** */ +/* *********************** */ +/* UTILITIES */ +/* *********************** */ -Video::Read::~Read() { - if (_inputVideo.isOpened()) { - _inputVideo.release(); - _frames.clear(); - _frame_index_starting = 0; - _frame_index_ending = 0; - _video_id = ""; +void Video::perform_operations() { + try { + // At this point, there are three different potential callees: + // + // - An object is instantiated through the default constructor with + // no name: an exception is thrown as no operations can be applied. + // + // - An object is instantiated through one-arg string constructor, + // but has no operations set explicitely (i.e. when calling + // get_frame_count()): a 'read' operation is pushed to the head of + // the queue. + // + // - An object is instantiated through any of the non-default + // constructors, and has pushed operations explicitely: a 'read' + // operation is pushed to the head of the queue. + if (_operations.empty() || _operations.front()->get_type() != READ) { + //&& !is_read()) { + if (_video_id.empty()) + throw VCLException(OpenFailed, "video_id is not initialized"); + _operations.push_front(std::make_shared(this)); } -} -void Video::Read::finalize() { - reset(); -} - -void Video::Read::open() -{ - _video_id = _video->_video_id; - if (!_inputVideo.open(_video_id)) { - throw VCLException(OpenFailed, - "Could not open the output video for read"); + if (_operations.size() == 1) { + // If only read operation exists, we should add another operation to + // avoid the useless loop. + _operations.push_back( + std::make_shared(this, Video::FRAMES, 0, 0, 1)); } - _video->_fps = static_cast(_inputVideo.get(cv::CAP_PROP_FPS)); - _video->_size.frame_count = static_cast( - _inputVideo.get(cv::CAP_PROP_FRAME_COUNT)); - _video->_size.width = static_cast( - _inputVideo.get(cv::CAP_PROP_FRAME_WIDTH)); - _video->_size.height = static_cast( - _inputVideo.get(cv::CAP_PROP_FRAME_HEIGHT)); - - - // Get Codec Type- Int form - int ex = static_cast(_inputVideo.get(cv::CAP_PROP_FOURCC)); - char fourcc[] = {(char)((ex & 0XFF)), - (char)((ex & 0XFF00) >> 8), - (char)((ex & 0XFF0000) >> 16), - (char)((ex & 0XFF000000) >> 24), - 0}; - - _video->_codec = read_codec(fourcc); - - _video->_video_read = shared_from_this(); -} - -void Video::Read::reset() -{ - if (_inputVideo.isOpened()) { - _inputVideo.release(); - _frames.clear(); - _frame_index_starting = 0; - _frame_index_ending = 0; - _video_id = ""; - - if (_video->_video_read == shared_from_this()) { - _video->_video_read = nullptr; - } + for (const auto &op : _operations) { + if (op == NULL) + throw VCLException(ObjectEmpty, "Nothing to be done"); } -} -void Video::Read::reopen() -{ - reset(); - open(); -} - -VCL::Image* Video::Read::read_frame(int index) -{ - cv::Mat mat; - - if (!_inputVideo.isOpened()) { - open(); - } - - if (index < _frame_index_starting) { // Read the video file all over again - reopen(); // _frame_index_ending = 0; - _frame_index_starting = index; - } - else if (index > _frame_index_starting + 30) { // The cached vector is full - _frames.clear(); - _frame_index_starting = index; + Video::OperationResult res = PASS; + for (int index = 0; res != BREAK; index++) { + for (const auto &op : _operations) { + res = (*op)(index); + if (res != PASS) + break; + } } - // Skip the frames that are too "old" - while (_frame_index_ending < _frame_index_starting) { - _inputVideo >> mat; - if (mat.empty()) return nullptr; - _frame_index_ending++; + for (const auto &op : _operations) { + op->finalize(); } + // FIXME Do we need to clear _operations when some exception happened? + // Right now, we assume that we should have another try and hence the + // vector _operations should be kept. + } catch (cv::Exception &e) { + throw VCLException(OpenCVError, e.what()); + } - // Read the frames with indices up to - while (_frame_index_ending <= index) { - _inputVideo >> mat; - if (mat.empty()) return nullptr; - _frames.push_back(VCL::Image(mat, false)); - _frame_index_ending++; - } + _operations.clear(); +} - return &_frames[index - _frame_index_starting]; +void Video::swap(Video &rhs) noexcept { + using std::swap; + swap(_video_id, rhs._video_id); + swap(_flag_stored, rhs._flag_stored); + // swap(_frames, rhs._frames); + swap(_size, rhs._size); + swap(_fps, rhs._fps); + swap(_codec, rhs._codec); + swap(_operations, rhs._operations); + swap(_video_read, rhs._video_read); } -Video::Codec Video::Read::read_codec(char* fourcc) -{ - std::string codec(fourcc); - std::transform(codec.begin(), codec.end(), codec.begin(), ::tolower); +void Video::set_connection(RemoteConnection *remote) { + if (!remote->connected()) + remote->start(); + + if (!remote->connected()) { + throw VCLException(SystemNotFound, "No remote connection started"); + } - if (codec == "mjpg") - return Codec::MJPG; - else if (codec == "xvid") - return Codec::XVID; - else if (codec == "u263") - return Codec::H263; - else if (codec == "avc1" || codec == "x264") - return Codec::H264; - else - throw VCLException(UnsupportedFormat, codec + " is not supported"); + _remote = remote; + _storage = Storage::AWS; } -Video::OperationResult Video::Read::operator()(int index) -{ - // The video object is changed, reset the InputCapture handler. - if (_video_id != _video->_video_id) { - _video_id = _video->_video_id; - reset(); - } +/* *********************** */ +/* VIDEO INTERACTION */ +/* *********************** */ - if (!_inputVideo.isOpened()) { - open(); - } - if (_video->_size.frame_count <= index) return BREAK; - return PASS; +void Video::resize(int width, int height) { + _flag_stored = false; + _operations.push_back( + std::make_shared(this, cv::Size(width, height))); } - /* *********************** */ - /* WRITE OPERATION */ - /* *********************** */ - -int Video::Write::get_fourcc() -{ - switch(_codec) - { - case Codec::MJPG: - return cv::VideoWriter::fourcc('M', 'J', 'P', 'G'); - case Codec::XVID: - return cv::VideoWriter::fourcc('X', 'V', 'I', 'D'); - case Codec::H263: - return cv::VideoWriter::fourcc('U', '2', '6', '3'); - case Codec::H264: - return cv::VideoWriter::fourcc('X', '2', '6', '4'); - case Codec::AVC1: - return cv::VideoWriter::fourcc('A', 'V', 'C', '1'); - default: - throw VCLException(UnsupportedFormat, std::to_string((int)_codec) + - " is not a valid format"); - } +void Video::interval(Video::Unit u, int start, int stop, int step) { + _flag_stored = false; + _operations.push_back(std::make_shared(this, u, start, stop, step)); } -Video::OperationResult Video::Write::operator()(int index) -{ - VCL::Image* frame = _video->read_frame(index); - if (frame == NULL) return BREAK; +void Video::crop(const Rectangle &rect) { + _flag_stored = false; + _operations.push_back(std::make_shared(this, rect)); +} - if (_last_write == index) return PASS; - else if (_last_write > index) { - // Write the video file all over again. - // Probably some exceptions happened before. - _outputVideo.release(); - _last_write = -1; - } +void Video::threshold(int value) { + _flag_stored = false; + _operations.push_back(std::make_shared(this, value)); +} - if (!_outputVideo.isOpened()) { - _outputVideo.open( - _outname, - get_fourcc(), - _video->_fps, - cv::Size(_video->_size.width, _video->_size.height)); - - if (!_outputVideo.isOpened()) { - throw VCLException(OpenFailed, - "Could not open the output video for write"); - } - } +void Video::store(const std::string &video_id, Video::Codec video_codec) { + // out_name cannot be assigned to _video_id here as the read operation + // may be pending and the input file name is needed for the read. + _operations.push_back(std::make_shared(this, video_id, video_codec)); + perform_operations(); +} +void Video::store() { + if (_codec == NOCODEC || _video_id.empty()) { + throw VCLException(ObjectEmpty, "Cannot write video without codec" + "or ID"); + } + store(_video_id, _codec); +} - _outputVideo << frame->get_cvmat(false); - _frame_count++; - _last_write = index; - return PASS; +void Video::delete_video() { + if (exists(_video_id)) { + std::remove(_video_id.c_str()); + } } -void Video::Write::finalize() -{ - if (!_outputVideo.isOpened()) { - _outputVideo.release(); +/* *********************** */ +/* READ OPERATION */ +/* *********************** */ - _video->_video_id = _outname; - _video->_codec = _codec; - _video->_flag_stored = true; - _video->_size.frame_count = _frame_count; +Video::Read::~Read() { + if (_inputVideo.isOpened()) { + _inputVideo.release(); + _frames.clear(); + _frame_index_starting = 0; + _frame_index_ending = 0; + _video_id = ""; + } +} + +void Video::Read::finalize() { reset(); } + +void Video::Read::open() { + _video_id = _video->_video_id; + if (!_inputVideo.open(_video_id)) { + throw VCLException(OpenFailed, "Could not open the output video for read"); + } + + _video->_fps = static_cast(_inputVideo.get(cv::CAP_PROP_FPS)); + _video->_size.frame_count = + static_cast(_inputVideo.get(cv::CAP_PROP_FRAME_COUNT)); + _video->_size.width = + static_cast(_inputVideo.get(cv::CAP_PROP_FRAME_WIDTH)); + _video->_size.height = + static_cast(_inputVideo.get(cv::CAP_PROP_FRAME_HEIGHT)); + + // Get Codec Type- Int form + int ex = static_cast(_inputVideo.get(cv::CAP_PROP_FOURCC)); + char fourcc[] = {(char)((ex & 0XFF)), (char)((ex & 0XFF00) >> 8), + (char)((ex & 0XFF0000) >> 16), + (char)((ex & 0XFF000000) >> 24), 0}; + + _video->_codec = read_codec(fourcc); + + _video->_video_read = shared_from_this(); +} + +void Video::Read::reset() { + if (_inputVideo.isOpened()) { + _inputVideo.release(); + _frames.clear(); + _frame_index_starting = 0; + _frame_index_ending = 0; + _video_id = ""; + + if (_video->_video_read == shared_from_this()) { + _video->_video_read = nullptr; } + } } -Video::Write::~Write() { - finalize(); +void Video::Read::reopen() { + reset(); + open(); } - /* *********************** */ - /* RESIZE OPERATION */ - /* *********************** */ - -Video::OperationResult Video::Resize::operator()(int index) -{ - VCL::Image* frame = _video->read_frame(index); - if (frame == NULL) return BREAK; - // VCL::Image expect the params (h,w) (contrary to openCV convention) - frame->resize(_size.height, _size.width); - _video->_size.width = _size.width; - _video->_size.height = _size.height; - return PASS; -} - - /* *********************** */ - /* CROP OPERATION */ - /* *********************** */ - -Video::OperationResult Video::Crop::operator()(int index) -{ - VCL::Image* frame = _video->read_frame(index); - if (frame == NULL) return BREAK; - frame->crop(_rect); - _video->_size.width = _rect.width; - _video->_size.height = _rect.height; - return PASS; -} +VCL::Image *Video::Read::read_frame(int index) { + cv::Mat mat; - /* *********************** */ - /* THRESHOLD OPERATION */ - /* *********************** */ + if (!_inputVideo.isOpened()) { + open(); + } + + if (index < _frame_index_starting) { // Read the video file all over again + reopen(); // _frame_index_ending = 0; + _frame_index_starting = index; + } else if (index > _frame_index_starting + 30) { // The cached vector is full + _frames.clear(); + _frame_index_starting = index; + } + + // Skip the frames that are too "old" + while (_frame_index_ending < _frame_index_starting) { + _inputVideo >> mat; + if (mat.empty()) + return nullptr; + _frame_index_ending++; + } + + // Read the frames with indices up to + while (_frame_index_ending <= index) { + _inputVideo >> mat; + if (mat.empty()) + return nullptr; + _frames.push_back(VCL::Image(mat, false)); + _frame_index_ending++; + } + + return &_frames[index - _frame_index_starting]; +} + +Video::Codec Video::Read::read_codec(char *fourcc) { + std::string codec(fourcc); + std::transform(codec.begin(), codec.end(), codec.begin(), ::tolower); + + if (codec == "mjpg") + return Codec::MJPG; + else if (codec == "xvid") + return Codec::XVID; + else if (codec == "u263") + return Codec::H263; + else if (codec == "avc1" || codec == "x264") + return Codec::H264; + else + throw VCLException(UnsupportedFormat, codec + " is not supported"); +} + +Video::OperationResult Video::Read::operator()(int index) { + // The video object is changed, reset the InputCapture handler. + if (_video_id != _video->_video_id) { + _video_id = _video->_video_id; + reset(); + } -Video::OperationResult Video::Threshold::operator()(int index) -{ - VCL::Image* frame = _video->read_frame(index); - if (frame == NULL) return BREAK; - frame->threshold(_threshold); + if (!_inputVideo.isOpened()) { + open(); + } + if (_video->_size.frame_count <= index) + return BREAK; + return PASS; +} + +/* *********************** */ +/* WRITE OPERATION */ +/* *********************** */ + +int Video::Write::get_fourcc() { + switch (_codec) { + case Codec::MJPG: + return cv::VideoWriter::fourcc('M', 'J', 'P', 'G'); + case Codec::XVID: + return cv::VideoWriter::fourcc('X', 'V', 'I', 'D'); + case Codec::H263: + return cv::VideoWriter::fourcc('U', '2', '6', '3'); + case Codec::H264: + return cv::VideoWriter::fourcc('X', '2', '6', '4'); + case Codec::AVC1: + return cv::VideoWriter::fourcc('A', 'V', 'C', '1'); + default: + throw VCLException(UnsupportedFormat, + std::to_string((int)_codec) + " is not a valid format"); + } +} + +Video::OperationResult Video::Write::operator()(int index) { + VCL::Image *frame = _video->read_frame(index); + if (frame == NULL) + return BREAK; + + if (_last_write == index) return PASS; -} + else if (_last_write > index) { + // Write the video file all over again. + // Probably some exceptions happened before. + _outputVideo.release(); + _last_write = -1; + } - /* *********************** */ - /* INTERVAL Operation */ - /* *********************** */ + if (!_outputVideo.isOpened()) { + _outputVideo.open(_outname, get_fourcc(), _video->_fps, + cv::Size(_video->_size.width, _video->_size.height)); -Video::OperationResult Video::Interval::operator()(int index) -{ - if (_u != Video::Unit::FRAMES) { - _fps_updated = false; - throw VCLException(UnsupportedOperation, - "Only Unit::FRAMES supported for interval operation"); + if (!_outputVideo.isOpened()) { + throw VCLException(OpenFailed, + "Could not open the output video for write"); } + } - unsigned nframes = _video->_size.frame_count; + _outputVideo << frame->get_cvmat(false); + _frame_count++; + _last_write = index; + return PASS; +} - if (_start >= nframes) { - _fps_updated = false; - throw VCLException(SizeMismatch, - "Start Frame cannot be greater than number of frames"); - } +void Video::Write::finalize() { + if (_video->_storage == Storage::LOCAL) { + if (!_outputVideo.isOpened()) { + _outputVideo.release(); - if (_stop >= nframes) { - _fps_updated = false; - throw VCLException(SizeMismatch, - "End Frame cannot be greater than number of frames"); + _video->_video_id = _outname; + _video->_codec = _codec; + _video->_flag_stored = true; + _video->_size.frame_count = _frame_count; } - - if (index < _start) return CONTINUE; - if (index >= _stop) return BREAK; - if ( (index - _start) % _step != 0) return CONTINUE; - update_fps(); - return PASS; + } +} + +Video::Write::~Write() { finalize(); } + +/* *********************** */ +/* RESIZE OPERATION */ +/* *********************** */ + +Video::OperationResult Video::Resize::operator()(int index) { + VCL::Image *frame = _video->read_frame(index); + if (frame == NULL) + return BREAK; + // VCL::Image expect the params (h,w) (contrary to openCV convention) + frame->resize(_size.height, _size.width); + _video->_size.width = _size.width; + _video->_size.height = _size.height; + return PASS; +} + +/* *********************** */ +/* CROP OPERATION */ +/* *********************** */ + +Video::OperationResult Video::Crop::operator()(int index) { + VCL::Image *frame = _video->read_frame(index); + if (frame == NULL) + return BREAK; + frame->crop(_rect); + _video->_size.width = _rect.width; + _video->_size.height = _rect.height; + return PASS; +} + +/* *********************** */ +/* THRESHOLD OPERATION */ +/* *********************** */ + +Video::OperationResult Video::Threshold::operator()(int index) { + VCL::Image *frame = _video->read_frame(index); + if (frame == NULL) + return BREAK; + frame->threshold(_threshold); + return PASS; +} + +/* *********************** */ +/* INTERVAL Operation */ +/* *********************** */ + +Video::OperationResult Video::Interval::operator()(int index) { + if (_u != Video::Unit::FRAMES) { + _fps_updated = false; + throw VCLException(UnsupportedOperation, + "Only Unit::FRAMES supported for interval operation"); + } + + unsigned nframes = _video->_size.frame_count; + + if (_start >= nframes) { + _fps_updated = false; + throw VCLException(SizeMismatch, + "Start Frame cannot be greater than number of frames"); + } + + if (_stop >= nframes) { + _fps_updated = false; + throw VCLException(SizeMismatch, + "End Frame cannot be greater than number of frames"); + } + + if (index < _start) + return CONTINUE; + if (index >= _stop) + return BREAK; + if ((index - _start) % _step != 0) + return CONTINUE; + update_fps(); + return PASS; } void Video::Interval::update_fps() { - if (!_fps_updated) { - _video->_fps /= _step; - _fps_updated = true; - } + if (!_fps_updated) { + _video->_fps /= _step; + _fps_updated = true; + } } diff --git a/src/vcl/utils.cc b/src/vcl/utils.cc index 4f626105..4d60b8ee 100644 --- a/src/vcl/utils.cc +++ b/src/vcl/utils.cc @@ -28,111 +28,103 @@ */ #include -#include #include +#include #include -#include "vcl/utils.h" -#include "vcl/Exception.h" #include "../VDMSConfig.h" +#include "vcl/Exception.h" +#include "vcl/utils.h" namespace VCL { - uint64_t rdrand() - { - static const unsigned retry_limit = 10; - unsigned retries = retry_limit; - do { - uint64_t val; - bool r; - __asm("rdrand %0; setc %1" : "=r"(val), "=r"(r)); - if (r) - return val; - } while (--retries); - - throw VCLException(UndefinedException, "Random number not generated\n"); - } - - bool supports_rdrand() - { - const unsigned int flag_rdrand = (1 << 30); - - unsigned int eax, ebx, ecx, edx; - __cpuid(1, eax, ebx, ecx, edx); - - return ((ecx & flag_rdrand) == flag_rdrand); - } - - uint64_t combine(uint64_t a, uint64_t b) - { - int multiplier = 1; - - while (multiplier <= a) { - multiplier *= 10; - } - - return a*multiplier + b; - } - - uint64_t get_uint64() - { - if ( supports_rdrand() ) { - return combine(rdrand(), rdrand()); - } - else { - init_rand; - - return combine(rand(), rand()); - } - } - - std::string get_extension(const std::string &object_id) - { - size_t file_ext = object_id.find_last_of("."); - size_t dir_ext = object_id.find_last_of("/"); - - if ( file_ext != std::string::npos ) { - if ( file_ext > dir_ext + 2 ) - return object_id.substr(file_ext + 1); - else - throw VCLException(ObjectEmpty, object_id + " does not have a valid extension"); - } - else - return ""; - } - - bool exists(const std::string &name) - { - struct stat filestatus; - - return (stat (name.c_str(), &filestatus) == 0); - } - - std::string create_unique(const std::string &path, - const std::string &extension) - { - - std::ostringstream tmp_stream; - for(int i = 0; i < DIRECTORY_LAYERS; i++) - { - tmp_stream << std::internal << std::setfill('0') << std::setw(CHARS_PER_LAYER_NAME) << std::rand() % DIRECTORIES_PER_LAYER << "/" ; - } - - - std::string unique_id; - std::string name; - const char& last = path.back(); - - do { - uint64_t id = get_uint64(); - std::stringstream ss; - ss << std::hex << id; - unique_id = ss.str(); - name = path + std::string((last != '/')? "/":"") + tmp_stream.str() + - unique_id + "." + extension; - - } while (exists(name)); - - return name; - } +uint64_t rdrand() { + static const unsigned retry_limit = 10; + unsigned retries = retry_limit; + do { + uint64_t val; + bool r; + __asm("rdrand %0; setc %1" : "=r"(val), "=r"(r)); + if (r) + return val; + } while (--retries); + + throw VCLException(UndefinedException, "Random number not generated\n"); +} + +bool supports_rdrand() { + const unsigned int flag_rdrand = (1 << 30); + + unsigned int eax, ebx, ecx, edx; + __cpuid(1, eax, ebx, ecx, edx); + + return ((ecx & flag_rdrand) == flag_rdrand); +} + +uint64_t combine(uint64_t a, uint64_t b) { + int multiplier = 1; + + while (multiplier <= a) { + multiplier *= 10; + } + + return a * multiplier + b; +} + +uint64_t get_uint64() { + if (supports_rdrand()) { + return combine(rdrand(), rdrand()); + } else { + init_rand; + + return combine(rand(), rand()); + } +} + +std::string get_extension(const std::string &object_id) { + size_t file_ext = object_id.find_last_of("."); + size_t dir_ext = object_id.find_last_of("/"); + + if (file_ext != std::string::npos) { + if (file_ext > dir_ext + 2) + return object_id.substr(file_ext + 1); + else + throw VCLException(ObjectEmpty, + object_id + " does not have a valid extension"); + } else + return ""; +} + +bool exists(const std::string &name) { + struct stat filestatus; + + return (stat(name.c_str(), &filestatus) == 0); +} + +std::string create_unique(const std::string &path, + const std::string &extension) { + + std::ostringstream tmp_stream; + for (int i = 0; i < DIRECTORY_LAYERS; i++) { + tmp_stream << std::internal << std::setfill('0') + << std::setw(CHARS_PER_LAYER_NAME) + << std::rand() % DIRECTORIES_PER_LAYER << "/"; + } + + std::string unique_id; + std::string name; + const char &last = path.back(); + + do { + uint64_t id = get_uint64(); + std::stringstream ss; + ss << std::hex << id; + unique_id = ss.str(); + name = path + std::string((last != '/') ? "/" : "") + tmp_stream.str() + + unique_id + "." + extension; + + } while (exists(name)); + + return name; } +} // namespace VCL diff --git a/src/vdms.cc b/src/vdms.cc index f50027d0..4692c159 100644 --- a/src/vdms.cc +++ b/src/vdms.cc @@ -34,98 +34,88 @@ */ #include - #include "Server.h" -void printUsage() -{ - std::cout << "Usage: vdms -cfg config-file.json" << std::endl; +void printUsage() { + std::cout << "Usage: vdms -cfg config-file.json" << std::endl; - std::cout << "Usage: vdms -restore db.tar.gz" << std::endl; - exit(0); + std::cout << "Usage: vdms -restore db.tar.gz" << std::endl; + exit(0); } - - -static void* start_request_thread(void* server) -{ - ((VDMS::Server*)(server))->process_requests(); - return NULL; -} -static void* start_replication_thread(void* server){ - ((VDMS::Server*)(server))->auto_replicate_data(); - return NULL; +static void *start_request_thread(void *server) { + ((VDMS::Server *)(server))->process_requests(); + return NULL; } +static void *start_replication_thread(void *server) { + VDMS::Server *srv = (VDMS::Server *)server; + // If replication time is not set, use auto-replication interval + srv->auto_replicate_interval(); - -static void* start_autodelete_thread(void* server) -{ - ((VDMS::Server*)(server))->autodelete_expired_data(); - return NULL; + return NULL; } +static void *start_autodelete_thread(void *server) { + ((VDMS::Server *)(server))->autodelete_expired_data(); + return NULL; +} -int main(int argc, char **argv) -{ - pthread_t request_thread, autodelete_thread, auto_replicate_thread; - int request_thread_flag, autodelete_thread_flag, auto_replcation_flag; - - printf("VDMS Server\n"); - - if (argc != 3 && argc != 1) { - printUsage(); - } - - std::string config_file = "config-vdms.json"; - - if (argc == 3){ - std::string option(argv[1]); +int main(int argc, char **argv) { + pthread_t request_thread, autodelete_thread, auto_replicate_thread; + int request_thread_flag, autodelete_thread_flag, auto_replcation_flag; - if (option != "-cfg" && option!="-restore" && option!="-backup") - printUsage(); - if(option =="-cfg") - config_file = std::string (argv[2]); + printf("VDMS Server\n"); + if (argc != 3 && argc != 1) { + printUsage(); + } + std::string config_file = "config-vdms.json"; - else if (option=="-restore" ){ - void* server; + if (argc == 3) { + std::string option(argv[1]); - std::string db_name(argv[2]); - size_t file_ext1 = db_name.find_last_of("."); + if (option != "-cfg" && option != "-restore" && option != "-backup") + printUsage(); + if (option == "-cfg") + config_file = std::string(argv[2]); - std::string temp_name_1= db_name.substr(0,file_ext1); + else if (option == "-restore") { + void *server; - size_t file_ext2 = temp_name_1.find_last_of("."); + std::string db_name(argv[2]); + size_t file_ext1 = db_name.find_last_of("."); - std::string temp_name_2= temp_name_1.substr(0,file_ext2); + std::string temp_name_1 = db_name.substr(0, file_ext1); - ((VDMS::Server*)(server))->untar_data(db_name); + size_t file_ext2 = temp_name_1.find_last_of("."); - config_file = temp_name_2+".json"; + std::string temp_name_2 = temp_name_1.substr(0, file_ext2); - } + ((VDMS::Server *)(server))->untar_data(db_name); + config_file = temp_name_2 + ".json"; } + } + printf("Server will start processing requests... \n"); + VDMS::Server server(config_file); + // create a thread for processing request and a thread for the autodelete + // timer + request_thread_flag = pthread_create(&request_thread, NULL, + start_request_thread, (void *)(&server)); + autodelete_thread_flag = pthread_create( + &autodelete_thread, NULL, start_autodelete_thread, (void *)(&server)); + auto_replcation_flag = + pthread_create(&auto_replicate_thread, NULL, start_replication_thread, + (void *)(&server)); - printf("Server will start processing requests... \n"); - VDMS::Server server(config_file); - - //create a thread for processing request and a thread for the autodelete timer - request_thread_flag = pthread_create(&request_thread, NULL, start_request_thread, (void*)( &server ) ); - autodelete_thread_flag = pthread_create(&autodelete_thread, NULL, start_autodelete_thread, (void*)( &server ) ); - auto_replcation_flag = pthread_create(&auto_replicate_thread, NULL, start_replication_thread, (void*)( &server ) ); - - - pthread_join(request_thread, NULL); - pthread_join(autodelete_thread, NULL); - pthread_join(auto_replicate_thread, NULL); - - + pthread_join(request_thread, NULL); + pthread_join(autodelete_thread, NULL); + pthread_join(auto_replicate_thread, NULL); - printf("Server shutting down... \n"); + printf("Server shutting down... \n"); - return 0; + return 0; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 06c72f71..0774885e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,7 @@ -cmake_minimum_required (VERSION 3.10) +cmake_minimum_required (VERSION 3.17) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +set(CMAKE_CXX_STANDARD 17) + option(CODE_COVERAGE "Collect coverage" OFF) IF(CODE_COVERAGE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -Wall -coverage -fprofile-arcs -ftest-coverage") @@ -12,11 +15,13 @@ project(tests ) find_package( OpenCV REQUIRED ) find_package( Threads REQUIRED ) +find_package(AWSSDK REQUIRED COMPONENTS core s3) -link_directories(/usr/local/lib /usr/lib/x86_64-linux-gnu/) +link_directories(/usr/local/lib/ /usr/lib/x86_64-linux-gnu/) include_directories( ../src ../include/ + ../include/vcl ../utils/include/ ../src/vcl /usr/include/jsoncpp @@ -33,6 +38,7 @@ add_executable(unit_tests unit_tests/helpers.cc unit_tests/TDBImage_test.cc unit_tests/Image_test.cc + unit_tests/RemoteConnection_test.cc unit_tests/Video_test.cc unit_tests/DescriptorSetAdd_test.cc unit_tests/DescriptorSetClassify_test.cc @@ -68,4 +74,5 @@ target_link_libraries(unit_tests vdms-utils ${CMAKE_THREAD_LIBS_INIT} ${OpenCV_LIBS} + ${AWSSDK_LINK_LIBRARIES} ) diff --git a/tests/cleandbs.sh b/tests/cleandbs.sh index 8e2bf9f8..99fea4e9 100755 --- a/tests/cleandbs.sh +++ b/tests/cleandbs.sh @@ -10,4 +10,4 @@ rm -r vdms rm test_images/tdb_to_jpg.jpg rm test_images/tdb_to_png.png rm test_images/test_image.jpg -rm -r backups +rm -r backups \ No newline at end of file diff --git a/tests/main.cc b/tests/main.cc index eb0f4914..af19c060 100644 --- a/tests/main.cc +++ b/tests/main.cc @@ -4,14 +4,13 @@ This main file will include all other tests #include "gtest/gtest.h" -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); - // To make GoogleTest silent: - // if (true) { - // auto& listeners = ::testing::UnitTest::GetInstance()->listeners(); - // delete listeners.Release(listeners.default_result_printer()); - // } - return RUN_ALL_TESTS(); -} + // To make GoogleTest silent: + // if (true) { + // auto& listeners = ::testing::UnitTest::GetInstance()->listeners(); + // delete listeners.Release(listeners.default_result_printer()); + // } + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/tests/python/TestBoundingBox.py b/tests/python/TestBoundingBox.py index 6ff049dc..d8c50bb7 100644 --- a/tests/python/TestBoundingBox.py +++ b/tests/python/TestBoundingBox.py @@ -26,15 +26,14 @@ import TestCommand -class TestBoundingBox(TestCommand.TestCommand): +class TestBoundingBox(TestCommand.TestCommand): @classmethod def setUpClass(self): self.number_of_inserts = 2 - #Method to insert one bounding box + # Method to insert one bounding box def insertBoundingBox(self, db, props=None): - all_queries = [] bb = {} @@ -62,7 +61,7 @@ def addBoundingBoxwithImage(self, db, numBoxes, imgprops=None): all_queries = [] imgs_arr = [] - fd = open("../test_images/brain.png", 'rb') + fd = open("../test_images/brain.png", "rb") imgs_arr.append(fd.read()) fd.close() @@ -79,8 +78,8 @@ def addBoundingBoxwithImage(self, db, numBoxes, imgprops=None): basename = imgprops["name"] + "_bb_" for x in range(0, numBoxes): bb_coords = {} - bb_coords["x"] = x*10 - bb_coords["y"] = x*10 + bb_coords["x"] = x * 10 + bb_coords["y"] = x * 10 bb_coords["h"] = 100 bb_coords["w"] = 100 @@ -100,10 +99,9 @@ def addBoundingBoxwithImage(self, db, numBoxes, imgprops=None): self.assertEqual(len(response), numBoxes + 1) self.assertEqual(response[0]["AddImage"]["status"], 0) for i in range(0, numBoxes): - self.assertEqual(response[i+1]["AddBoundingBox"]["status"], 0) + self.assertEqual(response[i + 1]["AddBoundingBox"]["status"], 0) def test_addBoundingBox(self): - db = self.create_connection() all_queries = [] @@ -134,7 +132,6 @@ def test_addBoundingBox(self): self.assertEqual(response[i]["AddBoundingBox"]["status"], 0) def test_findBoundingBox(self): - db = self.create_connection() prefix_name = "find_my_bb_" @@ -166,11 +163,14 @@ def test_findBoundingBox(self): self.assertEqual(response[0]["FindBoundingBox"]["status"], 0) self.assertEqual(response[1]["FindBoundingBox"]["status"], 0) - self.assertEqual(response[0]["FindBoundingBox"]["entities"][0]["name"], prefix_name + "0") - self.assertEqual(response[1]["FindBoundingBox"]["entities"][0]["name"], prefix_name + "1") + self.assertEqual( + response[0]["FindBoundingBox"]["entities"][0]["name"], prefix_name + "0" + ) + self.assertEqual( + response[1]["FindBoundingBox"]["entities"][0]["name"], prefix_name + "1" + ) def test_findBoundingBoxCoordinates(self): - db = self.create_connection() prefix_name = "find_my_bb_coords_" @@ -202,19 +202,26 @@ def test_findBoundingBoxCoordinates(self): for i in range(0, self.number_of_inserts): self.assertEqual(response[i]["FindBoundingBox"]["status"], 0) - self.assertEqual(response[i]["FindBoundingBox"]["entities"][0]["_coordinates"]["x"], 10) - self.assertEqual(response[i]["FindBoundingBox"]["entities"][0]["_coordinates"]["y"], 10) - self.assertEqual(response[i]["FindBoundingBox"]["entities"][0]["_coordinates"]["w"], 100) - self.assertEqual(response[i]["FindBoundingBox"]["entities"][0]["_coordinates"]["h"], 100) + self.assertEqual( + response[i]["FindBoundingBox"]["entities"][0]["_coordinates"]["x"], 10 + ) + self.assertEqual( + response[i]["FindBoundingBox"]["entities"][0]["_coordinates"]["y"], 10 + ) + self.assertEqual( + response[i]["FindBoundingBox"]["entities"][0]["_coordinates"]["w"], 100 + ) + self.assertEqual( + response[i]["FindBoundingBox"]["entities"][0]["_coordinates"]["h"], 100 + ) def test_addBoundingBoxWithImage(self): - db = self.create_connection() all_queries = [] imgs_arr = [] - fd = open("../test_images/brain.png", 'rb') + fd = open("../test_images/brain.png", "rb") imgs_arr.append(fd.read()) fd.close() @@ -255,7 +262,6 @@ def test_addBoundingBoxWithImage(self): self.assertEqual(response[1]["AddBoundingBox"]["status"], 0) def test_findBoundingBoxesInImage(self): - db = self.create_connection() img_name = "my_brain_multiple" @@ -290,19 +296,32 @@ def test_findBoundingBoxesInImage(self): self.assertEqual(response[0]["FindImage"]["status"], 0) self.assertEqual(response[1]["FindBoundingBox"]["status"], 0) - self.assertEqual(response[1]["FindBoundingBox"]["returned"], self.number_of_inserts) + self.assertEqual( + response[1]["FindBoundingBox"]["returned"], self.number_of_inserts + ) for i in range(0, self.number_of_inserts): ind = self.number_of_inserts - i - 1 - self.assertEqual(response[1]["FindBoundingBox"]["entities"][i]["_coordinates"]["x"], 10 * ind) - self.assertEqual(response[1]["FindBoundingBox"]["entities"][i]["_coordinates"]["y"], 10 * ind) - self.assertEqual(response[1]["FindBoundingBox"]["entities"][i]["_coordinates"]["w"], 100) - self.assertEqual(response[1]["FindBoundingBox"]["entities"][i]["_coordinates"]["h"], 100) - self.assertEqual(response[1]["FindBoundingBox"]["entities"][i]["name"], "my_brain_multiple_bb_" + str(ind)) - + self.assertEqual( + response[1]["FindBoundingBox"]["entities"][i]["_coordinates"]["x"], + 10 * ind, + ) + self.assertEqual( + response[1]["FindBoundingBox"]["entities"][i]["_coordinates"]["y"], + 10 * ind, + ) + self.assertEqual( + response[1]["FindBoundingBox"]["entities"][i]["_coordinates"]["w"], 100 + ) + self.assertEqual( + response[1]["FindBoundingBox"]["entities"][i]["_coordinates"]["h"], 100 + ) + self.assertEqual( + response[1]["FindBoundingBox"]["entities"][i]["name"], + "my_brain_multiple_bb_" + str(ind), + ) def test_findBoundingBoxByCoordinates(self): - db = self.create_connection() all_queries = [] @@ -330,7 +349,6 @@ def test_findBoundingBoxByCoordinates(self): self.assertEqual(response[0]["FindBoundingBox"]["status"], 0) def test_findBoundingBoxBlob(self): - db = self.create_connection() prefix_name = "my_brain_return_" @@ -367,10 +385,12 @@ def test_findBoundingBoxBlob(self): for i in range(0, self.number_of_inserts): coord = self.number_of_inserts - i - 1 self.assertEqual(response[i]["FindBoundingBox"]["status"], 0) - self.assertEqual(response[i]["FindBoundingBox"]["entities"][0]["name"], prefix_name + str(i) + "_bb_0") + self.assertEqual( + response[i]["FindBoundingBox"]["entities"][0]["name"], + prefix_name + str(i) + "_bb_0", + ) def test_findBoundingBoxBlobComplex(self): - db = self.create_connection() prefix_name = "my_brain_complex_" @@ -413,7 +433,6 @@ def test_findBoundingBoxBlobComplex(self): self.assertIn(test, response[0]["FindBoundingBox"]["entities"]) def test_updateBoundingBox(self): - db = self.create_connection() prefix_name = "update_bb_" @@ -464,10 +483,11 @@ def test_updateBoundingBox(self): response, img_array = db.query(all_queries) self.assertEqual(response[0]["FindBoundingBox"]["status"], 0) - self.assertEqual(response[0]["FindBoundingBox"]["entities"][0]["name"], "updated_bb_0") + self.assertEqual( + response[0]["FindBoundingBox"]["entities"][0]["name"], "updated_bb_0" + ) def test_updateBoundingBoxCoords(self): - db = self.create_connection() prefix_name = "update_bb_" @@ -521,7 +541,15 @@ def test_updateBoundingBoxCoords(self): response, img_array = db.query(all_queries) self.assertEqual(response[0]["FindBoundingBox"]["status"], 0) - self.assertEqual(response[0]["FindBoundingBox"]["entities"][0]["_coordinates"]["x"], 15) - self.assertEqual(response[0]["FindBoundingBox"]["entities"][0]["_coordinates"]["y"], 15) - self.assertEqual(response[0]["FindBoundingBox"]["entities"][0]["_coordinates"]["w"], 75) - self.assertEqual(response[0]["FindBoundingBox"]["entities"][0]["_coordinates"]["h"], 75) + self.assertEqual( + response[0]["FindBoundingBox"]["entities"][0]["_coordinates"]["x"], 15 + ) + self.assertEqual( + response[0]["FindBoundingBox"]["entities"][0]["_coordinates"]["y"], 15 + ) + self.assertEqual( + response[0]["FindBoundingBox"]["entities"][0]["_coordinates"]["w"], 75 + ) + self.assertEqual( + response[0]["FindBoundingBox"]["entities"][0]["_coordinates"]["h"], 75 + ) diff --git a/tests/python/TestCommand.py b/tests/python/TestCommand.py index 37a4b23f..1c9a4110 100644 --- a/tests/python/TestCommand.py +++ b/tests/python/TestCommand.py @@ -30,7 +30,6 @@ class TestCommand(unittest.TestCase): - def __init__(self, *args, **kwargs): super(TestCommand, self).__init__(*args, **kwargs) @@ -40,36 +39,37 @@ def __init__(self, *args, **kwargs): db_up = False attempts = 0 - while(not db_up): + while not db_up: try: db = vdms.vdms() db.connect(self.hostname, self.port) db.disconnect() db_up = True - if (attempts > 0): + if attempts > 0: print("Connection to VDMS successful.") except: - print("Attempt", attempts, - "to connect to VDMS failed, retying...") + print("Attempt", attempts, "to connect to VDMS failed, retying...") attempts += 1 - time.sleep(1) # sleeps 1 second + time.sleep(1) # sleeps 1 second if attempts > 10: print("Failed to connect to VDMS after 10 attempts") exit() def create_connection(self): - db = vdms.vdms() db.connect(self.hostname, self.port) return db - def addEntity(self, class_name, properties=None, - constraints=None, - blob = False, # Generic blob - check_status=True): - + def addEntity( + self, + class_name, + properties=None, + constraints=None, + blob=False, # Generic blob + check_status=True, + ): addEntity = {} addEntity["class"] = class_name @@ -90,7 +90,7 @@ def addEntity(self, class_name, properties=None, response, res_arr = db.query(all_queries) else: blob_arr = [] - fd = open("../test_images/brain.png", 'rb') + fd = open("../test_images/brain.png", "rb") blob_arr.append(fd.read()) fd.close() diff --git a/tests/python/TestConnections.py b/tests/python/TestConnections.py index 8aee62d0..66e5064c 100644 --- a/tests/python/TestConnections.py +++ b/tests/python/TestConnections.py @@ -27,10 +27,9 @@ from threading import Thread import TestCommand -class TestConnections(TestCommand.TestCommand): +class TestConnections(TestCommand.TestCommand): def test_FindEntity_link_constraints_float(self): - db = self.create_connection() props = {} @@ -38,22 +37,25 @@ def test_FindEntity_link_constraints_float(self): props["lastname"] = "Bonachon" props["age"] = 29 - response, arr = self.addEntity("felcflo_People", properties=props, - check_status=True) + response, arr = self.addEntity( + "felcflo_People", properties=props, check_status=True + ) props = {} props["type"] = "foo" props["name"] = "alligator" - response, arr = self.addEntity("felcflo_foo", properties=props, - check_status=True) + response, arr = self.addEntity( + "felcflo_foo", properties=props, check_status=True + ) props = {} props["type"] = "foo" props["name"] = "cat" - response, arr = self.addEntity("felcflo_foo", properties=props, - check_status=True) + response, arr = self.addEntity( + "felcflo_foo", properties=props, check_status=True + ) all_queries = [] @@ -64,7 +66,7 @@ def test_FindEntity_link_constraints_float(self): "name": ["==", "Jon"], "lastname": ["==", "Bonachon"], }, - "_ref": 2 + "_ref": 2, } } all_queries.append(fE) @@ -72,10 +74,8 @@ def test_FindEntity_link_constraints_float(self): fE = { "FindEntity": { "class": "felcflo_foo", - "constraints": { - "name": ["==", "alligator"] - }, - "_ref": 3 + "constraints": {"name": ["==", "alligator"]}, + "_ref": 3, } } all_queries.append(fE) @@ -83,38 +83,28 @@ def test_FindEntity_link_constraints_float(self): fE = { "FindEntity": { "class": "felcflo_foo", - "constraints": { - "name": ["==", "cat"] - }, - "_ref": 4 + "constraints": {"name": ["==", "cat"]}, + "_ref": 4, } } all_queries.append(fE) aC = { - "AddConnection": { "class": "foo_connection", "ref1": 2, "ref2": 3, - "properties":{ - "name": "best_type_of_connection", - "probablity": 0.3 - } + "properties": {"name": "best_type_of_connection", "probablity": 0.3}, } } all_queries.append(aC) aC = { - "AddConnection": { "class": "foo_connection", "ref1": 2, "ref2": 4, - "properties":{ - "name": "best_type_of_connection", - "probablity": 0.6 - } + "properties": {"name": "best_type_of_connection", "probablity": 0.6}, } } all_queries.append(aC) @@ -133,9 +123,7 @@ def test_FindEntity_link_constraints_float(self): "FindEntity": { "class": "felcflo_People", "_ref": 1, - "results": { - "list": ["name", "lastname"] - } + "results": {"list": ["name", "lastname"]}, } } all_queries.append(fE) @@ -147,13 +135,10 @@ def test_FindEntity_link_constraints_float(self): "ref": 1, "constraints": { "probablity": [">=", 0.5], - "name": ["==", "best_type_of_connection"] - } - + "name": ["==", "best_type_of_connection"], + }, }, - "results": { - "list": ["name"] - } + "results": {"list": ["name"]}, } } all_queries.append(fE) @@ -169,9 +154,7 @@ def test_FindEntity_link_constraints_float(self): "FindEntity": { "class": "felcflo_People", "_ref": 1, - "results": { - "list": ["name", "lastname"] - } + "results": {"list": ["name", "lastname"]}, } } all_queries.append(fE) @@ -183,13 +166,10 @@ def test_FindEntity_link_constraints_float(self): "ref": 1, "constraints": { "probablity": [">=", 0.1], - "name": ["==", "best_type_of_connection"] - } - + "name": ["==", "best_type_of_connection"], + }, }, - "results": { - "list": ["name"] - } + "results": {"list": ["name"]}, } } all_queries.append(fE) @@ -203,9 +183,7 @@ def test_FindEntity_link_constraints_float(self): "FindEntity": { "class": "felcflo_People", "_ref": 1, - "results": { - "list": ["name", "lastname"] - } + "results": {"list": ["name", "lastname"]}, } } all_queries.append(fE) @@ -217,13 +195,10 @@ def test_FindEntity_link_constraints_float(self): "ref": 1, "constraints": { "probablity": [">=", 1.0], - "name": ["==", "best_type_of_connection"] - } - + "name": ["==", "best_type_of_connection"], + }, }, - "results": { - "list": ["name"] - } + "results": {"list": ["name"]}, } } all_queries.append(fE) @@ -232,7 +207,6 @@ def test_FindEntity_link_constraints_float(self): self.assertEqual(len(response[1]["FindEntity"]["entities"]), 0) def test_FindEntity_link_constraints_string(self): - db = self.create_connection() props = {} @@ -240,22 +214,25 @@ def test_FindEntity_link_constraints_string(self): props["lastname"] = "Bonachon" props["age"] = 29 - response, arr = self.addEntity("felcstr_People", properties=props, - check_status=True) + response, arr = self.addEntity( + "felcstr_People", properties=props, check_status=True + ) props = {} props["type"] = "foo" props["name"] = "alligator" - response, arr = self.addEntity("felcstr_foo", properties=props, - check_status=True) + response, arr = self.addEntity( + "felcstr_foo", properties=props, check_status=True + ) props = {} props["type"] = "foo" props["name"] = "cat" - response, arr = self.addEntity("felcstr_foo", properties=props, - check_status=True) + response, arr = self.addEntity( + "felcstr_foo", properties=props, check_status=True + ) all_queries = [] @@ -266,7 +243,7 @@ def test_FindEntity_link_constraints_string(self): "name": ["==", "Jon"], "lastname": ["==", "Bonachon"], }, - "_ref": 2 + "_ref": 2, } } all_queries.append(fE) @@ -274,10 +251,8 @@ def test_FindEntity_link_constraints_string(self): fE = { "FindEntity": { "class": "felcstr_foo", - "constraints": { - "name": ["==", "alligator"] - }, - "_ref": 3 + "constraints": {"name": ["==", "alligator"]}, + "_ref": 3, } } all_queries.append(fE) @@ -285,38 +260,28 @@ def test_FindEntity_link_constraints_string(self): fE = { "FindEntity": { "class": "felcstr_foo", - "constraints": { - "name": ["==", "cat"] - }, - "_ref": 4 + "constraints": {"name": ["==", "cat"]}, + "_ref": 4, } } all_queries.append(fE) aC = { - "AddConnection": { "class": "foo_connection", "ref1": 2, "ref2": 3, - "properties":{ - "name": "best_type_of_connection_1", - "probablity": 0.3 - } + "properties": {"name": "best_type_of_connection_1", "probablity": 0.3}, } } all_queries.append(aC) aC = { - "AddConnection": { "class": "foo_connection", "ref1": 2, "ref2": 4, - "properties":{ - "name": "best_type_of_connection", - "probablity": 0.6 - } + "properties": {"name": "best_type_of_connection", "probablity": 0.6}, } } all_queries.append(aC) @@ -335,9 +300,7 @@ def test_FindEntity_link_constraints_string(self): "FindEntity": { "class": "felcstr_People", "_ref": 1, - "results": { - "list": ["name", "lastname"] - } + "results": {"list": ["name", "lastname"]}, } } all_queries.append(fE) @@ -347,14 +310,9 @@ def test_FindEntity_link_constraints_string(self): "class": "felcstr_foo", "link": { "ref": 1, - "constraints": { - "name": ["==", "best_type_of_connection_1"] - } - + "constraints": {"name": ["==", "best_type_of_connection_1"]}, }, - "results": { - "list": ["name"] - } + "results": {"list": ["name"]}, } } all_queries.append(fE) @@ -370,9 +328,7 @@ def test_FindEntity_link_constraints_string(self): "FindEntity": { "class": "felcstr_People", "_ref": 1, - "results": { - "list": ["name", "lastname"] - } + "results": {"list": ["name", "lastname"]}, } } all_queries.append(fE) @@ -382,13 +338,9 @@ def test_FindEntity_link_constraints_string(self): "class": "felcstr_foo", "link": { "ref": 1, - "constraints": { - "name": [">=", "best_type_of_connection"] - } + "constraints": {"name": [">=", "best_type_of_connection"]}, }, - "results": { - "list": ["name"] - } + "results": {"list": ["name"]}, } } all_queries.append(fE) @@ -402,9 +354,7 @@ def test_FindEntity_link_constraints_string(self): "FindEntity": { "class": "felcstr_People", "_ref": 1, - "results": { - "list": ["name", "lastname"] - } + "results": {"list": ["name", "lastname"]}, } } all_queries.append(fE) @@ -414,13 +364,9 @@ def test_FindEntity_link_constraints_string(self): "class": "felcstr_foo", "link": { "ref": 1, - "constraints": { - "name": ["<", "best_type_of_connection"] - } + "constraints": {"name": ["<", "best_type_of_connection"]}, }, - "results": { - "list": ["name"] - } + "results": {"list": ["name"]}, } } all_queries.append(fE) @@ -434,9 +380,7 @@ def test_FindEntity_link_constraints_string(self): "FindEntity": { "class": "felcstr_People", "_ref": 1, - "results": { - "list": ["name", "lastname"] - } + "results": {"list": ["name", "lastname"]}, } } all_queries.append(fE) @@ -446,14 +390,9 @@ def test_FindEntity_link_constraints_string(self): "class": "felcstr_foo", "link": { "ref": 1, - "constraints": { - "name": ["==", "best_type_of_connection"] - } - + "constraints": {"name": ["==", "best_type_of_connection"]}, }, - "results": { - "list": ["name"] - } + "results": {"list": ["name"]}, } } all_queries.append(fE) diff --git a/tests/python/TestDescriptors.py b/tests/python/TestDescriptors.py index 3924b937..7326d22a 100644 --- a/tests/python/TestDescriptors.py +++ b/tests/python/TestDescriptors.py @@ -27,10 +27,9 @@ import TestCommand import numpy as np -class TestDescriptors(TestCommand.TestCommand): +class TestDescriptors(TestCommand.TestCommand): def addSet(self, name, dim, metric, engine): - db = self.create_connection() all_queries = [] @@ -52,14 +51,13 @@ def addSet(self, name, dim, metric, engine): self.assertEqual(response[0]["AddDescriptorSet"]["status"], 0) def test_addSet(self): - db = self.create_connection() all_queries = [] descriptor_set = {} descriptor_set["name"] = "features_xd" - descriptor_set["dimensions"] = 1024*4 + descriptor_set["dimensions"] = 1024 * 4 query = {} query["AddDescriptorSet"] = descriptor_set @@ -72,7 +70,6 @@ def test_addSet(self): self.assertEqual(response[0]["AddDescriptorSet"]["status"], 0) def test_addSetAndDescriptors(self): - db = self.create_connection() all_queries = [] @@ -97,7 +94,7 @@ def test_addSetAndDescriptors(self): descriptor_blob = [] x = np.zeros(dims) - x = x.astype('float32') + x = x.astype("float32") # print type(x[0]) # print "size: ", len(x.tobytes())/4 descriptor_blob.append(x.tobytes()) @@ -116,7 +113,6 @@ def test_addSetAndDescriptors(self): self.assertEqual(response[0]["AddDescriptor"]["status"], 0) def test_addSetAndDescriptorsDimMismatch(self): - db = self.create_connection() all_queries = [] @@ -140,8 +136,8 @@ def test_addSetAndDescriptorsDimMismatch(self): all_queries = [] descriptor_blob = [] - x = np.zeros(dims//2) - x = x.astype('float32') + x = np.zeros(dims // 2) + x = x.astype("float32") # print type(x[0]) # print "size: ", len(x.tobytes())/4 descriptor_blob.append(x.tobytes()) @@ -165,7 +161,7 @@ def test_addSetAndDescriptorsDimMismatch(self): descriptor_blob = [] x = np.zeros(dims)[:-1] - x = x.astype('float32') + x = x.astype("float32") # print type(x[0]) # print "size: ", len(x.tobytes())/4 descriptor_blob.append(x.tobytes()) @@ -185,7 +181,6 @@ def test_addSetAndDescriptorsDimMismatch(self): self.assertEqual(response[0]["info"], "Blob Dimensions Mismatch") def test_addDescriptorsx1000(self): - db = self.create_connection() all_queries = [] @@ -208,12 +203,12 @@ def test_addDescriptorsx1000(self): all_queries = [] descriptor_blob = [] - total = 2; + total = 2 - for i in range(1,total): + for i in range(1, total): x = np.ones(dims) - x[2] = 2.34 + i*20 - x = x.astype('float32') + x[2] = 2.34 + i * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) descriptor = {} @@ -228,11 +223,10 @@ def test_addDescriptorsx1000(self): response, img_array = db.query(all_queries, [descriptor_blob]) # Check success - for x in range(0,total-1): + for x in range(0, total - 1): self.assertEqual(response[x]["AddDescriptor"]["status"], 0) def test_classifyDescriptor(self): - db = self.create_connection() all_queries = [] @@ -255,16 +249,16 @@ def test_classifyDescriptor(self): all_queries = [] descriptor_blob = [] - total = 2; + total = 2 class_counter = -1 - for i in range(0,total-1): - if ((i % 4) == 0): + for i in range(0, total - 1): + if (i % 4) == 0: class_counter += 1 x = np.ones(dims) - x[2] = 2.34 + i*20 - x = x.astype('float32') + x[2] = 2.34 + i * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) descriptor = {} @@ -279,23 +273,22 @@ def test_classifyDescriptor(self): response, img_array = db.query(all_queries, [descriptor_blob]) # Check success - for x in range(0,total-1): + for x in range(0, total - 1): self.assertEqual(response[x]["AddDescriptor"]["status"], 0) - descriptor = {} descriptor["set"] = set_name query = {} query["ClassifyDescriptor"] = descriptor - for i in range(2, total//10, 4): + for i in range(2, total // 10, 4): all_queries = [] descriptor_blob = [] x = np.ones(dims) - x[2] = 2.34 + i*20 # Calculated to be of class1 - x = x.astype('float32') + x[2] = 2.34 + i * 20 # Calculated to be of class1 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) all_queries.append(query) @@ -304,5 +297,6 @@ def test_classifyDescriptor(self): # Check success self.assertEqual(response[0]["ClassifyDescriptor"]["status"], 0) - self.assertEqual(response[0]["ClassifyDescriptor"] - ["label"], "class" + str(int(i/4))) + self.assertEqual( + response[0]["ClassifyDescriptor"]["label"], "class" + str(int(i / 4)) + ) diff --git a/tests/python/TestEngineDescriptors.py b/tests/python/TestEngineDescriptors.py index ef2a5db9..15772ed3 100644 --- a/tests/python/TestEngineDescriptors.py +++ b/tests/python/TestEngineDescriptors.py @@ -27,10 +27,9 @@ import TestCommand import numpy as np -class TestDescriptors(TestCommand.TestCommand): +class TestDescriptors(TestCommand.TestCommand): def addSet(self, name, dim, metric, engine): - db = self.create_connection() all_queries = [] @@ -52,7 +51,6 @@ def addSet(self, name, dim, metric, engine): self.assertEqual(response[0]["AddDescriptorSet"]["status"], 0) def test_addDifferentSets(self): - self.addSet("128-L2-FaissFlat", 128, "L2", "FaissFlat") self.addSet("128-IP-FaissFlat", 128, "IP", "FaissFlat") self.addSet("128-L2-FaissIVFFlat", 128, "L2", "FaissIVFFlat") @@ -67,7 +65,6 @@ def test_addDifferentSets(self): self.addSet("4075-L2-TileDBDense", 4075, "L2", "TileDBDense") def test_addDescriptorsx1000FaissIVFFlat(self): - db = self.create_connection() all_queries = [] @@ -92,12 +89,12 @@ def test_addDescriptorsx1000FaissIVFFlat(self): all_queries = [] descriptor_blob = [] - total =2; + total = 2 - for i in range(1,total): + for i in range(1, total): x = np.ones(dims) - x[2] = 2.34 + i*20 - x = x.astype('float32') + x[2] = 2.34 + i * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) descriptor = {} @@ -112,12 +109,10 @@ def test_addDescriptorsx1000FaissIVFFlat(self): response, img_array = db.query(all_queries, [descriptor_blob]) # Check success - for x in range(0,total-1): + for x in range(0, total - 1): self.assertEqual(response[x]["AddDescriptor"]["status"], 0) - def test_addDescriptorsx1000TileDBSparse(self): - db = self.create_connection() all_queries = [] @@ -142,12 +137,12 @@ def test_addDescriptorsx1000TileDBSparse(self): all_queries = [] descriptor_blob = [] - total = 2; + total = 2 - for i in range(1,total): + for i in range(1, total): x = np.ones(dims) - x[2] = 2.34 + i*20 - x = x.astype('float32') + x[2] = 2.34 + i * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) descriptor = {} @@ -162,11 +157,10 @@ def test_addDescriptorsx1000TileDBSparse(self): response, img_array = db.query(all_queries, [descriptor_blob]) # Check success - for x in range(0,total-1): + for x in range(0, total - 1): self.assertEqual(response[x]["AddDescriptor"]["status"], 0) def test_addDescriptorsx1000TileDBDense(self): - db = self.create_connection() all_queries = [] @@ -192,12 +186,12 @@ def test_addDescriptorsx1000TileDBDense(self): all_queries = [] descriptor_blob = [] - total = 2; + total = 2 - for i in range(1,total): + for i in range(1, total): x = np.ones(dims) - x[2] = 2.34 + i*20 - x = x.astype('float32') + x[2] = 2.34 + i * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) descriptor = {} @@ -212,5 +206,5 @@ def test_addDescriptorsx1000TileDBDense(self): response, img_array = db.query(all_queries, [descriptor_blob]) # Check success - for x in range(0,total-1): + for x in range(0, total - 1): self.assertEqual(response[x]["AddDescriptor"]["status"], 0) diff --git a/tests/python/TestEntities.py b/tests/python/TestEntities.py index 481f80d6..06be0826 100644 --- a/tests/python/TestEntities.py +++ b/tests/python/TestEntities.py @@ -27,18 +27,18 @@ from threading import Thread import TestCommand -class TestEntities(TestCommand.TestCommand): +class TestEntities(TestCommand.TestCommand): def addSingleEntity(self, thID, results): - props = {} props["name"] = "Luis" props["lastname"] = "Ferro" props["age"] = 27 props["threadid"] = thID - response, arr = self.addEntity("AwesomePeople", properties=props, - check_status=False) + response, arr = self.addEntity( + "AwesomePeople", properties=props, check_status=False + ) try: self.assertEqual(response[0]["AddEntity"]["status"], 0) @@ -48,11 +48,10 @@ def addSingleEntity(self, thID, results): results[thID] = 0 def findEntity(self, thID, results): - db = self.create_connection() constraints = {} - constraints["threadid"] = ["==",thID] + constraints["threadid"] = ["==", thID] findEntity = {} findEntity["constraints"] = constraints @@ -71,25 +70,23 @@ def findEntity(self, thID, results): response, res_arr = db.query(all_queries) try: - self.assertEqual(response[0]["FindEntity"]["status"], 0) - self.assertEqual(response[0]["FindEntity"]["entities"][0] - ["lastname"], "Ferro") - self.assertEqual(response[0]["FindEntity"]["entities"][0] - ["threadid"], thID) + self.assertEqual( + response[0]["FindEntity"]["entities"][0]["lastname"], "Ferro" + ) + self.assertEqual(response[0]["FindEntity"]["entities"][0]["threadid"], thID) except: results[thID] = -1 results[thID] = 0 def test_runMultipleAdds(self): - # Test concurrent AddEntities concurrency = 32 thread_arr = [] results = [None] * concurrency - for i in range(0,concurrency): - thread_add = Thread(target=self.addSingleEntity,args=(i, results) ) + for i in range(0, concurrency): + thread_add = Thread(target=self.addSingleEntity, args=(i, results)) thread_add.start() thread_arr.append(thread_add) @@ -97,7 +94,7 @@ def test_runMultipleAdds(self): error_counter = 0 for th in thread_arr: th.join() - if (results[idx] == -1): + if results[idx] == -1: error_counter += 1 idx += 1 @@ -106,23 +103,22 @@ def test_runMultipleAdds(self): thread_arr = [] # Tests concurrent AddEntities and FindEntities (that should exists) - results = [None] * concurrency * 2 - for i in range(0,concurrency): + results = [None] * concurrency * 2 + for i in range(0, concurrency): addidx = concurrency + i - thread_add = Thread(target=self.addSingleEntity,args=(addidx, results) ) + thread_add = Thread(target=self.addSingleEntity, args=(addidx, results)) thread_add.start() thread_arr.append(thread_add) - thread_find = Thread( - target=self.findEntity,args=(i, results) ) + thread_find = Thread(target=self.findEntity, args=(i, results)) thread_find.start() thread_arr.append(thread_find) idx = 0 error_counter = 0 for th in thread_arr: - th.join(); - if (results[idx] == -1): + th.join() + if results[idx] == -1: error_counter += 1 idx += 1 @@ -130,9 +126,9 @@ def test_runMultipleAdds(self): self.assertEqual(error_counter, 0) def test_addFindEntity(self): - results = [None] * 1 - self.addSingleEntity(0, results); - self.findEntity(0, results); + results = [None] * 1 + self.addSingleEntity(0, results) + self.findEntity(0, results) def test_addEntityWithLink(self): db = self.create_connection() @@ -186,11 +182,7 @@ def test_addfindEntityWrongConstraints(self): all_queries = [] - props = { - "name": "Luis", - "lastname": "Ferro", - "age": 25 - } + props = {"name": "Luis", "lastname": "Ferro", "age": 25} addEntity = {} addEntity["_ref"] = 32 addEntity["properties"] = props @@ -208,14 +200,12 @@ def test_addfindEntityWrongConstraints(self): all_queries = [] # this format is invalid, as each constraint must be an array - constraints = { - "name": "Luis" - } + constraints = {"name": "Luis"} entity = {} entity["constraints"] = constraints entity["class"] = "SomePeople" - entity["results"] = {'count': ''} + entity["results"] = {"count": ""} query = {} query["FindEntity"] = entity @@ -225,13 +215,12 @@ def test_addfindEntityWrongConstraints(self): response, blob_arr = db.query(all_queries) self.assertEqual(response[0]["status"], -1) - self.assertEqual(response[0]["info"], - "Constraint for property 'name' must be an array") + self.assertEqual( + response[0]["info"], "Constraint for property 'name' must be an array" + ) # Another invalid format - constraints = { - "name": [] - } + constraints = {"name": []} entity["constraints"] = constraints all_queries = [] all_queries.append(query) @@ -239,19 +228,19 @@ def test_addfindEntityWrongConstraints(self): response, blob_arr = db.query(all_queries) self.assertEqual(response[0]["status"], -1) - self.assertEqual(response[0]["info"], - "Constraint for property 'name' must be an array of size 2 or 4"); + self.assertEqual( + response[0]["info"], + "Constraint for property 'name' must be an array of size 2 or 4", + ) def test_FindWithSortKey(self): - db = self.create_connection() all_queries = [] number_of_inserts = 10 - for i in range(0,number_of_inserts): - + for i in range(0, number_of_inserts): props = {} props["name"] = "entity_" + str(i) props["id"] = i @@ -293,15 +282,13 @@ def test_FindWithSortKey(self): self.assertEqual(response[0]["FindEntity"]["entities"][i]["id"], i) def test_FindWithSortBlock(self): - db = self.create_connection() all_queries = [] number_of_inserts = 10 - for i in range(0,number_of_inserts): - + for i in range(0, number_of_inserts): props = {} props["name"] = "entity_" + str(i) props["id"] = i @@ -369,5 +356,7 @@ def test_FindWithSortBlock(self): self.assertEqual(response[0]["FindEntity"]["status"], 0) for i in range(0, number_of_inserts): - self.assertEqual(response[0]["FindEntity"]["entities"][i]["id"], - number_of_inserts - 1 - i) + self.assertEqual( + response[0]["FindEntity"]["entities"][i]["id"], + number_of_inserts - 1 - i, + ) diff --git a/tests/python/TestEntitiesBlobs.py b/tests/python/TestEntitiesBlobs.py index 7116d9eb..cbfd7477 100644 --- a/tests/python/TestEntitiesBlobs.py +++ b/tests/python/TestEntitiesBlobs.py @@ -26,10 +26,9 @@ import TestCommand -class TestEntitiesBlob(TestCommand.TestCommand): +class TestEntitiesBlob(TestCommand.TestCommand): def test_addEntityWithBlob(self, thID=0): - db = self.create_connection() props = {} @@ -50,7 +49,7 @@ def test_addEntityWithBlob(self, thID=0): all_queries.append(query) blob_arr = [] - fd = open("../test_images/brain.png", 'rb') + fd = open("../test_images/brain.png", "rb") blob_arr.append(fd.read()) fd.close() @@ -59,7 +58,6 @@ def test_addEntityWithBlob(self, thID=0): self.assertEqual(response[0]["AddEntity"]["status"], 0) def test_addEntityWithBlobNoBlob(self, thID=0): - db = self.create_connection() props = {} @@ -82,11 +80,9 @@ def test_addEntityWithBlobNoBlob(self, thID=0): response, res_arr = db.query(all_queries) self.assertEqual(response[0]["status"], -1) - self.assertEqual(response[0]["info"], - "Expected blobs: 1. Received blobs: 0") + self.assertEqual(response[0]["info"], "Expected blobs: 1. Received blobs: 0") def test_addEntityWithBlobAndFind(self, thID=0): - db = self.create_connection() props = {} @@ -107,7 +103,7 @@ def test_addEntityWithBlobAndFind(self, thID=0): all_queries.append(query) blob_arr = [] - fd = open("../test_images/brain.png", 'rb') + fd = open("../test_images/brain.png", "rb") blob_arr.append(fd.read()) fd.close() @@ -140,4 +136,3 @@ def test_addEntityWithBlobAndFind(self, thID=0): self.assertEqual(len(res_arr), len(blob_arr)) self.assertEqual(len(res_arr[0]), len(blob_arr[0])) self.assertEqual((res_arr[0]), (blob_arr[0])) - diff --git a/tests/python/TestFindDescriptors.py b/tests/python/TestFindDescriptors.py index 4db55ea2..ba3d0c8f 100644 --- a/tests/python/TestFindDescriptors.py +++ b/tests/python/TestFindDescriptors.py @@ -28,10 +28,9 @@ import numpy as np import unittest -class TestFindDescriptors(TestCommand.TestCommand): +class TestFindDescriptors(TestCommand.TestCommand): def create_set_and_insert(self, set_name, dims, total, labels=True): - db = self.create_connection() all_queries = [] @@ -53,13 +52,13 @@ def create_set_and_insert(self, set_name, dims, total, labels=True): descriptor_blob = [] class_counter = -1 - for i in range(0,total): - if ((i % 4) == 0): + for i in range(0, total): + if (i % 4) == 0: class_counter += 1 x = np.ones(dims) - x[2] = 2.34 + i*20 - x = x.astype('float32') + x[2] = 2.34 + i * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) descriptor = {} @@ -80,12 +79,11 @@ def create_set_and_insert(self, set_name, dims, total, labels=True): response, img_array = db.query(all_queries, [descriptor_blob]) # Check success - for x in range(0,total): + for x in range(0, total): self.assertEqual(response[x]["AddDescriptor"]["status"], 0) # @unittest.skip("Skipping class until fixed") def test_findDescByConstraints(self): - # Add Set set_name = "features_128d_4_findbyConst" dims = 128 @@ -104,7 +102,9 @@ def test_findDescByConstraints(self): finddescriptor["constraints"] = constraints results = {} - results["list"] = ["myid",] + results["list"] = [ + "myid", + ] finddescriptor["results"] = results query = {} @@ -118,12 +118,10 @@ def test_findDescByConstraints(self): # Check success self.assertEqual(response[0]["FindDescriptor"]["status"], 0) self.assertEqual(response[0]["FindDescriptor"]["returned"], 1) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][0]["myid"], 202) + self.assertEqual(response[0]["FindDescriptor"]["entities"][0]["myid"], 202) # @unittest.skip("Skipping class until fixed") def test_findDescUnusedRef(self): - # Add Set set_name = "features_128d_4_findunusedRef" dims = 128 @@ -160,7 +158,6 @@ def test_findDescUnusedRef(self): # @unittest.skip("Skipping class until fixed") def test_findDescByConst_get_id(self): - # Add Set set_name = "features_128d_4_findDescriptors_id" dims = 128 @@ -193,12 +190,10 @@ def test_findDescByConst_get_id(self): # Check success self.assertEqual(response[0]["FindDescriptor"]["status"], 0) self.assertEqual(response[0]["FindDescriptor"]["returned"], 1) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][0]["myid"], 202) + self.assertEqual(response[0]["FindDescriptor"]["entities"][0]["myid"], 202) # @unittest.skip("Skipping class until fixed") def test_findDescByConst_blobTrue(self): - # Add Set set_name = "features_128d_4_findDescriptors_id_blob" dims = 128 @@ -232,14 +227,12 @@ def test_findDescByConst_blobTrue(self): # Check success self.assertEqual(response[0]["FindDescriptor"]["status"], 0) self.assertEqual(response[0]["FindDescriptor"]["returned"], 1) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][0]["myid"], 202) + self.assertEqual(response[0]["FindDescriptor"]["entities"][0]["myid"], 202) self.assertEqual(len(fv_array), 1) - self.assertEqual(len(fv_array[0]), dims*4) + self.assertEqual(len(fv_array[0]), dims * 4) # @unittest.skip("Skipping class until fixed") def test_findDescByConst_multiple_blobTrue(self): - # Add Set set_name = "features_128d_4_findDescriptors_m_blob" dims = 128 @@ -276,11 +269,10 @@ def test_findDescByConst_multiple_blobTrue(self): self.assertEqual(response[0]["FindDescriptor"]["returned"], 3) self.assertEqual(response[0]["FindDescriptor"]["entities"][1]["myid"], 201) self.assertEqual(len(fv_array), 3) - self.assertEqual(len(fv_array[0]), dims*4) + self.assertEqual(len(fv_array[0]), dims * 4) # @unittest.skip("Skipping class until fixed") def test_findDescByBlob(self): - # Add Set set_name = "findwith_blob" dims = 128 @@ -310,8 +302,8 @@ def test_findDescByBlob(self): descriptor_blob = [] x = np.ones(dims) - x[2] = x[2] = 2.34 + 1*20 #2.34 + 1*20 - x = x.astype('float32') + x[2] = x[2] = 2.34 + 1 * 20 # 2.34 + 1*20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) response, blob_array = db.query(all_queries, [descriptor_blob]) @@ -322,16 +314,12 @@ def test_findDescByBlob(self): # Check success self.assertEqual(response[0]["FindDescriptor"]["status"], 0) self.assertEqual(response[0]["FindDescriptor"]["returned"], kn) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][0]["_distance"], 0) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][1]["_distance"], 400) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][2]["_distance"], 400) + self.assertEqual(response[0]["FindDescriptor"]["entities"][0]["_distance"], 0) + self.assertEqual(response[0]["FindDescriptor"]["entities"][1]["_distance"], 400) + self.assertEqual(response[0]["FindDescriptor"]["entities"][2]["_distance"], 400) # @unittest.skip("Skipping class until fixed") def test_findDescByBlobNoLabels(self): - # Add Set set_name = "findwith_blob_no_labels" dims = 128 @@ -361,8 +349,8 @@ def test_findDescByBlobNoLabels(self): descriptor_blob = [] x = np.ones(dims) - x[2] = 2.34 + 1*20 - x = x.astype('float32') + x[2] = 2.34 + 1 * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) response, blob_array = db.query(all_queries, [descriptor_blob]) @@ -376,7 +364,6 @@ def test_findDescByBlobNoLabels(self): # @unittest.skip("Skipping class until fixed") def test_findDescByBlobNoResults(self): - # Add Set set_name = "findwith_blobNoResults" dims = 128 @@ -405,8 +392,8 @@ def test_findDescByBlobNoResults(self): descriptor_blob = [] x = np.ones(dims) - x[2] = 2.34 + 30*20 - x = x.astype('float32') + x[2] = 2.34 + 30 * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) response, blob_array = db.query(all_queries, [descriptor_blob]) @@ -419,7 +406,6 @@ def test_findDescByBlobNoResults(self): # @unittest.skip("Skipping class until fixed") def test_findDescByBlobUnusedRef(self): - # Add Set set_name = "findwith_blobUnusedRef" dims = 50 @@ -449,8 +435,8 @@ def test_findDescByBlobUnusedRef(self): descriptor_blob = [] x = np.ones(dims) - x[2] = 2.34 + 1*20 - x = x.astype('float32') + x[2] = 2.34 + 1 * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) response, blob_array = db.query(all_queries, [descriptor_blob]) @@ -463,7 +449,6 @@ def test_findDescByBlobUnusedRef(self): # @unittest.skip("Skipping class until fixed") def test_findDescByBlobAndConstraints(self): - # Add Set set_name = "findwith_blob_const" dims = 128 @@ -497,8 +482,8 @@ def test_findDescByBlobAndConstraints(self): descriptor_blob = [] x = np.ones(dims) - x[2] = 2.34 + 2*20 - x = x.astype('float32') + x[2] = 2.34 + 2 * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) response, blob_array = db.query(all_queries, [descriptor_blob]) @@ -510,12 +495,10 @@ def test_findDescByBlobAndConstraints(self): self.assertEqual(response[0]["FindDescriptor"]["status"], 0) self.assertEqual(response[0]["FindDescriptor"]["returned"], 1) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][0]["_distance"], 0) + self.assertEqual(response[0]["FindDescriptor"]["entities"][0]["_distance"], 0) # @unittest.skip("Skipping class until fixed") def test_findDescByBlobWithLink(self): - # Add Set set_name = "findwith_blob_link" dims = 128 @@ -542,15 +525,15 @@ def test_findDescByBlobWithLink(self): descriptor_blob = [] class_counter = -1 - for i in range(0,total): #-1): - if ((i % 4) == 0): + for i in range(0, total): # -1): + if (i % 4) == 0: class_counter += 1 reference = i + 2 x = np.ones(dims) - x[2] = 2.34 + i*20 - x = x.astype('float32') + x[2] = 2.34 + i * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) descriptor = {} @@ -586,12 +569,12 @@ def test_findDescByBlobWithLink(self): response, img_array = db.query(all_queries, [descriptor_blob]) # Check success - for x in range(0,total-1,2): + for x in range(0, total - 1, 2): self.assertEqual(response[x]["AddDescriptor"]["status"], 0) - self.assertEqual(response[x+1]["AddEntity"] ["status"], 0) + self.assertEqual(response[x + 1]["AddEntity"]["status"], 0) kn = 3 - reference = 102 # because I can + reference = 102 # because I can all_queries = [] @@ -612,8 +595,8 @@ def test_findDescByBlobWithLink(self): descriptor_blob = [] x = np.ones(dims) - x[2] = 2.34 + 1*20 - x = x.astype('float32') + x[2] = 2.34 + 1 * 20 + x = x.astype("float32") descriptor_blob.append(x.tobytes()) results = {} @@ -635,7 +618,6 @@ def test_findDescByBlobWithLink(self): response, blob_array = db.query(all_queries, [descriptor_blob]) - self.assertEqual(len(blob_array), kn) # This checks that the received blobs is the same as the inserted. self.assertEqual(descriptor_blob[0], blob_array[0]) @@ -644,19 +626,13 @@ def test_findDescByBlobWithLink(self): self.assertEqual(response[0]["FindDescriptor"]["status"], 0) self.assertEqual(response[0]["FindDescriptor"]["returned"], kn) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][0]["_distance"], 0) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][1]["_distance"], 400) - self.assertEqual(response[0]["FindDescriptor"] - ["entities"][2]["_distance"], 400) + self.assertEqual(response[0]["FindDescriptor"]["entities"][0]["_distance"], 0) + self.assertEqual(response[0]["FindDescriptor"]["entities"][1]["_distance"], 400) + self.assertEqual(response[0]["FindDescriptor"]["entities"][2]["_distance"], 400) self.assertEqual(response[1]["FindEntity"]["status"], 0) self.assertEqual(response[1]["FindEntity"]["returned"], kn) - self.assertEqual(response[1]["FindEntity"] - ["entities"][0]["entity_prop"], 200) - self.assertEqual(response[1]["FindEntity"] - ["entities"][1]["entity_prop"], 201) - self.assertEqual(response[1]["FindEntity"] - ["entities"][2]["entity_prop"], 202) + self.assertEqual(response[1]["FindEntity"]["entities"][0]["entity_prop"], 200) + self.assertEqual(response[1]["FindEntity"]["entities"][1]["entity_prop"], 201) + self.assertEqual(response[1]["FindEntity"]["entities"][2]["entity_prop"], 202) diff --git a/tests/python/TestImages.py b/tests/python/TestImages.py index 465544de..b4c4ec6e 100644 --- a/tests/python/TestImages.py +++ b/tests/python/TestImages.py @@ -26,15 +26,14 @@ import TestCommand -class TestImages(TestCommand.TestCommand): - #Methos to insert one image +class TestImages(TestCommand.TestCommand): + # Method to insert one image def insertImage(self, db, props=None, collections=None, format="png"): - imgs_arr = [] all_queries = [] - fd = open("../test_images/brain.png", 'rb') + fd = open("../test_images/brain.png", "rb") imgs_arr.append(fd.read()) fd.close() @@ -61,7 +60,6 @@ def insertImage(self, db, props=None, collections=None, format="png"): self.assertEqual(response[0]["AddImage"]["status"], 0) def test_addImage(self): - db = self.create_connection() all_queries = [] @@ -69,15 +67,15 @@ def test_addImage(self): number_of_inserts = 2 - for i in range(0,number_of_inserts): - #Read Brain Image - fd = open("../test_images/brain.png", 'rb') + for i in range(0, number_of_inserts): + # Read Brain Image + fd = open("../test_images/brain.png", "rb") imgs_arr.append(fd.read()) fd.close() op_params_resize = {} op_params_resize["height"] = 512 - op_params_resize["width"] = 512 + op_params_resize["width"] = 512 op_params_resize["type"] = "resize" props = {} @@ -101,19 +99,18 @@ def test_addImage(self): self.assertEqual(response[i]["AddImage"]["status"], 0) def test_findEntityImage(self): - db = self.create_connection() prefix_name = "fent_brain_" - for i in range(0,2): + for i in range(0, 2): props = {} props["name"] = prefix_name + str(i) self.insertImage(db, props=props) all_queries = [] - for i in range(0,2): + for i in range(0, 2): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] @@ -134,30 +131,32 @@ def test_findEntityImage(self): self.assertEqual(response[0]["FindEntity"]["status"], 0) self.assertEqual(response[1]["FindEntity"]["status"], 0) - self.assertEqual(response[0]["FindEntity"]["entities"][0]["name"], prefix_name + "0") - self.assertEqual(response[1]["FindEntity"]["entities"][0]["name"], prefix_name + "1") + self.assertEqual( + response[0]["FindEntity"]["entities"][0]["name"], prefix_name + "0" + ) + self.assertEqual( + response[1]["FindEntity"]["entities"][0]["name"], prefix_name + "1" + ) def test_findImage(self): - db = self.create_connection() prefix_name = "fimg_brain_" - for i in range(0,2): + for i in range(0, 2): props = {} props["name"] = prefix_name + str(i) self.insertImage(db, props=props) all_queries = [] - for i in range(0,2): + for i in range(0, 2): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] img_params = {} img_params["constraints"] = constraints - query = {} query["FindImage"] = img_params @@ -170,19 +169,18 @@ def test_findImage(self): self.assertEqual(len(img_array), 2) def test_findImageResults(self): - db = self.create_connection() prefix_name = "fimg_results_" - for i in range(0,2): + for i in range(0, 2): props = {} props["name"] = prefix_name + str(i) self.insertImage(db, props=props) all_queries = [] - for i in range(0,2): + for i in range(0, 2): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] @@ -202,12 +200,15 @@ def test_findImageResults(self): self.assertEqual(response[0]["FindImage"]["status"], 0) self.assertEqual(response[1]["FindImage"]["status"], 0) - self.assertEqual(response[0]["FindImage"]["entities"][0]["name"], prefix_name + "0") - self.assertEqual(response[1]["FindImage"]["entities"][0]["name"], prefix_name + "1") + self.assertEqual( + response[0]["FindImage"]["entities"][0]["name"], prefix_name + "0" + ) + self.assertEqual( + response[1]["FindImage"]["entities"][0]["name"], prefix_name + "1" + ) self.assertEqual(len(img_array), 2) def test_addImageWithLink(self): - db = self.create_connection() all_queries = [] @@ -244,7 +245,7 @@ def test_addImageWithLink(self): imgs_arr = [] - fd = open("../test_images/brain.png", 'rb') + fd = open("../test_images/brain.png", "rb") imgs_arr.append(fd.read()) fd.close() @@ -261,13 +262,12 @@ def test_addImageWithLink(self): self.assertEqual(response[1]["AddImage"]["status"], 0) def test_findImage_multiple_results(self): - db = self.create_connection() prefix_name = "fimg_brain_multiple" number_of_inserts = 4 - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): props = {} props["name"] = prefix_name self.insertImage(db, props=props) @@ -294,19 +294,18 @@ def test_findImage_multiple_results(self): self.assertEqual(response[0]["FindImage"]["returned"], number_of_inserts) def test_findImageNoBlob(self): - db = self.create_connection() prefix_name = "fimg_no_blob_" - for i in range(0,2): + for i in range(0, 2): props = {} props["name"] = prefix_name + str(i) self.insertImage(db, props=props) all_queries = [] - for i in range(0,2): + for i in range(0, 2): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] @@ -330,12 +329,11 @@ def test_findImageNoBlob(self): self.assertEqual(len(img_array), 0) def test_findImageRefNoBlobNoPropsResults(self): - db = self.create_connection() prefix_name = "fimg_no_blob_no_res" - for i in range(0,2): + for i in range(0, 2): props = {} props["name"] = prefix_name + str(i) props["id"] = i @@ -343,7 +341,7 @@ def test_findImageRefNoBlobNoPropsResults(self): all_queries = [] - for i in range(0,1): + for i in range(0, 1): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] @@ -353,8 +351,8 @@ def test_findImageRefNoBlobNoPropsResults(self): img_params = {} img_params["constraints"] = constraints - img_params["results"] = results - img_params["_ref"] = 22 + img_params["results"] = results + img_params["_ref"] = 22 query = {} query["FindImage"] = img_params @@ -368,12 +366,11 @@ def test_findImageRefNoBlobNoPropsResults(self): self.assertEqual(len(img_array), 0) def test_updateImage(self): - db = self.create_connection() prefix_name = "fimg_update_" - for i in range(0,2): + for i in range(0, 2): props = {} props["name"] = prefix_name + str(i) self.insertImage(db, props=props) @@ -401,7 +398,6 @@ def test_updateImage(self): self.assertEqual(len(img_array), 0) def ztest_zFindImageWithCollection(self): - db = self.create_connection() prefix_name = "fimg_brain_collection_" @@ -410,7 +406,7 @@ def ztest_zFindImageWithCollection(self): colls = {} colls = ["brainScans"] - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): props = {} props["name"] = prefix_name + str(i) @@ -418,8 +414,7 @@ def ztest_zFindImageWithCollection(self): all_queries = [] - for i in range(0,1): - + for i in range(0, 1): results = {} results["list"] = ["name"] diff --git a/tests/python/TestRetail.py b/tests/python/TestRetail.py index d879697f..f4872990 100644 --- a/tests/python/TestRetail.py +++ b/tests/python/TestRetail.py @@ -34,10 +34,9 @@ dim = 1000 name = "features_vectors_store1" -class TestEntities(TestCommand.TestCommand): +class TestEntities(TestCommand.TestCommand): def add_descriptor_set(self, name, dim): - db = self.create_connection() all_queries = [] @@ -57,7 +56,6 @@ def add_descriptor_set(self, name, dim): self.assertEqual(response[0]["AddDescriptorSet"]["status"], 0) def build_store(self): - db = self.create_connection() all_queries = [] @@ -65,69 +63,61 @@ def build_store(self): store_ref = 999 query = { - "AddEntity" : - { - "_ref" : store_ref, - "class" : "Store", - "constraints" : { "Name" : [ "==", "Walmart" ] }, - "properties" : { - "Address" : "1428 alex way, Hillsboro 97124", - "Name" : "Walmart", - "Type" : "grocerys" - } + "AddEntity": { + "_ref": store_ref, + "class": "Store", + "constraints": {"Name": ["==", "Walmart"]}, + "properties": { + "Address": "1428 alex way, Hillsboro 97124", + "Name": "Walmart", + "Type": "grocerys", + }, } } all_queries.append(query) - areas_tag = ["ChildrenClothes", - "WomenClothes", - "MenClothes", - "Computers", - "Sport", - "Food", - "ChildrenClothes", - "WomenClothes", - "MenClothes", - "Computers", - "Sport", - "Food", - "ChildrenClothes", - "ChildrenClothes", - "WomenClothes", - "MenClothes", - "Computers", - "Sport", - "Food", - "ChildrenClothes" - ] - - for i in range(1,n_cameras+1): - + areas_tag = [ + "ChildrenClothes", + "WomenClothes", + "MenClothes", + "Computers", + "Sport", + "Food", + "ChildrenClothes", + "WomenClothes", + "MenClothes", + "Computers", + "Sport", + "Food", + "ChildrenClothes", + "ChildrenClothes", + "WomenClothes", + "MenClothes", + "Computers", + "Sport", + "Food", + "ChildrenClothes", + ] + + for i in range(1, n_cameras + 1): addCamera = { - "AddEntity" : - { + "AddEntity": { "_ref": i, - "class" : "Camera", - "constraints" : { "Name" : [ "==", "cam" + str(i) ] }, - "properties" : { - "Name" : "cam" + str(i) - } + "class": "Camera", + "constraints": {"Name": ["==", "cam" + str(i)]}, + "properties": {"Name": "cam" + str(i)}, } } all_queries.append(addCamera) addArea = { - "AddEntity" : - { - "_ref" : n_cameras * 10 + i, - "class" : "Area", - "constraints" : { "Name" : [ "==", "Area" + str(i) ] }, - "properties" : { - "Name" : "Area" + str(i), - "Tag" : areas_tag[i] - } + "AddEntity": { + "_ref": n_cameras * 10 + i, + "class": "Area", + "constraints": {"Name": ["==", "Area" + str(i)]}, + "properties": {"Name": "Area" + str(i), "Tag": areas_tag[i]}, } } @@ -140,22 +130,20 @@ def build_store(self): all_queries.append(addArea) addConnection = { - "AddConnection" : - { - "class" : "Covers", - "ref1" : i, - "ref2" : n_cameras * 10 + i + "AddConnection": { + "class": "Covers", + "ref1": i, + "ref2": n_cameras * 10 + i, } } all_queries.append(addConnection) addConnection = { - "AddConnection" : - { - "class" : "Consists_Of", - "ref1" : store_ref, - "ref2" : n_cameras * 10 + i + "AddConnection": { + "class": "Consists_Of", + "ref1": store_ref, + "ref2": n_cameras * 10 + i, } } @@ -166,14 +154,13 @@ def build_store(self): self.assertEqual(response[0]["AddEntity"]["status"], 0) - for i in range(1,n_cameras+1): - self.assertEqual(response[(i-1)*4+1]["AddEntity"]["status"], 0) - self.assertEqual(response[(i-1)*4+2]["AddEntity"]["status"], 0) - self.assertEqual(response[(i-1)*4+3]["AddConnection"]["status"], 0) - self.assertEqual(response[(i-1)*4+4]["AddConnection"]["status"], 0) + for i in range(1, n_cameras + 1): + self.assertEqual(response[(i - 1) * 4 + 1]["AddEntity"]["status"], 0) + self.assertEqual(response[(i - 1) * 4 + 2]["AddEntity"]["status"], 0) + self.assertEqual(response[(i - 1) * 4 + 3]["AddConnection"]["status"], 0) + self.assertEqual(response[(i - 1) * 4 + 4]["AddConnection"]["status"], 0) def single(self, thID, db, results): - # id = "19149ec8-fa0d-4ed0-9cfb-3e0811b75391" id = "19149ec8-fa0d-4ed0-9cfb-3e0811b" + str(thID) @@ -183,11 +170,10 @@ def single(self, thID, db, results): descriptor_blob = [] x = np.ones(dim) x[2] = 2.34 + np.random.random_sample() - x = x.astype('float32') + x = x.astype("float32") descriptor_blob.append(x.tobytes()) try: - response, res_arr = db.query(all_queries, [descriptor_blob]) for i in range(0, len(response)): @@ -209,7 +195,6 @@ def single(self, thID, db, results): @unittest.skip("Skipping class until fixed") def test_concurrent(self): - self.build_store() self.add_descriptor_set(name, dim) @@ -223,13 +208,11 @@ def test_concurrent(self): db_list.append(db) results = [None] * concurrency * retries - for ret in range(0,retries): - + for ret in range(0, retries): thread_arr = [] - for i in range(0,concurrency): + for i in range(0, concurrency): idx = concurrency * ret + i - thread_add = Thread( - target=self.single,args=(idx, db_list[i], results) ) + thread_add = Thread(target=self.single, args=(idx, db_list[i], results)) thread_add.start() thread_arr.append(thread_add) @@ -237,7 +220,7 @@ def test_concurrent(self): error_counter = 0 for th in thread_arr: th.join() - if (results[idx] == -1): + if results[idx] == -1: error_counter += 1 idx += 1 diff --git a/tests/python/TestVideos.py b/tests/python/TestVideos.py index efe5fc46..06365e05 100644 --- a/tests/python/TestVideos.py +++ b/tests/python/TestVideos.py @@ -27,15 +27,14 @@ import TestCommand import unittest -class TestVideos(TestCommand.TestCommand): - #Methos to insert one image +class TestVideos(TestCommand.TestCommand): + # Method to insert one video def insertVideo(self, db, props=None): - video_arr = [] all_queries = [] - fd = open("../test_videos/Megamind.avi", 'rb') + fd = open("../test_videos/Megamind.avi", "rb") video_arr.append(fd.read()) fd.close() @@ -46,7 +45,7 @@ def insertVideo(self, db, props=None): props["test_case"] = "test_case_prop" video_parms["properties"] = props - video_parms["codec"] = "h264" + video_parms["codec"] = "h264" video_parms["container"] = "mp4" query = {} @@ -60,7 +59,6 @@ def insertVideo(self, db, props=None): self.assertEqual(response[0]["AddVideo"]["status"], 0) def test_addVideo(self): - db = self.create_connection() all_queries = [] @@ -68,15 +66,15 @@ def test_addVideo(self): number_of_inserts = 2 - for i in range(0,number_of_inserts): - #Read Brain Image - fd = open("../test_videos/Megamind.avi", 'rb') + for i in range(0, number_of_inserts): + # Read Brain Image + fd = open("../test_videos/Megamind.avi", "rb") video_arr.append(fd.read()) fd.close() op_params_resize = {} op_params_resize["height"] = 512 - op_params_resize["width"] = 512 + op_params_resize["width"] = 512 op_params_resize["type"] = "resize" props = {} @@ -98,16 +96,15 @@ def test_addVideo(self): self.assertEqual(response[i]["AddVideo"]["status"], 0) def test_addVideoFromLocalFile_invalid_command(self): - # The test is meant to fail if both blob and a local file are specified db = self.create_connection() - with open("../test_videos/Megamind.avi", 'rb') as fd: + with open("../test_videos/Megamind.avi", "rb") as fd: video_blob = fd.read() video_params = {} video_params["from_server_file"] = "BigFile.mp4" - video_params["codec"] = "h264" + video_params["codec"] = "h264" query = {} query["AddVideo"] = video_params @@ -116,12 +113,11 @@ def test_addVideoFromLocalFile_invalid_command(self): self.assertEqual(response[0]["status"], -1) def test_addVideoFromLocalFile_file_not_found(self): - db = self.create_connection() video_params = {} video_params["from_server_file"] = "BigFile.mp4" - video_params["codec"] = "h264" + video_params["codec"] = "h264" query = {} query["AddVideo"] = video_params @@ -131,12 +127,11 @@ def test_addVideoFromLocalFile_file_not_found(self): @unittest.skip("Skipping class until fixed") def test_addVideoFromLocalFile_success(self): - db = self.create_connection() video_params = {} video_params["from_server_file"] = "../../tests/videos/Megamind.mp4" - video_params["codec"] = "h264" + video_params["codec"] = "h264" query = {} query["AddVideo"] = video_params @@ -144,12 +139,10 @@ def test_addVideoFromLocalFile_success(self): response, obj_array = db.query([query], [[]]) self.assertEqual(response[0]["AddVideo"]["status"], 0) - def test_extractKeyFrames(self): - db = self.create_connection() - fd = open("../../tests/videos/Megamind.mp4", 'rb') + fd = open("../../tests/videos/Megamind.mp4", "rb") video_blob = fd.read() fd.close() @@ -160,8 +153,8 @@ def test_extractKeyFrames(self): video_params = {} video_params["index_frames"] = True - video_params["properties"] = props - video_params["codec"] = "h264" + video_params["properties"] = props + video_params["codec"] = "h264" query = {} query["AddVideo"] = video_params @@ -172,7 +165,7 @@ def test_extractKeyFrames(self): entity = {} entity["class"] = "VD:KF" - entity["results"] = {'count': ''} + entity["results"] = {"count": ""} query = {} query["FindEntity"] = entity @@ -182,24 +175,23 @@ def test_extractKeyFrames(self): self.assertEqual(response[0]["FindEntity"]["status"], 0) # we know that this video has exactly four key frames - self.assertEqual(response[0]["FindEntity"]["count"], 4) + self.assertEqual(response[0]["FindEntity"]["count"], 4) def test_findVideo(self): - db = self.create_connection() prefix_name = "video_1_" number_of_inserts = 2 - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): props = {} props["name"] = prefix_name + str(i) self.insertVideo(db, props=props) all_queries = [] - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] @@ -219,7 +211,6 @@ def test_findVideo(self): self.assertEqual(response[i]["FindVideo"]["status"], 0) def test_FindFramesByFrames(self): - db = self.create_connection() prefix_name = "video_2_" @@ -233,7 +224,7 @@ def test_FindFramesByFrames(self): all_queries = [] - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] @@ -250,10 +241,9 @@ def test_FindFramesByFrames(self): self.assertEqual(response[0]["FindFrames"]["status"], 0) self.assertEqual(response[1]["FindFrames"]["status"], 0) - self.assertEqual(len(img_array), 2 * len(video_params["frames"]) ) + self.assertEqual(len(img_array), 2 * len(video_params["frames"])) def test_FindFramesByInterval(self): - db = self.create_connection() prefix_name = "video_3_" @@ -267,22 +257,22 @@ def test_FindFramesByInterval(self): all_queries = [] - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] number_of_frames = 10 operations = [] interval_operation = {} - interval_operation["type"] = "interval" + interval_operation["type"] = "interval" interval_operation["start"] = 0 - interval_operation["stop"] = number_of_frames - interval_operation["step"] = 1 + interval_operation["stop"] = number_of_frames + interval_operation["step"] = 1 operations.append(interval_operation) video_params = {} video_params["constraints"] = constraints - video_params["operations"] = operations + video_params["operations"] = operations query = {} query["FindFrames"] = video_params @@ -296,7 +286,6 @@ def test_FindFramesByInterval(self): self.assertEqual(len(img_array), 2 * number_of_frames) def test_FindFramesMissingParameters(self): - db = self.create_connection() constraints = {} @@ -317,7 +306,6 @@ def test_FindFramesMissingParameters(self): self.assertEqual(img, []) def test_FindFramesInvalidParameters(self): - db = self.create_connection() constraints = {} @@ -325,17 +313,16 @@ def test_FindFramesInvalidParameters(self): operations = [] interval_operation = {} - interval_operation["type"] = "interval" + interval_operation["type"] = "interval" interval_operation["start"] = 10 - interval_operation["stop"] = 20 - interval_operation["step"] = 1 + interval_operation["stop"] = 20 + interval_operation["step"] = 1 operations.append(interval_operation) video_params = {} video_params["constraints"] = constraints - video_params["operations"] = operations - video_params["frames"] = [1] - + video_params["operations"] = operations + video_params["frames"] = [1] query = {} query["FindFrames"] = video_params @@ -349,21 +336,20 @@ def test_FindFramesInvalidParameters(self): self.assertEqual(img, []) def test_findVideoResults(self): - db = self.create_connection() prefix_name = "resvideo_1_" number_of_inserts = 2 - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): props = {} props["name"] = prefix_name + str(i) self.insertVideo(db, props=props) all_queries = [] - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] @@ -387,7 +373,6 @@ def test_findVideoResults(self): self.assertEqual(response[i]["FindVideo"]["status"], 0) def test_addVideoWithLink(self): - db = self.create_connection() all_queries = [] @@ -423,7 +408,7 @@ def test_addVideoWithLink(self): imgs_arr = [] - fd = open("../test_videos/Megamind.avi", 'rb') + fd = open("../test_videos/Megamind.avi", "rb") imgs_arr.append(fd.read()) fd.close() @@ -440,13 +425,12 @@ def test_addVideoWithLink(self): self.assertEqual(response[1]["AddVideo"]["status"], 0) def test_findVid_multiple_results(self): - db = self.create_connection() prefix_name = "vid_multiple" number_of_inserts = 4 - for i in range(0,number_of_inserts): + for i in range(0, number_of_inserts): props = {} props["name"] = prefix_name self.insertVideo(db, props=props) @@ -473,19 +457,18 @@ def test_findVid_multiple_results(self): self.assertEqual(response[0]["FindVideo"]["returned"], number_of_inserts) def test_findVideoNoBlob(self): - db = self.create_connection() prefix_name = "fvid_no_blob_" - for i in range(0,2): + for i in range(0, 2): props = {} props["name"] = prefix_name + str(i) self.insertVideo(db, props=props) all_queries = [] - for i in range(0,2): + for i in range(0, 2): constraints = {} constraints["name"] = ["==", prefix_name + str(i)] @@ -509,12 +492,11 @@ def test_findVideoNoBlob(self): self.assertEqual(len(img_array), 0) def test_updateVideo(self): - db = self.create_connection() prefix_name = "fvid_update_" - for i in range(0,2): + for i in range(0, 2): props = {} props["name"] = prefix_name + str(i) self.insertVideo(db, props=props) diff --git a/tests/python/config-aws-tests.json b/tests/python/config-aws-tests.json new file mode 100644 index 00000000..c0e48723 --- /dev/null +++ b/tests/python/config-aws-tests.json @@ -0,0 +1,11 @@ +// VDMS Config File +// This is the run-time config file +// Sets database paths and other parameters +{ + // Network + "port": 55565, + "db_root_path": "test_db", + "storage_type": "aws", //local, aws, etc + "bucket_name": "minio-bucket", + "more-info": "github.com/IntelLabs/vdms" +} diff --git a/tests/python/config-tests.json b/tests/python/config-tests.json index 30141207..43afef5e 100644 --- a/tests/python/config-tests.json +++ b/tests/python/config-tests.json @@ -5,6 +5,7 @@ // Network "port": 55565, "db_root_path": "test_db", - + "storage_type": "local", //local, aws, etc + "bucket_name": "minio-bucket", "more-info": "github.com/IntelLabs/vdms" } diff --git a/tests/python/longquery.py b/tests/python/longquery.py index 6801fbd9..1e613e92 100644 --- a/tests/python/longquery.py +++ b/tests/python/longquery.py @@ -26,684 +26,364 @@ import os -def queryPerson(id): - query = [ { - "AddEntity" : - { - "_ref" : 1, - "class" : "Person", - "properties" : - { - "Id" : id, - "imaginary_node" : 1 - } - } - }, - { - "AddEntity" : - { - "_ref" : 2, - "class" : "BoundingBox", - "properties" : - { - "Height" : "267", - "Id" : id, - "Width" : "117", - "X" : "296", - "Y" : "496" - } - } - }, - { - "AddDescriptor" : - { - "_ref" : 3, - "label" : "Person", - "properties" : - { - "id" : id, - "tag" : "person", - "time_stamp" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } - }, - "set" : "features_vectors_store1" - } - }, +def queryPerson(id): + query = [ { - "AddConnection" : - { - "class" : "Has", - "ref1" : 1, - "ref2" : 3 + "AddEntity": { + "_ref": 1, + "class": "Person", + "properties": {"Id": id, "imaginary_node": 1}, } }, { - "AddConnection" : - { - "class" : "Represents", - "ref1" : 1, - "ref2" : 2 + "AddEntity": { + "_ref": 2, + "class": "BoundingBox", + "properties": { + "Height": "267", + "Id": id, + "Width": "117", + "X": "296", + "Y": "496", + }, } }, { - "AddConnection" : - { - "class" : "AppearsIn", - "ref1" : 3, - "ref2" : 2 + "AddDescriptor": { + "_ref": 3, + "label": "Person", + "properties": { + "id": id, + "tag": "person", + "time_stamp": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, + }, + "set": "features_vectors_store1", } - } - ] + }, + {"AddConnection": {"class": "Has", "ref1": 1, "ref2": 3}}, + {"AddConnection": {"class": "Represents", "ref1": 1, "ref2": 2}}, + {"AddConnection": {"class": "AppearsIn", "ref1": 3, "ref2": 2}}, + ] return query -def queryVisit(id): +def queryVisit(id): query = [ { - "AddEntity" : - { - "_ref" : 4, - "class" : "Visit", - "constraints" : - { - "Id" : - [ - "==", - id - ] + "AddEntity": { + "_ref": 4, + "class": "Visit", + "constraints": {"Id": ["==", id]}, + "properties": { + "Id": id, + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "starting_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "properties" : - { - "Id" : id, - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "starting_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } - } - } - }, - { - "FindEntity" : - { - "_ref" : 5, - "class" : "Person", - "constraints" : - { - "Id" : - [ - "==", - id - ] - } - } - }, - { - "AddConnection" : - { - "class" : "visited", - "ref1" : 4, - "ref2" : 5 - } - }, - { - "FindEntity" : - { - "_ref" : 6, - "class" : "Store", - "constraints" : - { - "Name" : - [ - "==", - "Walmart" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "Store_Visit", - "ref1" : 4, - "ref2" : 6 - } - }, - { - "FindEntity" : - { - "_ref" : 7, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area15" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area15", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + } + }, + { + "FindEntity": { + "_ref": 5, + "class": "Person", + "constraints": {"Id": ["==", id]}, + } + }, + {"AddConnection": {"class": "visited", "ref1": 4, "ref2": 5}}, + { + "FindEntity": { + "_ref": 6, + "class": "Store", + "constraints": {"Name": ["==", "Walmart"]}, + } + }, + {"AddConnection": {"class": "Store_Visit", "ref1": 4, "ref2": 6}}, + { + "FindEntity": { + "_ref": 7, + "class": "Area", + "constraints": {"Name": ["==", "Area15"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area15", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 7 - } - }, - { - "FindEntity" : - { - "_ref" : 8, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area14" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area14", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 7, + } + }, + { + "FindEntity": { + "_ref": 8, + "class": "Area", + "constraints": {"Name": ["==", "Area14"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area14", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 8 - } - }, - { - "FindEntity" : - { - "_ref" : 9, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area13" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area13", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 8, + } + }, + { + "FindEntity": { + "_ref": 9, + "class": "Area", + "constraints": {"Name": ["==", "Area13"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area13", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 9 - } - }, - { - "FindEntity" : - { - "_ref" : 10, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area12" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area12", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 9, + } + }, + { + "FindEntity": { + "_ref": 10, + "class": "Area", + "constraints": {"Name": ["==", "Area12"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area12", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 10 - } - }, - { - "FindEntity" : - { - "_ref" : 11, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area11" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area11", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 10, + } + }, + { + "FindEntity": { + "_ref": 11, + "class": "Area", + "constraints": {"Name": ["==", "Area11"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area11", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 11 - } - }, - { - "FindEntity" : - { - "_ref" : 12, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area10" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area10", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 11, + } + }, + { + "FindEntity": { + "_ref": 12, + "class": "Area", + "constraints": {"Name": ["==", "Area10"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area10", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 12 - } - }, - { - "FindEntity" : - { - "_ref" : 13, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area9" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area9", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 12, + } + }, + { + "FindEntity": { + "_ref": 13, + "class": "Area", + "constraints": {"Name": ["==", "Area9"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area9", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 13 - } - }, - { - "FindEntity" : - { - "_ref" : 14, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area8" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area8", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 13, + } + }, + { + "FindEntity": { + "_ref": 14, + "class": "Area", + "constraints": {"Name": ["==", "Area8"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area8", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 14 - } - }, - { - "FindEntity" : - { - "_ref" : 15, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area7" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area7", - "ending_time" : - { - - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - - "passing_time" : - { - - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 14, + } + }, + { + "FindEntity": { + "_ref": 15, + "class": "Area", + "constraints": {"Name": ["==", "Area7"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area7", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 15 - } - }, - { - "FindEntity" : - { - "_ref" : 16, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area6" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area6", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 15, + } + }, + { + "FindEntity": { + "_ref": 16, + "class": "Area", + "constraints": {"Name": ["==", "Area6"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area6", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 16 - } - }, - { - "FindEntity" : - { - "_ref" : 17, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area5" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area5", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 16, + } + }, + { + "FindEntity": { + "_ref": 17, + "class": "Area", + "constraints": {"Name": ["==", "Area5"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area5", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 17 - } - }, - { - "FindEntity" : - { - "_ref" : 18, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area4" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area4", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 17, + } + }, + { + "FindEntity": { + "_ref": 18, + "class": "Area", + "constraints": {"Name": ["==", "Area4"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area4", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 18 - } - }, - { - "FindEntity" : - { - "_ref" : 19, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area3" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area3", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 18, + } + }, + { + "FindEntity": { + "_ref": 19, + "class": "Area", + "constraints": {"Name": ["==", "Area3"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area3", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 19 - } - }, - { - "FindEntity" : - { - "_ref" : 20, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area2" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area2", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 19, + } + }, + { + "FindEntity": { + "_ref": 20, + "class": "Area", + "constraints": {"Name": ["==", "Area2"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area2", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 20 - } - }, - { - "FindEntity" : - { - "_ref" : 21, - "class" : "Area", - "constraints" : - { - "Name" : - [ - "==", - "Area1" - ] - } - } - }, - { - "AddConnection" : - { - "class" : "PassBy", - "properties" : - { - "Area" : "Area1", - "ending_time" : - { - "_date" : "Sat Jan 06 23:03:00 PDT 2018" - }, - "passing_time" : - { - "_date" : "Sat Jan 06 23:00:00 PST 83186920" - } + "ref1": 4, + "ref2": 20, + } + }, + { + "FindEntity": { + "_ref": 21, + "class": "Area", + "constraints": {"Name": ["==", "Area1"]}, + } + }, + { + "AddConnection": { + "class": "PassBy", + "properties": { + "Area": "Area1", + "ending_time": {"_date": "Sat Jan 06 23:03:00 PDT 2018"}, + "passing_time": {"_date": "Sat Jan 06 23:00:00 PST 83186920"}, }, - "ref1" : 4, - "ref2" : 21 + "ref1": 4, + "ref2": 21, } - } - ] + }, + ] return query diff --git a/tests/python/main.py b/tests/python/main.py index 87941319..cacc1ca7 100644 --- a/tests/python/main.py +++ b/tests/python/main.py @@ -34,5 +34,5 @@ import numpy as np import vdms -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/python/run_python_aws_tests.sh b/tests/python/run_python_aws_tests.sh new file mode 100755 index 00000000..e50c9d7a --- /dev/null +++ b/tests/python/run_python_aws_tests.sh @@ -0,0 +1,55 @@ +#!/bin/bash -e +# +# The MIT License +# +# @copyright Copyright (c) 2017 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, +# merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +TEST_DIR=${PWD} +base_dir=$(dirname $(dirname $PWD)) +client_path=${base_dir}/client/python +export PYTHONPATH=$client_path:${PYTHONPATH} + +# Uncomment to re-generate queryMessage_pb2.py +# protoc -I=${base_dir}/utils/src/protobuf --python_out=${client_path}/vdms ${base_dir}/utils/src/protobuf/queryMessage.proto + +cd ${TEST_DIR} +rm -rf test_db log.log screen.log +mkdir -p test_db + +./../../build/vdms -cfg config-aws-tests.json > screen.log 2> log.log & +py_unittest_pid=$! + +sleep 1 + +#start the minio server +./../../minio server ./../../minio_files & +py_minio_pid=$! + +sleep 2 + +echo 'Running Python AWS S3 tests...' +python3 -m coverage run --include="../../*" --omit="${base_dir}/client/python/vdms/queryMessage_pb2.py,../*" -m unittest discover --pattern=Test*.py -v + +rm -rf test_db log.log screen.log +kill -9 $py_unittest_pid $py_minio_pid || true \ No newline at end of file diff --git a/tests/python/run_python_tests.sh b/tests/python/run_python_tests.sh index b5e34dbb..144525d3 100755 --- a/tests/python/run_python_tests.sh +++ b/tests/python/run_python_tests.sh @@ -1,3 +1,4 @@ +#!/bin/bash -e # # The MIT License # @@ -30,7 +31,7 @@ client_path=${base_dir}/client/python export PYTHONPATH=$client_path:${PYTHONPATH} # Uncomment to re-generate queryMessage_pb2.py -# python3 -m grpc_tools.protoc -I=${base_dir}/utils/src/protobuf --python_out=${client_path}/vdms ${base_dir}/utils/src/protobuf/queryMessage.proto +# protoc -I=${base_dir}/utils/src/protobuf --python_out=${client_path}/vdms ${base_dir}/utils/src/protobuf/queryMessage.proto cd ${TEST_DIR} rm -rf test_db log.log screen.log @@ -42,7 +43,7 @@ py_unittest_pid=$! sleep 1 echo 'Running Python tests...' -python3 -m coverage run --include="../../*" --omit="../*" -m unittest discover --pattern=Test*.py -v +python3 -m coverage run --include="../../*" --omit="${base_dir}/client/python/vdms/queryMessage_pb2.py,../*" -m unittest discover --pattern=Test*.py -v rm -rf test_db log.log screen.log -kill -9 $py_unittest_pid +kill -9 $py_unittest_pid || true diff --git a/tests/remote_function_test/functions/flip.py b/tests/remote_function_test/functions/flip.py new file mode 100644 index 00000000..a82cd3b8 --- /dev/null +++ b/tests/remote_function_test/functions/flip.py @@ -0,0 +1,10 @@ +import time +import cv2 + + +def run(ipfilename, format, options): + img = cv2.imread(ipfilename) + + img = cv2.flip(img, 0) + + return img diff --git a/tests/remote_function_test/requirements.txt b/tests/remote_function_test/requirements.txt new file mode 100644 index 00000000..89b80f95 --- /dev/null +++ b/tests/remote_function_test/requirements.txt @@ -0,0 +1,5 @@ +opencv-python==4.5.5.64 +flask +numpy +sk-video +imutils \ No newline at end of file diff --git a/tests/remote_function_test/syncremote.jpg b/tests/remote_function_test/syncremote.jpg new file mode 100644 index 00000000..e6343a7e Binary files /dev/null and b/tests/remote_function_test/syncremote.jpg differ diff --git a/tests/remote_function_test/udf_server.py b/tests/remote_function_test/udf_server.py new file mode 100644 index 00000000..68d0006b --- /dev/null +++ b/tests/remote_function_test/udf_server.py @@ -0,0 +1,106 @@ +from flask import Flask, request, jsonify, send_file, after_this_request +import cv2 +import numpy as np +import json +from datetime import datetime, timezone +import os +import sys +from collections import defaultdict, deque +import skvideo.io +import imutils + +for entry in os.scandir("functions"): + if entry.is_file(): + string = f"from functions import {entry.name}"[:-3] + exec(string) + +app = Flask(__name__) + +count = 0 + + +def get_current_timestamp(): + dt = datetime.now(timezone.utc) + + utc_time = dt.replace(tzinfo=timezone.utc) + utc_timestamp = utc_time.timestamp() + + return utc_timestamp + + +@app.route("/hello", methods=["GET"]) +def hello(): + return jsonify({"response": "true"}) + + +@app.route("/image", methods=["POST"]) +def image_api(): + json_data = json.loads(request.form["jsonData"]) + image_data = request.files["imageData"] + + format = json_data["format"] if "format" in json_data else "jpg" + + tmpfile = "tmpfile" + str(datetime.now()) + "." + str(format) + + image_data.save(tmpfile) + + udf = globals()[json_data["id"]] + r_img = udf.run(tmpfile, format, json_data) + + return_string = cv2.imencode("." + str(format), r_img)[1].tostring() + os.remove(tmpfile) + return return_string + + +@app.route("/video", methods=["POST"]) +def video_api(): + json_data = json.loads(request.form["jsonData"]) + video_data = request.files["videoData"] + + format = json_data["format"] if "format" in json_data else "mp4" + + tmpfile = "tmpfile" + str(datetime.now()) + "." + str(format) + video_data.save(tmpfile) + + udf = globals()[json_data["format"]] + activity_tagged_file = udf.run(tmpfile, format, json_data) + + os.remove(tmpfile) + + @after_this_request + def remove_tempfile(response): + try: + os.remove(activity_tagged_file) + except Exception as e: + print("File cannot be deleted or not present") + return response + + try: + return send_file( + activity_tagged_file, as_attachment=True, download_name=activity_tagged_file + ) + except Exception as e: + print(str(e)) + return "Error in file read" + + +@app.errorhandler(400) +def handle_bad_request(e): + response = e.get_response() + response.data = json.dumps( + { + "code": e.code, + "name": e.name, + "description": e.description, + } + ) + response.content_type = "application/json" + print("400 error:", response) + return response + + +if __name__ == "__main__": + if sys.argv[1] == None: + print("Port missing\n Correct Usage: python3 udf_server.py ") + else: + app.run(host="0.0.0.0", port=int(sys.argv[1])) diff --git a/tests/run_aws_tests.sh b/tests/run_aws_tests.sh new file mode 100755 index 00000000..9546a022 --- /dev/null +++ b/tests/run_aws_tests.sh @@ -0,0 +1,19 @@ +#!/bin/bash -e + +sh cleandbs.sh || true +mkdir test_db_client +mkdir dbs # necessary for Descriptors +mkdir temp # necessary for Videos +mkdir videos_tests +mkdir backups + +#start the minio server +./../minio server ./../minio_files & +py_minio_pid=$! + +sleep 2 + +echo 'Running C++ tests...' +./../build/tests/unit_tests --gtest_filter=RemoteConnectionTest.* + +kill -9 $py_minio_pid || true diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 2ee2f92e..41933ae7 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -1,19 +1,42 @@ -sh cleandbs.sh +#!/bin/bash -e + +sh cleandbs.sh || true mkdir test_db_client mkdir dbs # necessary for Descriptors mkdir temp # necessary for Videos mkdir videos_tests mkdir backups +# Stop UDF Queue and Remote Server if already running +pkill -9 -f udf_server.py || true +pkill -9 -f udf_local.py || true + +# Start remote server for test +cd remote_function_test +python3 -m pip install -r requirements.txt +python3 udf_server.py 5010 > ../tests_screen.log 2> ../tests_log.log & + +# Start UDF message queue for test +cd ../udf_test +python3 -m pip install -r requirements.txt +python3 udf_local.py > ../tests_screen.log 2> ../tests_log.log & + +cd .. + # Start server for client test ./../build/vdms -cfg unit_tests/config-tests.json > tests_screen.log 2> tests_log.log & +cpp_unittest_pid=$! ./../build/vdms -cfg unit_tests/config-client-tests.json > tests_screen.log 2> tests_log.log & +client_test_pid=$! echo 'not the vdms application - this file is needed for shared key' > vdms echo 'Running C++ tests...' ./../build/tests/unit_tests \ - --gtest_filter=-ImageTest.CreateNameTDB:ImageTest.NoMetadata:VideoTest.CreateUnique:Descriptors_Add.add_1by1_and_search_1k + --gtest_filter=-ImageTest.CreateNameTDB:ImageTest.NoMetadata:VideoTest.CreateUnique:Descriptors_Add.add_1by1_and_search_1k:RemoteConnectionTest.* + +pkill -9 -f udf_server.py +pkill -9 -f udf_local.py -# kill -9 $cpp_unittest_pid $client_test_pid +kill -9 $cpp_unittest_pid $client_test_pid || true diff --git a/tests/server/QueryHandlerTester.h b/tests/server/QueryHandlerTester.h index 426715aa..4311a1d0 100644 --- a/tests/server/QueryHandlerTester.h +++ b/tests/server/QueryHandlerTester.h @@ -31,18 +31,15 @@ #include "QueryHandler.h" namespace VDMS { - class QueryHandlerTester - { - QueryHandler& _qh; - public: +class QueryHandlerTester { + QueryHandler &_qh; - QueryHandlerTester(QueryHandler& qh): _qh(qh) - {} +public: + QueryHandlerTester(QueryHandler &qh) : _qh(qh) {} - void pq(protobufs::queryMessage& proto_query, - protobufs::queryMessage& response) - { - _qh.process_query(proto_query, response); - } - }; -}; \ No newline at end of file + void pq(protobufs::queryMessage &proto_query, + protobufs::queryMessage &response) { + _qh.process_query(proto_query, response); + } +}; +}; // namespace VDMS \ No newline at end of file diff --git a/tests/server/config-auto-replicate-tests.json b/tests/server/config-auto-replicate-tests.json index 9d283df1..76d1dcd3 100755 --- a/tests/server/config-auto-replicate-tests.json +++ b/tests/server/config-auto-replicate-tests.json @@ -1,6 +1,6 @@ { "port": 55557, - "autoreplicate_interval":5, + "autoreplicate_interval":-5, "unit":"s", "max_simultaneous_clients": 100, "backup_path":"", diff --git a/tests/server/json_queries.cc b/tests/server/json_queries.cc index d20b2f29..8dc6733d 100644 --- a/tests/server/json_queries.cc +++ b/tests/server/json_queries.cc @@ -27,19 +27,19 @@ * */ -#include #include #include #include +#include /* system, NULL, EXIT_FAILURE */ +#include #include -#include /* system, NULL, EXIT_FAILURE */ #include "gtest/gtest.h" #include -#include "pmgd.h" -#include "VDMSConfig.h" #include "QueryHandlerTester.h" +#include "VDMSConfig.h" +#include "pmgd.h" using namespace VDMS; using namespace PMGD; @@ -61,639 +61,636 @@ std::string singleAddImage(" \ } \ } \ "); -TEST( AutoReplicate, default_replicate) -{ - +TEST(AutoReplicate, default_replicate) { + + std::string path = "server/config-auto-replicate-tests.json"; + std::cout << path << std::endl; + VDMSConfig::init(path); + PMGDQueryHandler::init(); + QueryHandler::init(); + ReplicationConfig replication_test; + replication_test.backup_path = "backups"; + replication_test.db_path = "db_backup"; + replication_test.autoreplicate_interval = 5; + replication_test.autoreplication_unit = "s"; + replication_test.server_port = 55557; + + QueryHandler qh_base; + qh_base.regualar_run_autoreplicate(replication_test); +} +TEST(AddImage, simpleAdd) { + std::string addImg; + addImg += "[" + singleAddImage + "]"; - VDMSConfig::init("server/config-auto-replicate-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); - std::string backup_path ="backups"; - std::string db_path="db_backup"; - int port =55557; + VDMSConfig::init("server/config-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); - QueryHandler qh_base; - qh_base.regualar_run_autoreplicate(backup_path, db_path, port); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(addImg); + std::string image; + std::ifstream file("test_images/brain.png", + std::ios::in | std::ios::binary | std::ios::ate); - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + image.resize(file.tellg()); -} + file.seekg(0, std::ios::beg); + if (!file.read(&image[0], image.size())) + std::cout << "error" << std::endl; + proto_query.add_blobs(image); -TEST(AddImage, simpleAdd) -{ - std::string addImg; - addImg += "[" + singleAddImage + "]"; + VDMS::protobufs::queryMessage response; + query_handler.pq(proto_query, response); - VDMSConfig::init("server/config-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); + Json::Reader json_reader; + Json::Value json_response; + json_reader.parse(response.json(), json_response); - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); + EXPECT_EQ(json_response[0]["AddImage"]["status"].asString(), "0"); + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); +} - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(addImg); +TEST(UpdateEntity, simpleAddUpdate) { + + Json::StyledWriter writer; + + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("server/AddFindUpdate.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + Json::Reader reader; + Json::Value root; + Json::Value parsed; + + VDMSConfig::init("server/config-update-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); + + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); + + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(json_query); + VDMS::protobufs::queryMessage response; + + query_handler.pq(proto_query, response); + + reader.parse(response.json().c_str(), parsed); + // std::cout << writer.write(parsed) << std::endl; + + // Verify results returned. + for (int j = 0; j < parsed.size(); j++) { + const Json::Value &query = parsed[j]; + ASSERT_EQ(query.getMemberNames().size(), 1); + std::string cmd = query.getMemberNames()[0]; + + if (cmd == "UpdateEntity") + EXPECT_EQ(query[cmd]["count"].asInt(), 1); + if (cmd == "FindEntity") { + EXPECT_EQ(query[cmd]["returned"].asInt(), 2); + EXPECT_EQ(query["FindEntity"]["entities"][0]["fv"].asString(), + "Missing property"); + } + } - std::string image; - std::ifstream file("test_images/brain.png", - std::ios::in | std::ios::binary | std::ios::ate); + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); +} - image.resize(file.tellg()); +TEST(AddImage, simpleAddx10) { + int total_images = 10; + std::string string_query("["); - file.seekg(0, std::ios::beg); - if( !file.read(&image[ 0 ], image.size())) - std::cout << "error" << std::endl; + for (int i = 0; i < total_images; ++i) { + string_query += singleAddImage; + if (i != total_images - 1) + string_query += ","; + } + string_query += "]"; - proto_query.add_blobs(image); + VDMSConfig::init("server/config-add10-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); - VDMS::protobufs::queryMessage response; - query_handler.pq(proto_query, response); + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); - Json::Reader json_reader; - Json::Value json_response; - json_reader.parse(response.json(), json_response); + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(string_query); - EXPECT_EQ(json_response[0]["AddImage"]["status"].asString(), "0"); - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); -} + std::string image; + std::ifstream file("test_images/brain.png", + std::ios::in | std::ios::binary | std::ios::ate); -TEST(UpdateEntity, simpleAddUpdate) -{ - - Json::StyledWriter writer; - - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("server/AddFindUpdate.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - Json::Reader reader; - Json::Value root; - Json::Value parsed; - - VDMSConfig::init("server/config-update-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); - - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); - - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(json_query); - VDMS::protobufs::queryMessage response; - - query_handler.pq(proto_query, response ); - - reader.parse(response.json().c_str(), parsed); - // std::cout << writer.write(parsed) << std::endl; - - // Verify results returned. - for (int j = 0; j < parsed.size(); j++) { - const Json::Value& query = parsed[j]; - ASSERT_EQ(query.getMemberNames().size(), 1); - std::string cmd = query.getMemberNames()[0]; - - if (cmd == "UpdateEntity") - EXPECT_EQ(query[cmd]["count"].asInt(), 1); - if (cmd == "FindEntity") { - EXPECT_EQ(query[cmd]["returned"].asInt(), 2); - EXPECT_EQ(query["FindEntity"]["entities"][0]["fv"].asString(), - "Missing property"); - } - } + image.resize(file.tellg()); - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); -} + file.seekg(0, std::ios::beg); + if (!file.read(&image[0], image.size())) + std::cout << "error" << std::endl; -TEST(AddImage, simpleAddx10) -{ - int total_images = 10; - std::string string_query("["); + for (int i = 0; i < total_images; ++i) { + proto_query.add_blobs(image); + } - for (int i = 0; i < total_images; ++i) { - string_query += singleAddImage; - if (i != total_images - 1) - string_query += ","; - } - string_query += "]"; + VDMS::protobufs::queryMessage response; + query_handler.pq(proto_query, response); - VDMSConfig::init("server/config-add10-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); + Json::Reader json_reader; + Json::Value json_response; - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); + // std::cout << response.json() << std::endl; + json_reader.parse(response.json(), json_response); - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(string_query); + for (int i = 0; i < total_images; ++i) { + EXPECT_EQ(json_response[i]["AddImage"]["status"].asString(), "0"); + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); +} - std::string image; - std::ifstream file("test_images/brain.png", - std::ios::in | std::ios::binary | std::ios::ate); +TEST(QueryHandler, AddAndFind) { + Json::StyledWriter writer; + + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("server/AddAndFind_query.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + Json::Reader reader; + Json::Value root; + Json::Value parsed; + reader.parse(json_query, root); + int in_node_num = 0, out_node_num = 0; + int in_edge_num = 0, out_edge_num = 0; + int in_query_num = 0, out_query_num = 0; + int in_props = 0, out_props = 0; + int success = 0; + bool list_found_before = false, average_found_before = false; + bool count_found_before = false, sum_found_before = false; + bool list_found_after = false, average_found_after = false; + bool count_found_after = false, sum_found_after = false; + double average_value = 0; + int count_value = 4342; + + for (int j = 0; j < root.size(); j++) { + const Json::Value &query = root[j]; + assert(query.getMemberNames().size() == 1); + std::string cmd = query.getMemberNames()[0]; + + if (cmd == "AddEntity") + in_node_num++; + + else if (cmd == "AddConnection") + in_edge_num++; + + else if (cmd == "FindEntity") { + in_query_num++; + if (query[cmd]["results"].isMember("list")) + list_found_before = true; + + if (query[cmd]["results"].isMember("average")) + average_found_before = true; + + if (query[cmd]["results"].isMember("sum")) + sum_found_before = true; + + if (query[cmd]["results"].isMember("count")) { + count_found_before = true; + } + } else if (query.isMember("properties")) + in_props = query["properties"].size(); + else if (cmd == "FindConnection") + in_query_num++; + else if (cmd == "UpdateConnection") { + count_found_before = true; + in_edge_num++; + } + } + + VDMSConfig::init("server/config-addfind-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); + + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); + + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(json_query); + VDMS::protobufs::queryMessage response; + + query_handler.pq(proto_query, response); + + reader.parse(response.json().c_str(), parsed); + // std::cout << writer.write(parsed) << std::endl; + + for (int j = 0; j < parsed.size(); j++) { + const Json::Value &query = parsed[j]; + ASSERT_EQ(query.getMemberNames().size(), 1); + std::string cmd = query.getMemberNames()[0]; + + if (cmd == "AddEntity") + out_node_num++; + if (cmd == "AddConnection") + out_edge_num++; + if (cmd == "UpdateConnection") + out_edge_num++; + if (cmd == "FindEntity" || cmd == "FindConnection") + out_query_num++; + + if (j == 11) { // Second Last FindEntity + EXPECT_EQ(query["FindEntity"]["entities"][2]["Study"].asString(), + "Missing property"); + + EXPECT_EQ(query["FindEntity"]["entities"][3]["Study"].asString(), + "Missing property"); + } - image.resize(file.tellg()); + if (j == 12) { // Last FindEntiy + EXPECT_EQ(query["FindEntity"]["entities"][0]["Birthday"].asString(), + "1946-10-07T17:59:24-07:00"); - file.seekg(0, std::ios::beg); - if( !file.read(&image[ 0 ], image.size())) - std::cout << "error" << std::endl; + EXPECT_EQ(query["FindEntity"]["entities"][1]["Birthday"].asString(), + "1936-10-01T17:59:24-07:00"); + } + if (j == 13) { // FindConnection + EXPECT_EQ( + query["FindConnection"]["connections"][0]["location"].asString(), + "residence"); - for (int i = 0; i < total_images; ++i) { - proto_query.add_blobs(image); + EXPECT_EQ(query["FindConnection"]["connections"][0]["city"].asString(), + "Boston"); } + if (query[cmd]["status"] == 0) + success++; - VDMS::protobufs::queryMessage response; - query_handler.pq(proto_query, response); + if (query[cmd].isMember("list")) + list_found_after = true; - Json::Reader json_reader; - Json::Value json_response; + if (query[cmd].isMember("average")) { + average_found_after = true; + average_value = query[cmd]["average"].asDouble(); + } - // std::cout << response.json() << std::endl; - json_reader.parse(response.json(), json_response); + if (query[cmd].isMember("sum")) + sum_found_after = true; - for (int i = 0; i < total_images; ++i) { - EXPECT_EQ(json_response[i]["AddImage"]["status"].asString(), "0"); + if (query[cmd].isMember("count")) { + count_found_after = true; + count_value = query[cmd]["count"].asInt(); } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + } + + int total_success = out_node_num + out_query_num + out_edge_num; + + EXPECT_EQ(in_node_num, out_node_num); + EXPECT_EQ(in_edge_num, out_edge_num); + EXPECT_EQ(in_query_num, out_query_num); + EXPECT_EQ(success, total_success); + EXPECT_EQ(average_found_before, average_found_after); + EXPECT_EQ(sum_found_before, sum_found_after); + EXPECT_EQ(count_found_before, count_found_after); + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(QueryHandler, AddAndFind) -{ - Json::StyledWriter writer; - - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("server/AddAndFind_query.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - Json::Reader reader; - Json::Value root; - Json::Value parsed; - reader.parse(json_query, root); - int in_node_num = 0, out_node_num = 0; - int in_edge_num = 0, out_edge_num = 0; - int in_query_num = 0, out_query_num = 0; - int in_props = 0, out_props = 0; - int success=0; - bool list_found_before = false, average_found_before = false; - bool count_found_before =false , sum_found_before =false; - bool list_found_after = false , average_found_after = false; - bool count_found_after =false , sum_found_after =false; - double average_value=0; - int count_value = 4342; - - for (int j = 0; j < root.size(); j++) { - const Json::Value& query = root[j]; - assert (query.getMemberNames().size() == 1); - std::string cmd = query.getMemberNames()[0]; - - if (cmd=="AddEntity") - in_node_num++; - - else if (cmd == "AddConnection") - in_edge_num++; - - else if (cmd == "FindEntity") { - in_query_num++; - if ( query[cmd]["results"].isMember("list") ) - list_found_before=true; - - if ( query[cmd]["results"].isMember("average") ) - average_found_before=true; - - if ( query[cmd]["results"].isMember("sum") ) - sum_found_before=true; - - if ( query[cmd]["results"].isMember("count") ) { - count_found_before=true; - } - } - else if (query.isMember("properties")) - in_props=query["properties"].size(); - else if (cmd == "FindConnection") - in_query_num++; - else if (cmd == "UpdateConnection") { - count_found_before=true; - in_edge_num++; - } +TEST(QueryHandler, EmptyResultCheck) { + Json::Reader reader; + Json::StyledWriter writer; + + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("server/EmptyResultChecks.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + VDMSConfig::init("server/config-emptyresult-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); + + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); + + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(json_query); + VDMS::protobufs::queryMessage response; + + query_handler.pq(proto_query, response); + + Json::Value parsed; + reader.parse(response.json().c_str(), parsed); + + for (int j = 0; j < parsed.size(); j++) { + const Json::Value &query = parsed[j]; + ASSERT_EQ(query.getMemberNames().size(), 1); + std::string cmd = query.getMemberNames()[0]; + + if (j == 6) { // Second last FindEntity + EXPECT_EQ(query["FindEntity"]["returned"].asInt(), 0); } - - VDMSConfig::init("server/config-addfind-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); - - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); - - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(json_query); - VDMS::protobufs::queryMessage response; - - query_handler.pq(proto_query, response ); - - reader.parse(response.json().c_str(), parsed); - // std::cout << writer.write(parsed) << std::endl; - - for (int j = 0; j < parsed.size(); j++) { - const Json::Value& query = parsed[j]; - ASSERT_EQ(query.getMemberNames().size(),1); - std::string cmd = query.getMemberNames()[0]; - - if (cmd=="AddEntity") - out_node_num++; - if (cmd=="AddConnection") - out_edge_num++; - if (cmd == "UpdateConnection") - out_edge_num++; - if (cmd == "FindEntity" || cmd == "FindConnection") - out_query_num++; - - if (j == 11) { // Second Last FindEntity - EXPECT_EQ(query["FindEntity"]["entities"][2]["Study"].asString(), - "Missing property"); - - EXPECT_EQ(query["FindEntity"]["entities"][3]["Study"].asString(), - "Missing property"); - } - - if (j == 12) { // Last FindEntiy - EXPECT_EQ(query["FindEntity"]["entities"][0]["Birthday"].asString(), - "1946-10-07T17:59:24-07:00"); - - EXPECT_EQ(query["FindEntity"]["entities"][1]["Birthday"].asString(), - "1936-10-01T17:59:24-07:00"); - } - if (j == 13) { // FindConnection - EXPECT_EQ(query["FindConnection"]["connections"][0]["location"].asString(), - "residence"); - - EXPECT_EQ(query["FindConnection"]["connections"][0]["city"].asString(), - "Boston"); - } - if ( query[cmd]["status"] == 0) - success++; - - if (query[cmd].isMember("list")) - list_found_after = true; - - if (query[cmd].isMember("average") ) { - average_found_after = true; - average_value = query[cmd]["average"].asDouble(); - } - - if (query[cmd].isMember("sum")) - sum_found_after = true; - - if (query[cmd].isMember("count")){ - count_found_after = true; - count_value = query[cmd]["count"].asInt(); - } - + if (j == 7) { // Last FindEntity + EXPECT_EQ(query["FindEntity"]["average"].asDouble(), 0); } - - int total_success = out_node_num + out_query_num + out_edge_num; - - EXPECT_EQ(in_node_num, out_node_num); - EXPECT_EQ(in_edge_num, out_edge_num); - EXPECT_EQ(in_query_num, out_query_num); - EXPECT_EQ(success, total_success); - EXPECT_EQ(average_found_before, average_found_after); - EXPECT_EQ(sum_found_before, sum_found_after); - EXPECT_EQ(count_found_before, count_found_after); - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); -} - -TEST(QueryHandler, EmptyResultCheck) -{ - Json::Reader reader; - Json::StyledWriter writer; - - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("server/EmptyResultChecks.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - VDMSConfig::init("server/config-emptyresult-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); - - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); - - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(json_query); - VDMS::protobufs::queryMessage response; - - query_handler.pq(proto_query, response ); - - Json::Value parsed; - reader.parse(response.json().c_str(), parsed); - - for (int j = 0; j < parsed.size(); j++) { - const Json::Value& query = parsed[j]; - ASSERT_EQ(query.getMemberNames().size(),1); - std::string cmd = query.getMemberNames()[0]; - - if (j == 6) { // Second last FindEntity - EXPECT_EQ(query["FindEntity"]["returned"].asInt(), 0); - } - if (j == 7) { // Last FindEntity - EXPECT_EQ(query["FindEntity"]["average"].asDouble(), 0); - } - if (j == 8) { // Last FindConnection - EXPECT_EQ(query["FindConnection"]["count"].asInt(), 0); - } + if (j == 8) { // Last FindConnection + EXPECT_EQ(query["FindConnection"]["count"].asInt(), 0); } + } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(QueryHandler, DataTypeChecks) -{ - Json::Reader reader; - Json::StyledWriter writer; - - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("server/DataTypeChecks.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - VDMSConfig::init("server/config-datatype-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); - - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); - - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(json_query); - VDMS::protobufs::queryMessage response; - - query_handler.pq(proto_query, response ); - - Json::Value parsed; - reader.parse(response.json().c_str(), parsed); - - // std::cout << writer.write(parsed) << std::endl; - const Json::Value& query = parsed[3]; - EXPECT_EQ(query["FindEntity"]["entities"][0]["Birthday"].asString(), "1936-10-01T17:59:24.001-07:00"); - EXPECT_EQ(query["FindEntity"]["entities"][0]["timestamp"].asInt64(), 1544069566053); - EXPECT_EQ(query["FindEntity"]["entities"][1]["Birthday"].asString(), "1946-10-01T17:49:24.009010-07:00"); - - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); +TEST(QueryHandler, DataTypeChecks) { + Json::Reader reader; + Json::StyledWriter writer; + + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("server/DataTypeChecks.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + VDMSConfig::init("server/config-datatype-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); + + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); + + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(json_query); + VDMS::protobufs::queryMessage response; + + query_handler.pq(proto_query, response); + + Json::Value parsed; + reader.parse(response.json().c_str(), parsed); + + // std::cout << writer.write(parsed) << std::endl; + const Json::Value &query = parsed[3]; + EXPECT_EQ(query["FindEntity"]["entities"][0]["Birthday"].asString(), + "1936-10-01T17:59:24.001-07:00"); + EXPECT_EQ(query["FindEntity"]["entities"][0]["timestamp"].asInt64(), + 1544069566053); + EXPECT_EQ(query["FindEntity"]["entities"][1]["Birthday"].asString(), + "1946-10-01T17:49:24.009010-07:00"); + + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(QueryHandler, AutoDeleteNode) -{ - Json::Reader reader; - - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("server/AutoDeleteNodeInit.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query_init = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - ifile.open("server/AutoDeleteNodeTest.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query_test = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - std::string image; - std::ifstream image_file("test_images/brain.png", - std::ios::in | std::ios::binary | std::ios::ate); - - image.resize(image_file.tellg()); - - image_file.seekg(0, std::ios::beg); - if( !image_file.read(&image[ 0 ], image.size())) - std::cout << "error" << std::endl; - - std::string video; - std::ifstream video_file("test_videos/Megamind.avi", - std::ios::in | std::ios::binary | std::ios::ate); - - video.resize(video_file.tellg()); - - video_file.seekg(0, std::ios::beg); - if( !video_file.read(&video[ 0 ], video.size())) - std::cout << "error" << std::endl; - - VDMSConfig::init("server/config-datatype-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); - - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); - - VDMS::protobufs::queryMessage proto_query_init; - proto_query_init.set_json(json_query_init); - proto_query_init.add_blobs(image); - proto_query_init.add_blobs(image); - proto_query_init.add_blobs(image); - proto_query_init.add_blobs(image); - proto_query_init.add_blobs(video); - proto_query_init.add_blobs(video); - - VDMS::protobufs::queryMessage response_init; - query_handler.pq(proto_query_init, response_init ); - - std::this_thread::sleep_for(12s); - - qh_base.set_autodelete_init_flag(); - qh_base.build_autodelete_queue(); //create priority queue of nodes with _expiration property - qh_base.regualar_run_autodelete(); // delete nodes that have expired since server previous closed - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - - VDMS::protobufs::queryMessage proto_query_test; - proto_query_test.set_json(json_query_test); - VDMS::protobufs::queryMessage response_test; - query_handler.pq(proto_query_test, response_test ); - Json::Value parsed; - reader.parse(response_test.json().c_str(), parsed); - - const Json::Value& query_1 = parsed[0]; - EXPECT_EQ(query_1["FindEntity"]["returned"], 2 ); - EXPECT_EQ(query_1["FindEntity"]["status"], 0); - const Json::Value& query_2 = parsed[1]; - EXPECT_EQ(query_2["FindImage"]["returned"], 2 ); - EXPECT_EQ(query_2["FindImage"]["status"], 0); - const Json::Value& query_3 = parsed[2]; - EXPECT_EQ(query_3["FindVideo"]["returned"], 1 ); - EXPECT_EQ(query_3["FindVideo"]["status"], 0); - - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); +TEST(QueryHandler, AutoDeleteNode) { + Json::Reader reader; + + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("server/AutoDeleteNodeInit.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query_init = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + ifile.open("server/AutoDeleteNodeTest.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query_test = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + std::string image; + std::ifstream image_file("test_images/brain.png", + std::ios::in | std::ios::binary | std::ios::ate); + + image.resize(image_file.tellg()); + + image_file.seekg(0, std::ios::beg); + if (!image_file.read(&image[0], image.size())) + std::cout << "error" << std::endl; + + std::string video; + std::ifstream video_file("test_videos/Megamind.avi", + std::ios::in | std::ios::binary | std::ios::ate); + + video.resize(video_file.tellg()); + + video_file.seekg(0, std::ios::beg); + if (!video_file.read(&video[0], video.size())) + std::cout << "error" << std::endl; + + VDMSConfig::init("server/config-datatype-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); + + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); + + VDMS::protobufs::queryMessage proto_query_init; + proto_query_init.set_json(json_query_init); + proto_query_init.add_blobs(image); + proto_query_init.add_blobs(image); + proto_query_init.add_blobs(image); + proto_query_init.add_blobs(image); + proto_query_init.add_blobs(video); + proto_query_init.add_blobs(video); + + VDMS::protobufs::queryMessage response_init; + query_handler.pq(proto_query_init, response_init); + + std::this_thread::sleep_for(12s); + + qh_base.set_autodelete_init_flag(); + qh_base.build_autodelete_queue(); // create priority queue of nodes with + // _expiration property + qh_base.regualar_run_autodelete(); // delete nodes that have expired since + // server previous closed + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + + VDMS::protobufs::queryMessage proto_query_test; + proto_query_test.set_json(json_query_test); + VDMS::protobufs::queryMessage response_test; + query_handler.pq(proto_query_test, response_test); + Json::Value parsed; + reader.parse(response_test.json().c_str(), parsed); + + const Json::Value &query_1 = parsed[0]; + EXPECT_EQ(query_1["FindEntity"]["returned"], 2); + EXPECT_EQ(query_1["FindEntity"]["status"], 0); + const Json::Value &query_2 = parsed[1]; + EXPECT_EQ(query_2["FindImage"]["returned"], 2); + EXPECT_EQ(query_2["FindImage"]["status"], 0); + const Json::Value &query_3 = parsed[2]; + EXPECT_EQ(query_3["FindVideo"]["returned"], 1); + EXPECT_EQ(query_3["FindVideo"]["status"], 0); + + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(QueryHandler, CustomFunctionNoProcess) -{ - Json::Reader reader; - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("server/CustomFunctionNoProcess.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; - std::string image; - std::ifstream image_file("test_images/brain.png", - std::ios::in | std::ios::binary | std::ios::ate); - - image.resize(image_file.tellg()); - - image_file.seekg(0, std::ios::beg); - if( !image_file.read(&image[ 0 ], image.size())) - std::cout << "error" << std::endl; - - VDMSConfig::init("server/config-datatype-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); - - - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(json_query); - proto_query.add_blobs(image); - VDMS::protobufs::queryMessage response; - query_handler.pq(proto_query, response); - Json::Value parsed; - - reader.parse(response.json().c_str(), parsed); - const Json::Value& query = parsed[0]; - EXPECT_EQ(query["info"], "custom function process not found"); - EXPECT_EQ(query["status"], -1); - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); +TEST(QueryHandler, CustomFunctionNoProcess) { + Json::Reader reader; + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("server/CustomFunctionNoProcess.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; + std::string image; + std::ifstream image_file("test_images/brain.png", + std::ios::in | std::ios::binary | std::ios::ate); + + image.resize(image_file.tellg()); + + image_file.seekg(0, std::ios::beg); + if (!image_file.read(&image[0], image.size())) + std::cout << "error" << std::endl; + + VDMSConfig::init("server/config-datatype-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); + + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(json_query); + proto_query.add_blobs(image); + VDMS::protobufs::queryMessage response; + query_handler.pq(proto_query, response); + Json::Value parsed; + + reader.parse(response.json().c_str(), parsed); + const Json::Value &query = parsed[0]; + EXPECT_EQ(query["info"], "custom function process not found"); + EXPECT_EQ(query["status"], -1); + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } +TEST(QueryHandler, AddUpdateFind_Blob) { -TEST(QueryHandler, AddUpdateFind_Blob) -{ - - Json::StyledWriter writer; + Json::StyledWriter writer; - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("server/AddFindUpdate_blob.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("server/AddFindUpdate_blob.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; - Json::Reader reader; - Json::Value root; - Json::Value parsed; + Json::Reader reader; + Json::Value root; + Json::Value parsed; - VDMSConfig::init("unit_tests/config-tests.json"); - PMGDQueryHandler::init(); - QueryHandler::init(); + VDMSConfig::init("unit_tests/config-tests.json"); + PMGDQueryHandler::init(); + QueryHandler::init(); - QueryHandler qh_base; - qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has been initialized - QueryHandlerTester query_handler(qh_base); + QueryHandler qh_base; + qh_base.reset_autodelete_init_flag(); // set flag to show autodelete queue has + // been initialized + QueryHandlerTester query_handler(qh_base); - VDMS::protobufs::queryMessage proto_query; - proto_query.set_json(json_query); + VDMS::protobufs::queryMessage proto_query; + proto_query.set_json(json_query); - std::string image; - std::ifstream file("test_images/brain.png", - std::ios::in | std::ios::binary | std::ios::ate); + std::string image; + std::ifstream file("test_images/brain.png", + std::ios::in | std::ios::binary | std::ios::ate); - image.resize(file.tellg()); + image.resize(file.tellg()); - file.seekg(0, std::ios::beg); - if( !file.read(&image[ 0 ], image.size())) - std::cout << "error" << std::endl; + file.seekg(0, std::ios::beg); + if (!file.read(&image[0], image.size())) + std::cout << "error" << std::endl; - proto_query.add_blobs(image); - VDMS::protobufs::queryMessage response; + proto_query.add_blobs(image); + VDMS::protobufs::queryMessage response; - query_handler.pq(proto_query, response ); + query_handler.pq(proto_query, response); - reader.parse(response.json().c_str(), parsed); - // std::cout << writer.write(parsed) << std::endl; + reader.parse(response.json().c_str(), parsed); + // std::cout << writer.write(parsed) << std::endl; - // Verify results returned. - for (int j = 0; j < parsed.size(); j++) { - const Json::Value& query = parsed[j]; - ASSERT_EQ(query.getMemberNames().size(), 1); - std::string cmd = query.getMemberNames()[0]; - EXPECT_EQ(query[cmd]["status"].asInt(), 0); - } + // Verify results returned. + for (int j = 0; j < parsed.size(); j++) { + const Json::Value &query = parsed[j]; + ASSERT_EQ(query.getMemberNames().size(), 1); + std::string cmd = query.getMemberNames()[0]; + EXPECT_EQ(query[cmd]["status"].asInt(), 0); + } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } diff --git a/tests/udf_test/functions/flip.py b/tests/udf_test/functions/flip.py new file mode 100644 index 00000000..59ee4f35 --- /dev/null +++ b/tests/udf_test/functions/flip.py @@ -0,0 +1,19 @@ +import time +import cv2 + + +def run(settings, message, input_params): + ipfilename = message + format = message.strip().split(".")[-1] + + t1 = time.time() + + opfilename = settings["opfile"] + str(t1) + "." + format + + img = cv2.imread(ipfilename) + + img = cv2.flip(img, 0) + + cv2.imwrite(opfilename, img) + + return (time.time() - t1), opfilename diff --git a/tests/udf_test/requirements.txt b/tests/udf_test/requirements.txt new file mode 100644 index 00000000..5ce1a8b4 --- /dev/null +++ b/tests/udf_test/requirements.txt @@ -0,0 +1,2 @@ +opencv-python==4.5.5.64 +zmq \ No newline at end of file diff --git a/tests/udf_test/settings.json b/tests/udf_test/settings.json new file mode 100644 index 00000000..2f7c4a3a --- /dev/null +++ b/tests/udf_test/settings.json @@ -0,0 +1,10 @@ +{ + "opfile": "/tmp/tmp_op_file", + "port": 5555, + "functions" : { + "facedetect" : "facedetect", + "flip": "flip", + "carcount": "carcount", + "activityrecognition": "activityrecognition" + } +} \ No newline at end of file diff --git a/tests/udf_test/syncremote.jpg b/tests/udf_test/syncremote.jpg new file mode 100644 index 00000000..e6343a7e Binary files /dev/null and b/tests/udf_test/syncremote.jpg differ diff --git a/tests/udf_test/udf_local.py b/tests/udf_test/udf_local.py new file mode 100644 index 00000000..aaf4a2ff --- /dev/null +++ b/tests/udf_test/udf_local.py @@ -0,0 +1,38 @@ +import os +import json +import zmq + +for entry in os.scandir("functions"): + if entry.is_file(): + string = f"from functions import {entry.name}"[:-3] + exec(string) + +with open("settings.json", "r") as settings_file: + settings_data = settings_file.read() + +# parse file +settings = json.loads(settings_data) + +context = zmq.Context() +socket = context.socket(zmq.REP) +socket.bind("tcp://*:" + str(settings["port"])) + +# print(globals()) +i = 0 +while True: + message = socket.recv() + + try: + message_received = message.decode("utf-8") + input_params = json.loads(message_received) + + udf = globals()[settings["functions"][input_params["id"]]] + + t, opfile = udf.run(settings, input_params["ipfile"], input_params) + + socket.send_string(opfile) + i += 1 + except Exception as e: + print(e.with_traceback(None)) + socket.send_string("An error occurred while running the operation.") + break diff --git a/tests/unit_tests/DescriptorSetAdd_test.cc b/tests/unit_tests/DescriptorSetAdd_test.cc index 148c5da3..958aafbc 100644 --- a/tests/unit_tests/DescriptorSetAdd_test.cc +++ b/tests/unit_tests/DescriptorSetAdd_test.cc @@ -29,645 +29,672 @@ * */ +#include +#include #include #include -#include #include #include -#include #include -#include "vcl/VCL.h" #include "helpers.h" +#include "vcl/VCL.h" #include "gtest/gtest.h" -TEST(Descriptors_Add, add_flatl2_100d) -{ - int d = 100; - int nb = 10000; +TEST(Descriptors_Add, add_flatl2_100d) { + int d = 100; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/add_flatl2_100d"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); + std::string index_filename = "dbs/add_flatl2_100d"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - index.add(xb, nb); + index.add(xb, nb); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - // std::cout << "DescriptorSet: " << std::endl; - for (auto& desc : desc_ids) { - // std::cout << desc << " "; - EXPECT_EQ(desc, exp++); - } + int exp = 0; + // std::cout << "DescriptorSet: " << std::endl; + for (auto &desc : desc_ids) { + // std::cout << desc << " "; + EXPECT_EQ(desc, exp++); + } - // std::cout << "Distances: " << std::endl; - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; + // std::cout << "Distances: " << std::endl; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; - for (int i = 0; i < 4; ++i) { - // std::cout << distances[i] << " "; - EXPECT_EQ(distances[i], results[i]); - } - // std::cout << std::endl; + for (int i = 0; i < 4; ++i) { + // std::cout << distances[i] << " "; + EXPECT_EQ(distances[i], results[i]); + } + // std::cout << std::endl; - index.store(); + index.store(); - delete [] xb; + delete[] xb; } +TEST(Descriptors_Add, add_and_radius_search_flatl2_100d) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); -TEST(Descriptors_Add, add_and_radius_search_flatl2_100d) -{ - int d = 100; - int nb = 10000; + std::string index_filename = "dbs/add_and_radius_search_flatl2_100d"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - float *xb = generate_desc_linear_increase(d, nb); - - std::string index_filename = "dbs/add_and_radius_search_flatl2_100d"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - - index.add(xb, nb); + index.add(xb, nb); - long* desc_ids = new long [20]; - float* distances = new float[20]; - index.radius_search(xb, 2000, desc_ids, distances); + long *desc_ids = new long[20]; + float *distances = new float[20]; + index.radius_search(xb, 2000, desc_ids, distances); - int exp = 0; + int exp = 0; - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; - for (int i = 0; i < 4; ++i) { - // std::cout << distances[i] << " "; - EXPECT_EQ(distances[i], results[i]); - } - // std::cout << std::endl; + for (int i = 0; i < 4; ++i) { + // std::cout << distances[i] << " "; + EXPECT_EQ(distances[i], results[i]); + } + // std::cout << std::endl; - index.store(); + index.store(); - delete [] xb; + delete[] xb; } +TEST(Descriptors_Add, add_ivfflatl2_100d) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); -TEST(Descriptors_Add, add_ivfflatl2_100d) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); - - std::string index_filename = "dbs/add_ivfflatl2_100d"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissIVFFlat); + std::string index_filename = "dbs/add_ivfflatl2_100d"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissIVFFlat); - std::vector classes(nb); + std::vector classes(nb); - for (auto& str : classes) { - str = 1; - } + for (auto &str : classes) { + str = 1; + } - index.add(xb, nb, classes); + index.add(xb, nb, classes); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - // std::cout << "DescriptorSet: " << std::endl; - for (auto& desc : desc_ids) { - // std::cout << desc << " "; - EXPECT_EQ(desc, exp++); - } - // std::cout << std::endl; + int exp = 0; + // std::cout << "DescriptorSet: " << std::endl; + for (auto &desc : desc_ids) { + // std::cout << desc << " "; + EXPECT_EQ(desc, exp++); + } + // std::cout << std::endl; - // std::cout << "Distances: " << std::endl; - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; - for (int i = 0; i < 4; ++i) { - // std::cout << distances[i] << " "; - EXPECT_EQ(distances[i], results[i]); - } - // std::cout << std::endl; + // std::cout << "Distances: " << std::endl; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; + for (int i = 0; i < 4; ++i) { + // std::cout << distances[i] << " "; + EXPECT_EQ(distances[i], results[i]); + } + // std::cout << std::endl; - index.store(); + index.store(); - delete [] xb; + delete[] xb; } -TEST(Descriptors_Add, add_recons_flatl2_100d) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); +TEST(Descriptors_Add, add_recons_flatl2_100d) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/add_recons_flatl2_100d"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); + std::string index_filename = "dbs/add_recons_flatl2_100d"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - std::vector classes(nb); + std::vector classes(nb); - for (auto& cl : classes) { - cl = 1; - } + for (auto &cl : classes) { + cl = 1; + } - index.add(xb, nb, classes); + index.add(xb, nb, classes); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); - desc_ids.clear(); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); + desc_ids.clear(); - float *recons = new float[d * nb]; - for (int i = 0; i < nb; ++i) { - desc_ids.push_back(i); - } + float *recons = new float[d * nb]; + for (int i = 0; i < nb; ++i) { + desc_ids.push_back(i); + } - index.get_descriptors(desc_ids, recons); + index.get_descriptors(desc_ids, recons); - for (int i = 0; i < nb*d; ++i) { - EXPECT_EQ(xb[i], recons[i]); - } + for (int i = 0; i < nb * d; ++i) { + EXPECT_EQ(xb[i], recons[i]); + } - index.store(); + index.store(); - delete [] xb; + delete[] xb; } -TEST(Descriptors_Add, add_flatl2_100d_2add) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); +TEST(Descriptors_Add, add_flatl2_100d_2add) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/add_flatl2_100d_2add"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); + std::string index_filename = "dbs/add_flatl2_100d_2add"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - index.add(xb, nb); + index.add(xb, nb); - generate_desc_linear_increase(d, nb, xb, .6); + generate_desc_linear_increase(d, nb, xb, .6); - index.add(xb, nb); + index.add(xb, nb); - generate_desc_linear_increase(d, 4, xb, 0); + generate_desc_linear_increase(d, 4, xb, 0); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(.6, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(1.6, 2)*d) }; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(std::round(distances[i]), std::round(results[i])); - } + float results[] = {float(std::pow(0, 2) * d), float(std::pow(.6, 2) * d), + float(std::pow(1, 2) * d), float(std::pow(1.6, 2) * d)}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(std::round(distances[i]), std::round(results[i])); + } - index.store(); - delete [] xb; + index.store(); + delete[] xb; } -//Flinng Tests - -TEST(Descriptors_Add, add_flinngIP_100d) -{ - int d = 100; - int nb = 10000; - float init=0.0; - int cluster_size=5; - float clusterhead_std=1.0; - float cluster_std=0.1; +// Flinng Tests - int n_clusters= floor((nb/cluster_size)); +TEST(Descriptors_Add, add_flinngIP_100d) { + int d = 100; + int nb = 10000; + float init = 0.0; + int cluster_size = 5; + float clusterhead_std = 1.0; + float cluster_std = 0.1; + int n_clusters = floor((nb / cluster_size)); - float *xb = generate_desc_normal_cluster(d, nb, init, cluster_size, clusterhead_std, cluster_std); - std::string index_filename = "dbs/add_flinngIP_100d"; + float *xb = generate_desc_normal_cluster(d, nb, init, cluster_size, + clusterhead_std, cluster_std); + std::string index_filename = "dbs/add_flinngIP_100d"; - VCL::DescriptorParams* param = new VCL::DescriptorParams(3, nb/10, 10, 12); - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, VCL::DistanceMetric::IP, param); - + VCL::DescriptorParams *param = new VCL::DescriptorParams(3, nb / 10, 10, 12); + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, + VCL::DistanceMetric::IP, param); - index.add_and_store(xb, nb); - index.finalize_index(); - - std::vector cluster_head(n_clusters * d); - std::vector descriptors(n_clusters*cluster_size); - std::vector distances(n_clusters*cluster_size); - - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < cluster_size; j++){ - if((i*cluster_size + j) % cluster_size == 0) { - for (int z = 0; z < d; z++) - cluster_head[i * d + z] = xb[ d*(i*cluster_size + j) + z]; - } - } - } + index.add_and_store(xb, nb); + index.finalize_index(); - //search with distances - index.search(cluster_head.data(), n_clusters, cluster_size, descriptors, distances); - + std::vector cluster_head(n_clusters * d); + std::vector descriptors(n_clusters * cluster_size); + std::vector distances(n_clusters * cluster_size); - int correct=0; - float recall=0.0; - for(int i = 0; i < n_clusters; ++i){ - for (int j = 0; j < cluster_size; ++j) { - if((i* cluster_size <= descriptors[i*cluster_size+j]) && (descriptors[i*cluster_size+j] < (i+1)*cluster_size)) - correct++; + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < cluster_size; j++) { + if ((i * cluster_size + j) % cluster_size == 0) { + for (int z = 0; z < d; z++) + cluster_head[i * d + z] = xb[d * (i * cluster_size + j) + z]; } } - recall=static_cast(correct) /(n_clusters*cluster_size); - //std::cout << "\n Recall (Angular Similarity) = " << recall << std::endl; - EXPECT_GE(recall, 0.7); + } + + // search with distances + index.search(cluster_head.data(), n_clusters, cluster_size, descriptors, + distances); + + int correct = 0; + float recall = 0.0; + for (int i = 0; i < n_clusters; ++i) { + for (int j = 0; j < cluster_size; ++j) { + if ((i * cluster_size <= descriptors[i * cluster_size + j]) && + (descriptors[i * cluster_size + j] < (i + 1) * cluster_size)) + correct++; + } + } + recall = static_cast(correct) / (n_clusters * cluster_size); + // std::cout << "\n Recall (Angular Similarity) = " << recall << std::endl; + EXPECT_GE(recall, 0.7); + + // search without returning distances + std::vector descriptors2(n_clusters * cluster_size); + index.search(cluster_head.data(), n_clusters, cluster_size, descriptors2); - //search without returning distances - std::vector descriptors2(n_clusters*cluster_size); - index.search(cluster_head.data(), n_clusters, cluster_size, descriptors2); - - EXPECT_EQ(descriptors,descriptors2); + EXPECT_EQ(descriptors, descriptors2); + index.store(); - index.store(); - - delete [] xb; + delete[] xb; } +TEST(Descriptors_Add, add_flinngL2_100d) { + int d = 100; + int nb = 10000; + float init = 0.0; + int cluster_size = 5; + float clusterhead_std = 1.0; + float cluster_std = 0.1; + + int n_clusters = floor((nb / cluster_size)); + + float *xb = generate_desc_normal_cluster(d, nb, init, cluster_size, + clusterhead_std, cluster_std); + std::string index_filename = "dbs/add_flinngL2_100d"; + + VCL::DescriptorParams *param = new VCL::DescriptorParams(3, nb / 10, 10, 12); + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, + VCL::DistanceMetric::L2, param); + + index.add_and_store(xb, nb); + index.finalize_index(); + std::vector cluster_head(n_clusters * d); + std::vector descriptors(n_clusters * cluster_size); + std::vector distances(n_clusters * cluster_size); -TEST(Descriptors_Add, add_flinngL2_100d) -{ - int d = 100; - int nb = 10000; - float init=0.0; - int cluster_size=5; - float clusterhead_std=1.0; - float cluster_std=0.1; + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < cluster_size; j++) { + if ((i * cluster_size + j) % cluster_size == 0) { + for (int z = 0; z < d; z++) + cluster_head[i * d + z] = xb[d * (i * cluster_size + j) + z]; + } + } + } + + index.search(cluster_head.data(), n_clusters, cluster_size, descriptors, + distances); + + int correct = 0; + float recall = 0.0; + for (int i = 0; i < n_clusters; ++i) { + for (int j = 0; j < cluster_size; ++j) { + if ((i * cluster_size <= descriptors[i * cluster_size + j]) && + (descriptors[i * cluster_size + j] < (i + 1) * cluster_size)) + correct++; + } + } + recall = static_cast(correct) / (n_clusters * cluster_size); + EXPECT_GE(recall, 0.7); - int n_clusters= floor((nb/cluster_size)); + // search without returning distances + std::vector descriptors2(n_clusters * cluster_size); + index.search(cluster_head.data(), n_clusters, cluster_size, descriptors2); + + EXPECT_EQ(descriptors, descriptors2); + + index.store(); + delete[] xb; +} +TEST(Descriptors_Add, add_recons_flinngIP_100d) { + int d = 100; + int nb = 10000; + float init = 0.0; + int cluster_size = 5; + float clusterhead_std = 1.0; + float cluster_std = 0.1; - float *xb = generate_desc_normal_cluster(d, nb, init, cluster_size, clusterhead_std, cluster_std); - std::string index_filename = "dbs/add_flinngL2_100d"; + int n_clusters = floor((nb / cluster_size)); - VCL::DescriptorParams* param = new VCL::DescriptorParams(3, nb/10, 10, 12); - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, VCL::DistanceMetric::L2, param); - + float *xb = generate_desc_normal_cluster(d, nb, init, cluster_size, + clusterhead_std, cluster_std); + std::string index_filename = "dbs/add_recons_flinngIP_100d"; - index.add_and_store(xb, nb); - index.finalize_index(); + VCL::DescriptorParams *param = new VCL::DescriptorParams(3, nb / 10, 10, 12); + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, + VCL::DistanceMetric::IP, param); - std::vector cluster_head(n_clusters * d); - std::vector descriptors(n_clusters*cluster_size); - std::vector distances(n_clusters*cluster_size); + std::vector classes(nb); - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < cluster_size; j++){ - if((i*cluster_size + j) % cluster_size == 0) { - for (int z = 0; z < d; z++) - cluster_head[i * d + z] = xb[ d*(i*cluster_size + j) + z]; - } - } + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < cluster_size; j++) { + classes[i * cluster_size + j] = i; } + } - index.search(cluster_head.data(), n_clusters, cluster_size, descriptors, distances); + index.add_and_store(xb, nb, classes); + index.finalize_index(); - int correct=0; - float recall=0.0; - for(int i = 0; i < n_clusters; ++i){ - for (int j = 0; j < cluster_size; ++j) { - if((i* cluster_size <= descriptors[i*cluster_size+j]) && (descriptors[i*cluster_size+j] < (i+1)*cluster_size)) - correct++; + std::vector cluster_head(n_clusters * d); + std::vector descriptors(n_clusters * cluster_size); + std::vector distances(n_clusters * cluster_size); + + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < cluster_size; j++) { + if ((i * cluster_size + j) % cluster_size == 0) { + for (int z = 0; z < d; z++) + cluster_head[i * d + z] = xb[d * (i * cluster_size + j) + z]; } } - recall=static_cast(correct) /(n_clusters*cluster_size); - EXPECT_GE(recall, 0.7); - - //search without returning distances - std::vector descriptors2(n_clusters*cluster_size); - index.search(cluster_head.data(), n_clusters, cluster_size, descriptors2); - - EXPECT_EQ(descriptors,descriptors2); - - index.store(); - delete [] xb; -} + } + index.search(cluster_head.data(), n_clusters, cluster_size, descriptors); + descriptors.clear(); -TEST(Descriptors_Add, add_recons_flinngIP_100d) -{ - int d = 100; - int nb = 10000; - float init=0.0; - int cluster_size=5; - float clusterhead_std=1.0; - float cluster_std=0.1; + float *recons = new float[d * nb]; + for (int i = 0; i < nb; ++i) { + descriptors.push_back(i); + } - int n_clusters= floor((nb/cluster_size)); + index.get_descriptors(descriptors, recons); + for (int i = 0; i < nb * d; ++i) { + EXPECT_EQ(xb[i], recons[i]); + } - float *xb = generate_desc_normal_cluster(d, nb, init, cluster_size, clusterhead_std, cluster_std); - std::string index_filename = "dbs/add_recons_flinngIP_100d"; + index.store(); - VCL::DescriptorParams* param = new VCL::DescriptorParams(3, nb/10, 10, 12); - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, VCL::DistanceMetric::IP, param); - - std::vector classes(nb); + delete[] xb; +} - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < cluster_size; j++){ - classes[i*cluster_size + j] = i; - } +TEST(Descriptors_Add, add_flinngIP_100d_2add) { + int d = 100; + int nb = 10000; + float init = 0.0; + int cluster_size = 5; + float clusterhead_std = 1.0; + float cluster_std = 0.1; + int cluster_increment = 2; + + int n_clusters = floor((nb / cluster_size)); + + float *xb = generate_desc_normal_cluster(d, nb, init, cluster_size, + clusterhead_std, cluster_std); + std::string index_filename = "dbs/add_flingIP_100d_2add"; + + VCL::DescriptorParams *param = new VCL::DescriptorParams(3, nb / 10, 10, 12); + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, + VCL::DistanceMetric::IP, param); + + index.add_and_store(xb, nb); + index.finalize_index(); + + std::vector cluster_head(n_clusters * d); + std::vector descriptors(n_clusters * cluster_size); + std::vector distances(n_clusters * cluster_size); + + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < cluster_size; j++) { + if ((i * cluster_size + j) % cluster_size == 0) { + for (int z = 0; z < d; z++) + cluster_head[i * d + z] = xb[d * (i * cluster_size + j) + z]; + } } + } - index.add_and_store(xb, nb,classes); - index.finalize_index(); - - std::vector cluster_head(n_clusters * d); - std::vector descriptors(n_clusters*cluster_size); - std::vector distances(n_clusters*cluster_size); + float *new_neighbors = create_additional_neighbors( + d, cluster_increment, n_clusters, cluster_head.data(), cluster_std); - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < cluster_size; j++){ - if((i*cluster_size + j) % cluster_size == 0) { - for (int z = 0; z < d; z++) - cluster_head[i * d + z] = xb[ d*(i*cluster_size + j) + z]; - } - } - } + index.add_and_store(new_neighbors, + n_clusters * cluster_increment); // add 2nd time + index.finalize_index(); - index.search(cluster_head.data(), n_clusters, cluster_size, descriptors); - descriptors.clear(); + cluster_size += cluster_increment; + descriptors.resize(n_clusters * cluster_size); - float *recons = new float[d * nb]; - for (int i = 0; i < nb; ++i) { - descriptors.push_back(i); - } + index.search(cluster_head.data(), n_clusters, cluster_size, descriptors); - index.get_descriptors(descriptors, recons); + int correct = 0; + float recall = 0.0; + int old_cluster_size = cluster_size - cluster_increment; - for (int i = 0; i < nb*d; ++i) { - EXPECT_EQ(xb[i], recons[i]); + for (int i = 0; i < n_clusters; ++i) { + for (int j = 0; j < cluster_size; ++j) { + if ((i * old_cluster_size <= descriptors[i * cluster_size + j]) && + (descriptors[i * cluster_size + j] < (i + 1) * old_cluster_size)) { + correct++; // within the old cluster + } + if (((nb + i * cluster_increment) <= descriptors[i * cluster_size + j]) && + (descriptors[i * cluster_size + j] < + (nb + (i + 1) * cluster_increment))) { + correct++; // within the new neighbors appended at end of index + } } + } + recall = static_cast(correct) / (n_clusters * cluster_size); + // std::cout <<"2 adds Recall = " << recall < cluster_head(n_clusters * d); - float *xb = generate_desc_normal_cluster(d, nb, init, cluster_size, clusterhead_std, cluster_std); - std::string index_filename = "dbs/add_flingIP_100d_2add"; + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < cluster_size; j++) { + if ((i * cluster_size + j) % cluster_size == 0) { + for (int z = 0; z < d; z++) + cluster_head[i * d + z] = xb[d * (i * cluster_size + j) + z]; + } + } + } - VCL::DescriptorParams* param = new VCL::DescriptorParams(3, nb/10, 10, 12); - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, VCL::DistanceMetric::IP, param); - + index.add_and_store(xb, nb); // adding same vectors again + index.finalize_index(); + // std::cout << "\n Total number of elements = " << index.get_n_descriptors() + // << std::endl; - index.add_and_store(xb, nb); - index.finalize_index(); + std::vector descriptors(n_clusters * cluster_size * 2); - std::vector cluster_head(n_clusters * d); - std::vector descriptors(n_clusters*cluster_size); - std::vector distances(n_clusters*cluster_size); + index.search(cluster_head.data(), n_clusters, cluster_size * 2, descriptors); - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < cluster_size; j++){ - if((i*cluster_size + j) % cluster_size == 0) { - for (int z = 0; z < d; z++) - cluster_head[i * d + z] = xb[ d*(i*cluster_size + j) + z]; - } - } + int correct = 0; + float recall = 0.0; + for (int i = 0; i < n_clusters; ++i) { + for (int j = 0; j < cluster_size * 2; ++j) { + if ((i * cluster_size <= descriptors[i * cluster_size * 2 + j]) && + (descriptors[i * cluster_size * 2 + j] < (i + 1) * cluster_size)) { + correct++; // within the first added nb elements + } + if (((nb + i * cluster_size) <= descriptors[i * cluster_size * 2 + j]) && + (descriptors[i * cluster_size * 2 + j] < + (nb + (i + 1) * cluster_size))) { + correct++; // within the 2nd added nb elements appended at the end of + // index + } } + } + recall = static_cast(correct) / (n_clusters * cluster_size * 2); + // std::cout << "\n Recall (Angular Similarity) = " << recall << std::endl; + EXPECT_GE(recall, 0.7); - - float *new_neighbors = create_additional_neighbors(d, cluster_increment, n_clusters, cluster_head.data(), cluster_std); - - - index.add_and_store(new_neighbors, n_clusters*cluster_increment); //add 2nd time - index.finalize_index(); - - - cluster_size += cluster_increment; - descriptors.resize(n_clusters*cluster_size); - - index.search(cluster_head.data(), n_clusters, cluster_size, descriptors); - - - int correct=0; - float recall=0.0; - int old_cluster_size = cluster_size - cluster_increment; - - for(int i = 0; i < n_clusters; ++i){ - for (int j = 0; j < cluster_size ; ++j) { - if((i* old_cluster_size <= descriptors[i*cluster_size+j]) && (descriptors[i*cluster_size+j] < (i+1)*old_cluster_size)){ - correct++; //within the old cluster - } - if(((nb+ i*cluster_increment) <= descriptors[i*cluster_size+j]) && (descriptors[i*cluster_size+j] < (nb+(i+1)*cluster_increment))){ - correct++; //within the new neighbors appended at end of index - } - } - } - recall=static_cast(correct) /(n_clusters*cluster_size); - //std::cout <<"2 adds Recall = " << recall < distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - VCL::DescriptorParams* param = new VCL::DescriptorParams(3, nb/10, 10, 12); - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, VCL::DistanceMetric::IP, param); - + int exp = 0; + // std::cout << "DescriptorSet: " << std::endl; + for (auto &desc : desc_ids) { + // std::cout << desc << " "; + EXPECT_EQ(desc, exp++); + } - index.add_and_store(xb, nb); - + // std::cout << "Distances: " << std::endl; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; + for (int i = 0; i < 4; ++i) { + // std::cout << distances[i] << " "; + EXPECT_EQ(distances[i], results[i]); + } + // std::cout << std::endl; - std::vector cluster_head(n_clusters * d); - - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < cluster_size; j++){ - if((i*cluster_size + j) % cluster_size == 0) { - for (int z = 0; z < d; z++) - cluster_head[i * d + z] = xb[ d*(i*cluster_size + j) + z]; - } - } - } + index.store(); + delete[] xb; +} - index.add_and_store(xb, nb); //adding same vectors again - index.finalize_index(); - //std::cout << "\n Total number of elements = " << index.get_n_descriptors() << std::endl; +TEST(Descriptors_Add, add_tiledbdense_100d_2add) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); - std::vector descriptors(n_clusters*cluster_size* 2); + std::string index_filename = "dbs/add_tiledbdense_100d_2add"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBDense); - index.search(cluster_head.data(), n_clusters, cluster_size* 2, descriptors); - + index.add(xb, nb); - int correct=0; - float recall=0.0; - for(int i = 0; i < n_clusters; ++i){ - for (int j = 0; j < cluster_size* 2; ++j) { - if((i* cluster_size <= descriptors[i*cluster_size*2+j]) && (descriptors[i*cluster_size*2+j] < (i+1)*cluster_size)){ - correct++; //within the first added nb elements - } - if(((nb+ i*cluster_size) <= descriptors[i*cluster_size*2+j]) && (descriptors[i*cluster_size*2+j] < (nb+(i+1)*cluster_size))){ - correct++; //within the 2nd added nb elements appended at the end of index - } + generate_desc_linear_increase(d, nb, xb, .6); - } - } - recall=static_cast(correct) /(n_clusters*cluster_size*2); - //std::cout << "\n Recall (Angular Similarity) = " << recall << std::endl; - EXPECT_GE(recall, 0.7); + index.add(xb, nb); - index.store(); - - delete [] xb; -} + generate_desc_linear_increase(d, 4, xb, 0); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); + float results[] = {float(std::pow(0, 2) * d), float(std::pow(.6, 2) * d), + float(std::pow(1, 2) * d), float(std::pow(1.6, 2) * d)}; + // This is: + // (0) ^2 * 100 = 0 + // (0.6)^2 * 100 = 36 + // (1 )^2 * 100 = 100 + // (1.6)^2 * 100 = 256 + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(std::round(distances[i]), std::round(results[i])); + // printf(" %f, %f \n", float(distances[i]), float(results[i])); + } + index.store(); + delete[] xb; +} +// TileDB Sparse +// #define TDB_SPARSE +// #ifdef TDB_SPARSE +TEST(Descriptors_Add, add_tiledbsparse_100d_2add) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); + // generate_desc_linear_increase(d, nb, xb, .1); -// TileDB Dense Tests + std::string index_filename = "dbs/add_tiledbsparse_100d_2add"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBSparse); -TEST(Descriptors_Add, add_tiledbdense_100d) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + index.add(xb, nb); - std::string index_filename = "dbs/add_tiledbdense_100d_tdb"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBDense); + generate_desc_linear_increase(d, nb, xb, .6); - index.add(xb, nb); + index.add(xb, nb); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + generate_desc_linear_increase(d, 4, xb, 0); - int exp = 0; - // std::cout << "DescriptorSet: " << std::endl; - for (auto& desc : desc_ids) { - // std::cout << desc << " "; - EXPECT_EQ(desc, exp++); - } + std::vector distances; + std::vector desc_ids; + index.search(xb, 2, 4, desc_ids, distances); - // std::cout << "Distances: " << std::endl; - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; - for (int i = 0; i < 4; ++i) { - // std::cout << distances[i] << " "; - EXPECT_EQ(distances[i], results[i]); - } - // std::cout << std::endl; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(.6, 2) * d), + float(std::pow(1, 2) * d), float(std::pow(1.6, 2) * d)}; - index.store(); + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(std::round(distances[i]), std::round(results[i])); + } - delete [] xb; + index.store(); + delete[] xb; } -TEST(Descriptors_Add, add_tiledbdense_100d_2add) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); +TEST(Descriptors_Add, add_tiledbsparse_100d) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); + // generate_desc_linear_increase(d, nb, xb, .1); - std::string index_filename = "dbs/add_tiledbdense_100d_2add"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBDense); + std::string index_filename = "dbs/add_tiledbsparse_100d"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBSparse); - index.add(xb, nb); + index.add(xb, nb); - generate_desc_linear_increase(d, nb, xb, .6); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - index.add(xb, nb); + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; - generate_desc_linear_increase(d, 4, xb, 0); + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(std::round(distances[i]), std::round(results[i])); + } - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + index.store(); + delete[] xb; +} - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(.6, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(1.6, 2)*d) }; - // This is: - // (0) ^2 * 100 = 0 - // (0.6)^2 * 100 = 36 - // (1 )^2 * 100 = 100 - // (1.6)^2 * 100 = 256 +TEST(Descriptors_Add, add_2_times_same_tdbsparse) { + int nb = 1000; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(std::round(distances[i]), std::round(results[i])); - // printf(" %f, %f \n", float(distances[i]), float(results[i])); - } + auto dimensions_list = get_dimensions_list(); - index.store(); - delete [] xb; -} + for (auto d : dimensions_list) { -// TileDB Sparse + float *xb = generate_desc_linear_increase(d, nb); -#define TDB_SPARSE -#ifdef TDB_SPARSE + auto eng = VCL::TileDBSparse; -TEST(Descriptors_Add, add_tiledbsparse_100d_2add) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); - // generate_desc_linear_increase(d, nb, xb, .1); + std::string index_filename = "dbs/add_2_times_same_tdbsparse_" + + std::to_string(d) + "_" + std::to_string(eng); - std::string index_filename = "dbs/add_tiledbsparse_100d_2add"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBSparse); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); index.add(xb, nb); - generate_desc_linear_increase(d, nb, xb, .6); + generate_desc_linear_increase(d, nb, xb, 10); index.add(xb, nb); @@ -675,455 +702,356 @@ TEST(Descriptors_Add, add_tiledbsparse_100d_2add) std::vector distances; std::vector desc_ids; - index.search(xb, 2, 4, desc_ids, distances); + index.search(xb, 1, 4, desc_ids, distances); - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(.6, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(1.6, 2)*d) }; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; for (int i = 0; i < 4; ++i) { - EXPECT_EQ(std::round(distances[i]), std::round(results[i])); + EXPECT_NEAR((distances[i]), (results[i]), .5f); } - index.store(); - delete [] xb; + delete[] xb; + } } -TEST(Descriptors_Add, add_tiledbsparse_100d) -{ - int d = 100; - int nb = 10000; +TEST(Descriptors_Add, add_2_times_tdbsparse) { + int nb = 10000; + + auto dimensions_list = get_dimensions_list(); + + for (auto d : dimensions_list) { + float *xb = generate_desc_linear_increase(d, nb); - // generate_desc_linear_increase(d, nb, xb, .1); - std::string index_filename = "dbs/add_tiledbsparse_100d"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBSparse); + auto eng = VCL::TileDBSparse; + + std::string index_filename = "dbs/add_2_times_tdbsparse_" + + std::to_string(d) + "_" + std::to_string(eng); + + VCL::DescriptorSet index(index_filename, unsigned(d), eng); + + index.add(xb, nb); + + generate_desc_linear_increase(d, nb, xb, .6); index.add(xb, nb); + generate_desc_linear_increase(d, 4, xb, 0); + std::vector distances; std::vector desc_ids; index.search(xb, 1, 4, desc_ids, distances); - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(.6, 2) * d), + float(std::pow(1, 2) * d), float(std::pow(1.6, 2) * d)}; for (int i = 0; i < 4; ++i) { - EXPECT_EQ(std::round(distances[i]), std::round(results[i])); + EXPECT_NEAR((distances[i]), (results[i]), .5f); } - index.store(); - delete [] xb; + delete[] xb; + } } -TEST(Descriptors_Add, add_2_times_same_tdbsparse) -{ - int nb = 10000; +// #endif - auto dimensions_list = get_dimensions_list(); +// ---------- - for (auto d : dimensions_list) { +TEST(Descriptors_Add, add_and_search_10k) { + int nb = 10000; + auto dimensions_list = get_dimensions_list(); - float *xb = generate_desc_linear_increase(d, nb); + for (auto d : dimensions_list) { - auto eng = VCL::TileDBSparse; + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/add_2_times_same_tdbsparse_" + - std::to_string(d) + "_" + - std::to_string(eng); + for (auto eng : get_engines()) { + std::string index_filename = "dbs/add_and_search_10k" + + std::to_string(d) + "_" + + std::to_string(eng); - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + /* + //Disbaled FLINNG, since dataset is not normalized + //Todo in future versions add support for arbitrary datasets + VCL::DescriptorParams* param = NULL; - index.add(xb, nb); + if (eng == VCL::Flinng) + param = new VCL::DescriptorParams(3, nb/10, 10, 12); - generate_desc_linear_increase(d, nb, xb, 10000); + VCL::DescriptorSet index(index_filename, unsigned(d), eng, + VCL::DistanceMetric::L2, param); + */ + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - index.add(xb, nb); + /* + if (eng == VCL::Flinng){ + index.add_and_store(xb, nb); + index.finalize_index(); + } + else{ + index.add(xb, nb); + } + */ - generate_desc_linear_increase(d, 4, xb, 0); + index.add(xb, nb); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; + int exp = 0; + // std::cout << "DescriptorSet: " << std::endl; + for (auto &desc : desc_ids) { + // std::cout << desc << " "; + EXPECT_EQ(desc, exp++); + } - for (int i = 0; i < 4; ++i) { - EXPECT_NEAR((distances[i]), (results[i]), .5f); - } + // std::cout << "Distances: " << std::endl; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; + for (int i = 0; i < 4; ++i) { + // std::cout << distances[i] << " "; + EXPECT_EQ(distances[i], results[i]); + } + // std::cout << std::endl; - delete [] xb; + index.store(); } -} -TEST(Descriptors_Add, add_2_times_tdbsparse) -{ - int nb = 10000; - - auto dimensions_list = get_dimensions_list(); - - for (auto d : dimensions_list) { - - float *xb = generate_desc_linear_increase(d, nb); - - auto eng = VCL::TileDBSparse; + delete[] xb; + } +} - std::string index_filename = "dbs/add_2_times_tdbsparse_" + - std::to_string(d) + "_" + - std::to_string(eng); +TEST(Descriptors_Add, add_and_search_10k_negative) { + int nb = 10000; + auto dimensions_list = get_dimensions_list(); - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + for (auto d : dimensions_list) { - index.add(xb, nb); + float *xb = generate_desc_linear_increase(d, nb, -900); - generate_desc_linear_increase(d, nb, xb, .6); + for (auto eng : get_engines()) { + std::string index_filename = "dbs/add_and_search_10k_negative" + + std::to_string(d) + "_" + + std::to_string(eng); - index.add(xb, nb); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - generate_desc_linear_increase(d, 4, xb, 0); + index.add(xb, nb); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(.6, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(1.6, 2)*d) }; + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - for (int i = 0; i < 4; ++i) { - EXPECT_NEAR((distances[i]), (results[i]), .5f); - } + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - delete [] xb; + index.store(); } -} -#endif + delete[] xb; + } +} -// ---------- +TEST(Descriptors_Add, add_1by1_and_search_1k) { + int nb = 1000; + auto dimensions_list = get_dimensions_list(); -TEST(Descriptors_Add, add_and_search_10k) -{ - int nb = 10000; - auto dimensions_list = get_dimensions_list(); - - for (auto d : dimensions_list) { - - float *xb = generate_desc_linear_increase(d, nb); - - for (auto eng : get_engines()) { - std::string index_filename = "dbs/add_and_search_10k" + - std::to_string(d) + "_" + - std::to_string(eng); - - - - - - /* - //Disbaled FLINNG, since dataset is not normalized - //Todo in future versions add support for arbitrary datasets - VCL::DescriptorParams* param = NULL; - - if (eng == VCL::Flinng) - param = new VCL::DescriptorParams(3, nb/10, 10, 12); - - VCL::DescriptorSet index(index_filename, unsigned(d), eng, VCL::DistanceMetric::L2, param); - */ - VCL::DescriptorSet index(index_filename, unsigned(d), eng); - - /* - if (eng == VCL::Flinng){ - index.add_and_store(xb, nb); - index.finalize_index(); - } - else{ - index.add(xb, nb); - } - */ - - index.add(xb, nb); - - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); - - int exp = 0; - // std::cout << "DescriptorSet: " << std::endl; - for (auto& desc : desc_ids) { - // std::cout << desc << " "; - EXPECT_EQ(desc, exp++); - } - - // std::cout << "Distances: " << std::endl; - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; - for (int i = 0; i < 4; ++i) { - // std::cout << distances[i] << " "; - EXPECT_EQ(distances[i], results[i]); - } - // std::cout << std::endl; - - index.store(); - } - - delete [] xb; - } -} + for (auto d : dimensions_list) { -TEST(Descriptors_Add, add_and_search_10k_negative) -{ - int nb = 10000; - auto dimensions_list = get_dimensions_list(); + float *xb = generate_desc_linear_increase(d, nb); - for (auto d : dimensions_list) { + for (auto eng : get_engines()) { - float *xb = generate_desc_linear_increase(d, nb, -900); + // It does not make sense to run on this index + if (eng == VCL::FaissIVFFlat) + continue; - for (auto eng : get_engines()) { - std::string index_filename = "dbs/add_and_search_10k_negative" + - std::to_string(d) + "_" + - std::to_string(eng); + std::string index_filename = "dbs/add_1by1_and_search_1k_" + + std::to_string(d) + "_" + + std::to_string(eng); - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - index.add(xb, nb); + printf("eng: %d \n", eng); + for (int i = 0; i < nb; ++i) { + index.add(xb + i * d, 1); + } - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + printf("about to start search... \n"); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + printf("done search\n"); - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - index.store(); - } + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - delete [] xb; + index.store(); + printf("done store\n"); } -} -TEST(Descriptors_Add, add_1by1_and_search_1k) -{ - int nb = 1000; - auto dimensions_list = get_dimensions_list(); - - for (auto d : dimensions_list) { + delete[] xb; + } +} - float *xb = generate_desc_linear_increase(d, nb); +TEST(Descriptors_Add, add_and_search_2_neigh_10k) { + int nb = 10000; + auto dimensions_list = get_dimensions_list(); - for (auto eng : get_engines()) { + for (auto d : dimensions_list) { - // It does not make sense to run on this index - if (eng == VCL::FaissIVFFlat) - continue; + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/add_1by1_and_search_1k_" + - std::to_string(d) + "_" + - std::to_string(eng); + for (auto eng : get_engines()) { + std::string index_filename = "dbs/add_and_search_2_neigh_10k" + + std::to_string(d) + "_" + + std::to_string(eng); - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - printf("eng: %d \n",eng ); - for (int i = 0; i < nb; ++i) { - index.add(xb + i*d, 1); - } + index.add(xb, nb); - printf("about to start search... \n"); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 2, 4, desc_ids, distances); - printf("done search\n"); + // Does not matter much, but good to test + // int exp[] = {0, 1, 2, 3, 1, 2, 0, 3}; + // int idx = 0; + // // std::cout << "DescriptorSet: " << std::endl; + // for (auto& desc : desc_ids) { + // // std::cout << desc << " "; + // EXPECT_EQ(desc, exp[idx++]); + // } - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + // std::cout << "Distances: " << std::endl; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; + for (int i = 0; i < 4; ++i) { + // std::cout << distances[i] << " "; + EXPECT_EQ(distances[i], results[i]); + } - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + float results_2[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d)}; - index.store(); - printf("done store\n"); - } + for (int i = 4; i < 8; ++i) { + // std::cout << distances[i] << " "; + EXPECT_EQ(distances[i], results_2[i - 4]); + } + // std::cout << std::endl; - delete [] xb; + index.store(); } -} -TEST(Descriptors_Add, add_and_search_2_neigh_10k) -{ - int nb = 10000; - auto dimensions_list = get_dimensions_list(); - - for (auto d : dimensions_list) { - - float *xb = generate_desc_linear_increase(d, nb); - - for (auto eng : get_engines()) { - std::string index_filename = "dbs/add_and_search_2_neigh_10k" + - std::to_string(d) + "_" + - std::to_string(eng); - - VCL::DescriptorSet index(index_filename, unsigned(d), eng); - - index.add(xb, nb); - - std::vector distances; - std::vector desc_ids; - index.search(xb, 2, 4, desc_ids, distances); - - // Does not matter much, but good to test - // int exp[] = {0, 1, 2, 3, 1, 2, 0, 3}; - // int idx = 0; - // // std::cout << "DescriptorSet: " << std::endl; - // for (auto& desc : desc_ids) { - // // std::cout << desc << " "; - // EXPECT_EQ(desc, exp[idx++]); - // } - - // std::cout << "Distances: " << std::endl; - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; - for (int i = 0; i < 4; ++i) { - // std::cout << distances[i] << " "; - EXPECT_EQ(distances[i], results[i]); - } - - float results_2[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d) }; - - for (int i = 4; i < 8; ++i) { - // std::cout << distances[i] << " "; - EXPECT_EQ(distances[i], results_2[i-4]); - } - // std::cout << std::endl; - - index.store(); - } - - delete [] xb; - } + delete[] xb; + } } -TEST(Descriptors_Add, add_2_times) -{ - // int d = 100; - int nb = 10000; - - auto dimensions_list = get_dimensions_list(); +TEST(Descriptors_Add, add_2_times) { + // int d = 100; + int nb = 10000; - for (auto d : dimensions_list) { + auto dimensions_list = get_dimensions_list(); - float *xb = generate_desc_linear_increase(d, nb); + for (auto d : dimensions_list) { - for (auto eng : get_engines()) { + float *xb = generate_desc_linear_increase(d, nb); - // this eng is segfaulting, possible tdb bug - if (eng == VCL::TileDBSparse) - continue; + for (auto eng : get_engines()) { - std::string index_filename = "dbs/add_2_times_" + - std::to_string(d) + "_" + - std::to_string(eng); + // this eng is segfaulting, possible tdb bug + if (eng == VCL::TileDBSparse) + continue; - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + std::string index_filename = + "dbs/add_2_times_" + std::to_string(d) + "_" + std::to_string(eng); - index.add(xb, nb); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - generate_desc_linear_increase(d, nb, xb, .6); + index.add(xb, nb); - index.add(xb, nb); + generate_desc_linear_increase(d, nb, xb, .6); - generate_desc_linear_increase(d, 4, xb, 0); + index.add(xb, nb); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + generate_desc_linear_increase(d, 4, xb, 0); - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(.6, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(1.6, 2)*d) }; + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - for (int i = 0; i < 4; ++i) { - EXPECT_NEAR((distances[i]), (results[i]), .5f); - } - } + float results[] = {float(std::pow(0, 2) * d), float(std::pow(.6, 2) * d), + float(std::pow(1, 2) * d), + float(std::pow(1.6, 2) * d)}; - delete [] xb; + for (int i = 0; i < 4; ++i) { + EXPECT_NEAR((distances[i]), (results[i]), .5f); + } } -} - -TEST(Descriptors_Add, add_and_get_descriptors) -{ - int nb = 10000; - int recons_n = 10; + delete[] xb; + } +} - auto dimensions_list = get_dimensions_list(); +TEST(Descriptors_Add, add_and_get_descriptors) { + int nb = 10000; - for (auto d : dimensions_list) { + int recons_n = 10; - float *xb = generate_desc_linear_increase(d, nb); + auto dimensions_list = get_dimensions_list(); - std::vector recons_ids; - for (int i = 0; i < recons_n; ++i) { - recons_ids.push_back(i); - } + for (auto d : dimensions_list) { - for (auto eng : get_engines()) { + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/add_and_get_descriptors_10k" + - std::to_string(d) + "_" + - std::to_string(eng); + std::vector recons_ids; + for (int i = 0; i < recons_n; ++i) { + recons_ids.push_back(i); + } - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + for (auto eng : get_engines()) { + std::string index_filename = "dbs/add_and_get_descriptors_10k" + + std::to_string(d) + "_" + + std::to_string(eng); - index.add(xb, nb); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - float *recons = new float[d * recons_n]; - index.get_descriptors(recons_ids, recons); + index.add(xb, nb); - for (int i = 0; i < recons_n*d; ++i) { - EXPECT_NEAR(xb[i], recons[i], .01f); - } - // printf("%d\n", eng); + float *recons = new float[d * recons_n]; + index.get_descriptors(recons_ids, recons); - delete[] recons; + for (int i = 0; i < recons_n * d; ++i) { + EXPECT_NEAR(xb[i], recons[i], .01f); + } + // printf("%d\n", eng); - index.store(); - } + delete[] recons; - delete [] xb; + index.store(); } + + delete[] xb; + } } diff --git a/tests/unit_tests/DescriptorSetClassify_test.cc b/tests/unit_tests/DescriptorSetClassify_test.cc index 39528f26..d7c4e78c 100644 --- a/tests/unit_tests/DescriptorSetClassify_test.cc +++ b/tests/unit_tests/DescriptorSetClassify_test.cc @@ -29,448 +29,436 @@ * */ +#include #include #include -#include #include #include +#include "helpers.h" #include "vcl/VCL.h" #include "gtest/gtest.h" -#include "helpers.h" -TEST(Descriptors_Classify, classify_flatl2_4d) -{ - int d = 4; - int nb = 10000; +TEST(Descriptors_Classify, classify_flatl2_4d) { + int d = 4; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/classify_flatl2_4d.faiss"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); + std::string index_filename = "dbs/classify_flatl2_4d.faiss"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); + index.add(xb, nb, classes); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,4,16,36}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 4, 16, 36}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - std::vector ret_ids = index.classify(xb, 60); + std::vector ret_ids = index.classify(xb, 60); - exp = 0; - int i = 0; - for (auto& id : ret_ids) { - EXPECT_EQ(id, exp); - if (++i % offset == 0 ) - ++exp; - } + exp = 0; + int i = 0; + for (auto &id : ret_ids) { + EXPECT_EQ(id, exp); + if (++i % offset == 0) + ++exp; + } - index.store(); + index.store(); - delete [] xb; + delete[] xb; } -TEST(Descriptors_Classify, classify_10k) -{ - int nb = 10000; +TEST(Descriptors_Classify, classify_10k) { + int nb = 10000; - auto dimensions_list = get_dimensions_list(); + auto dimensions_list = get_dimensions_list(); - for (auto d : dimensions_list) { + for (auto d : dimensions_list) { float *xb = generate_desc_linear_increase(d, nb); for (auto eng : get_engines()) { - std::string index_filename = "dbs/classify_10k" + - std::to_string(d) + "_" + - std::to_string(eng); + std::string index_filename = + "dbs/classify_10k" + std::to_string(d) + "_" + std::to_string(eng); - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); + index.add(xb, nb, classes); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - std::vector ret_ids = index.classify(xb, 60); + std::vector ret_ids = index.classify(xb, 60); - exp = 0; - int i = 0; - for (auto& id : ret_ids) { - // printf("%ld - %ld \n", id, exp); - EXPECT_EQ(id, exp); - if (++i % offset == 0 ) - ++exp; - } + exp = 0; + int i = 0; + for (auto &id : ret_ids) { + // printf("%ld - %ld \n", id, exp); + EXPECT_EQ(id, exp); + if (++i % offset == 0) + ++exp; + } - index.store(); + index.store(); } - delete [] xb; - } + delete[] xb; + } } - // String labels tests -TEST(Descriptors_Classify, classify_ivfflatl2_4d_labels) -{ - int d = 4; - int nb = 10000; +TEST(Descriptors_Classify, classify_ivfflatl2_4d_labels) { + int d = 4; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - auto class_map = animals_map(); + auto class_map = animals_map(); - std::string index_filename = "dbs/classify_ivfflatl2_4d_labels.faiss"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissIVFFlat); + std::string index_filename = "dbs/classify_ivfflatl2_4d_labels.faiss"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissIVFFlat); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.set_labels_map(class_map); + index.set_labels_map(class_map); - index.add(xb, nb, classes); + index.add(xb, nb, classes); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,4,16,36}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 4, 16, 36}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); + std::vector ret_ids = index.classify(xb, 60); + std::vector ret = index.label_id_to_string(ret_ids); - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); - } + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - index.search(xb, 1, offset, desc_ids, distances); - ret = index.get_str_labels(desc_ids); + index.search(xb, 1, offset, desc_ids, distances); + ret = index.get_str_labels(desc_ids); - for (auto& label : ret){ - EXPECT_EQ(label, "parrot"); - } + for (auto &label : ret) { + EXPECT_EQ(label, "parrot"); + } - delete [] xb; + delete[] xb; } -TEST(Descriptors_Classify, classify_flinngIP_100d_labels) -{ - int d = 100; - int nb = 10000; - - float init=0.0; - int offset = 10; - float clusterhead_std=1.0; - float cluster_std=0.1; - - int n_clusters= floor((nb/offset)); - - float *xb = generate_desc_normal_cluster(d, nb, init, offset, clusterhead_std, cluster_std); - std::string index_filename = "dbs/classify_flinngIP_100d_labels"; - - VCL::DescriptorParams* param = new VCL::DescriptorParams(3, nb/10, 10, 12); - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, VCL::DistanceMetric::IP, param); - - /* - std::vector classes(nb); - - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < offset; j++){ - classes[i*offset + j] = i; - } - } - */ +TEST(Descriptors_Classify, classify_flinngIP_100d_labels) { + int d = 100; + int nb = 10000; - auto class_map = animals_map(); - std::vector classes = classes_increasing_offset(nb, offset); - index.set_labels_map(class_map); + float init = 0.0; + int offset = 10; + float clusterhead_std = 1.0; + float cluster_std = 0.1; + int n_clusters = floor((nb / offset)); + float *xb = generate_desc_normal_cluster(d, nb, init, offset, clusterhead_std, + cluster_std); + std::string index_filename = "dbs/classify_flinngIP_100d_labels"; - index.add_and_store(xb, nb,classes); - index.finalize_index(); + VCL::DescriptorParams *param = new VCL::DescriptorParams(3, nb / 10, 10, 12); + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::Flinng, + VCL::DistanceMetric::IP, param); - std::vector cluster_head(n_clusters * d); - std::vector descriptors(n_clusters*offset); + /* + std::vector classes(nb); - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < offset; j++){ - if((i*offset + j) % offset == 0) { - for (int z = 0; z < d; z++) - cluster_head[i * d + z] = xb[ d*(i*offset + j) + z]; - } - } - } + for (int i = 0; i < n_clusters ; i++) { + for (int j = 0; j < offset; j++){ + classes[i*offset + j] = i; + } + } + */ + + auto class_map = animals_map(); + std::vector classes = classes_increasing_offset(nb, offset); + index.set_labels_map(class_map); - index.search(cluster_head.data(), n_clusters, offset, descriptors); + index.add_and_store(xb, nb, classes); + index.finalize_index(); - int correct=0; - float recall=0.0; - for(int i = 0; i < n_clusters; ++i){ - for (int j = 0; j < offset; ++j) { - if((i* offset <= descriptors[i*offset+j]) && (descriptors[i*offset+j] < (i+1)*offset)) - correct++; + std::vector cluster_head(n_clusters * d); + std::vector descriptors(n_clusters * offset); + + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < offset; j++) { + if ((i * offset + j) % offset == 0) { + for (int z = 0; z < d; z++) + cluster_head[i * d + z] = xb[d * (i * offset + j) + z]; } } - recall=static_cast(correct) /(n_clusters*offset); - EXPECT_GE(recall, 0.7); - - - std::vector desc_ids; - index.search(xb, 1, offset, desc_ids); - - - correct=0; - recall=0.0; + } + + index.search(cluster_head.data(), n_clusters, offset, descriptors); + + int correct = 0; + float recall = 0.0; + for (int i = 0; i < n_clusters; ++i) { for (int j = 0; j < offset; ++j) { - if((0 <= desc_ids[j]) && (desc_ids[j] < offset)){ - correct++; - } - } - - recall=static_cast(correct) /offset; - EXPECT_GE(recall, 0.7); - - std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); - - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); + if ((i * offset <= descriptors[i * offset + j]) && + (descriptors[i * offset + j] < (i + 1) * offset)) + correct++; + } + } + recall = static_cast(correct) / (n_clusters * offset); + EXPECT_GE(recall, 0.7); + + std::vector desc_ids; + index.search(xb, 1, offset, desc_ids); + + correct = 0; + recall = 0.0; + for (int j = 0; j < offset; ++j) { + if ((0 <= desc_ids[j]) && (desc_ids[j] < offset)) { + correct++; } + } + recall = static_cast(correct) / offset; + EXPECT_GE(recall, 0.7); - index.search(xb, 1, offset, desc_ids); - ret = index.get_str_labels(desc_ids); + std::vector ret_ids = index.classify(xb, 60); + std::vector ret = index.label_id_to_string(ret_ids); - for (auto& label : ret){ - EXPECT_EQ(label, "parrot"); - } + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - delete [] xb; -} + index.search(xb, 1, offset, desc_ids); + ret = index.get_str_labels(desc_ids); + for (auto &label : ret) { + EXPECT_EQ(label, "parrot"); + } -TEST(Descriptors_Classify, classify_labels_10k) -{ - int nb = 10000; + delete[] xb; +} - auto dimensions_list = get_dimensions_list(); - auto class_map = animals_map(); +TEST(Descriptors_Classify, classify_labels_10k) { + int nb = 10000; - for (auto d : dimensions_list) { - float *xb = generate_desc_linear_increase(d, nb); + auto dimensions_list = get_dimensions_list(); + auto class_map = animals_map(); - for (auto eng : get_engines()) { - std::string index_filename = "dbs/classify_labels_10k_" + - std::to_string(d) + "_" + - std::to_string(eng); + for (auto d : dimensions_list) { + float *xb = generate_desc_linear_increase(d, nb); - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + for (auto eng : get_engines()) { + std::string index_filename = "dbs/classify_labels_10k_" + + std::to_string(d) + "_" + + std::to_string(eng); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - index.set_labels_map(class_map); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); + index.set_labels_map(class_map); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + index.add(xb, nb, classes); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); - } + std::vector ret_ids = index.classify(xb, 60); + std::vector ret = index.label_id_to_string(ret_ids); - index.search(xb, 1, offset, desc_ids, distances); - ret = index.get_str_labels(desc_ids); + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - for (auto& label : ret){ - EXPECT_EQ(label, "parrot"); - } + index.search(xb, 1, offset, desc_ids, distances); + ret = index.get_str_labels(desc_ids); - index.store(); - } + for (auto &label : ret) { + EXPECT_EQ(label, "parrot"); + } - delete [] xb; + index.store(); } + + delete[] xb; + } } -TEST(Descriptors_Classify, classify_flatl2_4d_str_label) -{ - int d = 4; - int nb = 10000; +TEST(Descriptors_Classify, classify_flatl2_4d_str_label) { + int d = 4; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/classify_flatl2_4d_str_label.faiss"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); + std::string index_filename = "dbs/classify_flatl2_4d_str_label.faiss"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - auto class_map = animals_map(); - index.set_labels_map(class_map); + auto class_map = animals_map(); + index.set_labels_map(class_map); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); + index.add(xb, nb, classes); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,4,16,36}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 4, 16, 36}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - std::vector ret_ids = index.classify(xb, 60); + std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); + std::vector ret = index.label_id_to_string(ret_ids); - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); - } + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - desc_ids.clear(); - distances.clear(); + desc_ids.clear(); + distances.clear(); - index.search(xb, 1, offset, desc_ids, distances); - ret = index.get_str_labels(desc_ids); + index.search(xb, 1, offset, desc_ids, distances); + ret = index.get_str_labels(desc_ids); - for (auto& label : ret) { - EXPECT_EQ(label, "parrot"); - } + for (auto &label : ret) { + EXPECT_EQ(label, "parrot"); + } - index.store(); + index.store(); - delete [] xb; + delete[] xb; } // TILEDBDense tests -TEST(Descriptors_Classify, classify_tdbdense_4d) -{ - int d = 4; - int nb = 10000; +TEST(Descriptors_Classify, classify_tdbdense_4d) { + int d = 4; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - auto class_map = animals_map(); + auto class_map = animals_map(); - std::string index_filename = "dbs/classify_tdbdense_4d"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBDense); + std::string index_filename = "dbs/classify_tdbdense_4d"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBDense); - index.set_labels_map(class_map); + index.set_labels_map(class_map); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); + index.add(xb, nb, classes); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,4,16,36}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 4, 16, 36}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - std::vector ret_ids = index.classify(xb, 60); + std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); + std::vector ret = index.label_id_to_string(ret_ids); - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); - } + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - desc_ids.clear(); - distances.clear(); + desc_ids.clear(); + distances.clear(); - index.search(xb, 1, offset, desc_ids, distances); - ret = index.get_str_labels(desc_ids); + index.search(xb, 1, offset, desc_ids, distances); + ret = index.get_str_labels(desc_ids); - for (auto& label : ret) { - // std::cout << label << std::endl; - EXPECT_EQ(label, "parrot"); - } + for (auto &label : ret) { + // std::cout << label << std::endl; + EXPECT_EQ(label, "parrot"); + } - index.store(); + index.store(); - delete [] xb; + delete[] xb; } diff --git a/tests/unit_tests/DescriptorSetReadFS_test.cc b/tests/unit_tests/DescriptorSetReadFS_test.cc index 2de01910..f0fe3561 100644 --- a/tests/unit_tests/DescriptorSetReadFS_test.cc +++ b/tests/unit_tests/DescriptorSetReadFS_test.cc @@ -29,101 +29,97 @@ * */ +#include +#include #include #include -#include #include #include -#include #include -#include "vcl/VCL.h" #include "helpers.h" +#include "vcl/VCL.h" #include "gtest/gtest.h" -TEST(Descriptors_ReadFS, read_and_search_10k) -{ - int nb = 10000; - auto dimensions_list = get_dimensions_list(); - - for (auto d : dimensions_list) { +TEST(Descriptors_ReadFS, read_and_search_10k) { + int nb = 10000; + auto dimensions_list = get_dimensions_list(); - float *xb = generate_desc_linear_increase(d, nb); + for (auto d : dimensions_list) { - for (auto eng : get_engines()) { + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/read_and_search_10k" + - std::to_string(d) + "_" + - std::to_string(eng); - { - VCL::DescriptorSet index(index_filename, unsigned(d), eng); - index.add(xb, nb); - index.store(); - } + for (auto eng : get_engines()) { - VCL::DescriptorSet index_fs(index_filename); + std::string index_filename = "dbs/read_and_search_10k" + + std::to_string(d) + "_" + + std::to_string(eng); + { + VCL::DescriptorSet index(index_filename, unsigned(d), eng); + index.add(xb, nb); + index.store(); + } - std::vector distances; - std::vector desc_ids; - index_fs.search(xb, 1, 4, desc_ids, distances); + VCL::DescriptorSet index_fs(index_filename); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + std::vector distances; + std::vector desc_ids; + index_fs.search(xb, 1, 4, desc_ids, distances); - float results[] = {float(std::pow(0, 2)*d), - float(std::pow(1, 2)*d), - float(std::pow(2, 2)*d), - float(std::pow(3, 2)*d) }; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - delete [] xb; + float results[] = {float(std::pow(0, 2) * d), float(std::pow(1, 2) * d), + float(std::pow(2, 2) * d), float(std::pow(3, 2) * d)}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } } -} -TEST(Descriptors_ReadFS, read_and_classify_10k) -{ - int nb = 10000; + delete[] xb; + } +} - auto dimensions_list = get_dimensions_list(); +TEST(Descriptors_ReadFS, read_and_classify_10k) { + int nb = 10000; - for (auto d : dimensions_list) { + auto dimensions_list = get_dimensions_list(); - float *xb = generate_desc_linear_increase(d, nb); + for (auto d : dimensions_list) { - for (auto eng : get_engines()) { - std::string index_filename = "dbs/read_and_classify_10k" + - std::to_string(d) + "_" + - std::to_string(eng); - int offset = 10; + float *xb = generate_desc_linear_increase(d, nb); - { - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + for (auto eng : get_engines()) { + std::string index_filename = "dbs/read_and_classify_10k" + + std::to_string(d) + "_" + + std::to_string(eng); + int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + { + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - index.add(xb, nb, classes); - index.store(); - } + std::vector classes = classes_increasing_offset(nb, offset); - VCL::DescriptorSet index_fs(index_filename); + index.add(xb, nb, classes); + index.store(); + } - std::vector ret_ids = index_fs.classify(xb, 60); + VCL::DescriptorSet index_fs(index_filename); - int exp = 0; - int i = 0; - for (auto& id : ret_ids) { - // printf("%ld - %ld \n", id, exp); - EXPECT_EQ(id, exp); - if (++i % offset == 0 ) - ++exp; - } - } + std::vector ret_ids = index_fs.classify(xb, 60); - delete [] xb; + int exp = 0; + int i = 0; + for (auto &id : ret_ids) { + // printf("%ld - %ld \n", id, exp); + EXPECT_EQ(id, exp); + if (++i % offset == 0) + ++exp; + } } + + delete[] xb; + } } diff --git a/tests/unit_tests/DescriptorSetStore_test.cc b/tests/unit_tests/DescriptorSetStore_test.cc index 80ad354d..c86490f3 100644 --- a/tests/unit_tests/DescriptorSetStore_test.cc +++ b/tests/unit_tests/DescriptorSetStore_test.cc @@ -29,118 +29,115 @@ * */ +#include +#include #include #include -#include #include #include -#include -#include "vcl/VCL.h" #include "helpers.h" +#include "vcl/VCL.h" #include "gtest/gtest.h" -TEST(Descriptors_Store, add_ivfflatl2_100d_2add_file) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); +TEST(Descriptors_Store, add_ivfflatl2_100d_2add_file) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/store_ivfflatl2_100d_2add.faiss"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissIVFFlat); + std::string index_filename = "dbs/store_ivfflatl2_100d_2add.faiss"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissIVFFlat); - index.add(xb, nb); - index.store(); + index.add(xb, nb); + index.store(); - generate_desc_linear_increase(d, nb, xb, .6); + generate_desc_linear_increase(d, nb, xb, .6); - VCL::DescriptorSet index_f(index_filename); - index_f.add(xb, nb); + VCL::DescriptorSet index_f(index_filename); + index_f.add(xb, nb); - generate_desc_linear_increase(d, 4, xb, 0); + generate_desc_linear_increase(d, 4, xb, 0); - std::vector distances; - std::vector desc_ids; - index_f.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index_f.search(xb, 1, 4, desc_ids, distances); - float results[] = {0,36,100,256}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(std::round(distances[i]), std::round(results[i])); - } + float results[] = {0, 36, 100, 256}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(std::round(distances[i]), std::round(results[i])); + } - index_f.store(); + index_f.store(); - delete [] xb; + delete[] xb; } -TEST(Descriptors_Store, add_tiledbdense_100d_file) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); +TEST(Descriptors_Store, add_tiledbdense_100d_file) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/store_tiledbdense_100d_tdb"; - VCL::DescriptorSet index_f(index_filename, unsigned(d), VCL::TileDBDense); + std::string index_filename = "dbs/store_tiledbdense_100d_tdb"; + VCL::DescriptorSet index_f(index_filename, unsigned(d), VCL::TileDBDense); - index_f.add(xb, nb); - index_f.store(); + index_f.add(xb, nb); + index_f.store(); - VCL::DescriptorSet index(index_filename); + VCL::DescriptorSet index(index_filename); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,100,400,900}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 100, 400, 900}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - index.store(); + index.store(); - delete [] xb; + delete[] xb; } -TEST(Descriptors_Store, add_tiledbdense_100d_2add_file) -{ - int d = 100; - int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); +TEST(Descriptors_Store, add_tiledbdense_100d_2add_file) { + int d = 100; + int nb = 10000; + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/store_tiledbdense_100d_2add"; - VCL::DescriptorSet index_f(index_filename, unsigned(d), VCL::TileDBDense); + std::string index_filename = "dbs/store_tiledbdense_100d_2add"; + VCL::DescriptorSet index_f(index_filename, unsigned(d), VCL::TileDBDense); - index_f.add(xb, nb); + index_f.add(xb, nb); - generate_desc_linear_increase(d, nb, xb, .6); + generate_desc_linear_increase(d, nb, xb, .6); - index_f.add(xb, nb); - index_f.store(); + index_f.add(xb, nb); + index_f.store(); - generate_desc_linear_increase(d, 4, xb, 0); + generate_desc_linear_increase(d, 4, xb, 0); - VCL::DescriptorSet index(index_filename); + VCL::DescriptorSet index(index_filename); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - float results[] = {0,36,100,256}; - // This is: - // (0) ^2 * 100 = 0 - // (0.6)^2 * 100 = 36 - // (1 )^2 * 100 = 100 - // (1.6)^2 * 100 = 256 + float results[] = {0, 36, 100, 256}; + // This is: + // (0) ^2 * 100 = 0 + // (0.6)^2 * 100 = 36 + // (1 )^2 * 100 = 100 + // (1.6)^2 * 100 = 256 - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(std::round(distances[i]), std::round(results[i])); - } + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(std::round(distances[i]), std::round(results[i])); + } - index.store(); - delete [] xb; + index.store(); + delete[] xb; } diff --git a/tests/unit_tests/DescriptorSetTrain_test.cc b/tests/unit_tests/DescriptorSetTrain_test.cc index 559c8469..6776ff58 100644 --- a/tests/unit_tests/DescriptorSetTrain_test.cc +++ b/tests/unit_tests/DescriptorSetTrain_test.cc @@ -29,356 +29,347 @@ * */ +#include #include #include -#include #include #include +#include "helpers.h" #include "vcl/VCL.h" #include "gtest/gtest.h" -#include "helpers.h" -TEST(Descriptors_Train, train_flatl2_4d) -{ - int d = 4; - int nb = 10000; +TEST(Descriptors_Train, train_flatl2_4d) { + int d = 4; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/train_flatl2_4d.faiss"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); + std::string index_filename = "dbs/train_flatl2_4d.faiss"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); + index.add(xb, nb, classes); - index.train(); + index.train(); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,4,16,36}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 4, 16, 36}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - std::vector ret_ids = index.classify(xb, 60); + std::vector ret_ids = index.classify(xb, 60); - exp = 0; - int i = 0; - for (auto& id : ret_ids) { - EXPECT_EQ(id, exp); - if (++i % offset == 0 ) - ++exp; - } + exp = 0; + int i = 0; + for (auto &id : ret_ids) { + EXPECT_EQ(id, exp); + if (++i % offset == 0) + ++exp; + } - index.store(); + index.store(); - delete [] xb; + delete[] xb; } -TEST(Descriptors_Train, train_10k) -{ - int nb = 10000; +TEST(Descriptors_Train, train_10k) { + int nb = 10000; - auto dimensions_list = get_dimensions_list(); + auto dimensions_list = get_dimensions_list(); - for (auto d : dimensions_list) { + for (auto d : dimensions_list) { float *xb = generate_desc_linear_increase(d, nb); for (auto eng : get_engines()) { - std::string index_filename = "dbs/train_10k" + - std::to_string(d) + "_" + - std::to_string(eng); + std::string index_filename = + "dbs/train_10k" + std::to_string(d) + "_" + std::to_string(eng); - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); + index.add(xb, nb, classes); - index.train(); + index.train(); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - std::vector ret_ids = index.classify(xb, 60); + std::vector ret_ids = index.classify(xb, 60); - exp = 0; - int i = 0; - for (auto& id : ret_ids) { - // printf("%ld - %ld \n", id, exp); - EXPECT_EQ(id, exp); - if (++i % offset == 0 ) - ++exp; - } + exp = 0; + int i = 0; + for (auto &id : ret_ids) { + // printf("%ld - %ld \n", id, exp); + EXPECT_EQ(id, exp); + if (++i % offset == 0) + ++exp; + } - index.store(); + index.store(); } - delete [] xb; - } + delete[] xb; + } } - // String labels tests -TEST(Descriptors_Train, train_ivfflatl2_4d_labels) -{ - int d = 4; - int nb = 10000; +TEST(Descriptors_Train, train_ivfflatl2_4d_labels) { + int d = 4; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - auto class_map = animals_map(); + auto class_map = animals_map(); - std::string index_filename = "dbs/train_ivfflatl2_4d_labels.faiss"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissIVFFlat); + std::string index_filename = "dbs/train_ivfflatl2_4d_labels.faiss"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissIVFFlat); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.set_labels_map(class_map); + index.set_labels_map(class_map); - index.add(xb, nb, classes); + index.add(xb, nb, classes); - index.train(); + index.train(); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,4,16,36}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 4, 16, 36}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); + std::vector ret_ids = index.classify(xb, 60); + std::vector ret = index.label_id_to_string(ret_ids); - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); - } + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - index.search(xb, 1, offset, desc_ids, distances); - ret = index.get_str_labels(desc_ids); + index.search(xb, 1, offset, desc_ids, distances); + ret = index.get_str_labels(desc_ids); - for (auto& label : ret){ - EXPECT_EQ(label, "parrot"); - } + for (auto &label : ret) { + EXPECT_EQ(label, "parrot"); + } - delete [] xb; + delete[] xb; } -TEST(Descriptors_Train, train_labels_10k) -{ - int nb = 10000; - - auto dimensions_list = get_dimensions_list(); - auto class_map = animals_map(); +TEST(Descriptors_Train, train_labels_10k) { + int nb = 10000; - for (auto d : dimensions_list) { - float *xb = generate_desc_linear_increase(d, nb); + auto dimensions_list = get_dimensions_list(); + auto class_map = animals_map(); - for (auto eng : get_engines()) { - std::string index_filename = "dbs/train_labels_10k_" + - std::to_string(d) + "_" + - std::to_string(eng); + for (auto d : dimensions_list) { + float *xb = generate_desc_linear_increase(d, nb); - VCL::DescriptorSet index(index_filename, unsigned(d), eng); + for (auto eng : get_engines()) { + std::string index_filename = "dbs/train_labels_10k_" + std::to_string(d) + + "_" + std::to_string(eng); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + VCL::DescriptorSet index(index_filename, unsigned(d), eng); - index.set_labels_map(class_map); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); + index.set_labels_map(class_map); - index.train(); + index.add(xb, nb, classes); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + index.train(); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); - } + std::vector ret_ids = index.classify(xb, 60); + std::vector ret = index.label_id_to_string(ret_ids); - index.search(xb, 1, offset, desc_ids, distances); - ret = index.get_str_labels(desc_ids); + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - for (auto& label : ret){ - EXPECT_EQ(label, "parrot"); - } + index.search(xb, 1, offset, desc_ids, distances); + ret = index.get_str_labels(desc_ids); - index.store(); - } + for (auto &label : ret) { + EXPECT_EQ(label, "parrot"); + } - delete [] xb; + index.store(); } + + delete[] xb; + } } -TEST(Descriptors_Train, train_flatl2_4d_str_label) -{ - int d = 4; - int nb = 10000; +TEST(Descriptors_Train, train_flatl2_4d_str_label) { + int d = 4; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - std::string index_filename = "dbs/train_flatl2_4d_str_label.faiss"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); + std::string index_filename = "dbs/train_flatl2_4d_str_label.faiss"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::FaissFlat); - auto class_map = animals_map(); - index.set_labels_map(class_map); + auto class_map = animals_map(); + index.set_labels_map(class_map); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); - index.train(); + index.add(xb, nb, classes); + index.train(); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,4,16,36}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 4, 16, 36}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - std::vector ret_ids = index.classify(xb, 60); + std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); + std::vector ret = index.label_id_to_string(ret_ids); - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); - } + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - desc_ids.clear(); - distances.clear(); + desc_ids.clear(); + distances.clear(); - index.search(xb, 1, offset, desc_ids, distances); - ret = index.get_str_labels(desc_ids); + index.search(xb, 1, offset, desc_ids, distances); + ret = index.get_str_labels(desc_ids); - for (auto& label : ret) { - EXPECT_EQ(label, "parrot"); - } + for (auto &label : ret) { + EXPECT_EQ(label, "parrot"); + } - index.store(); + index.store(); - delete [] xb; + delete[] xb; } // TILEDBDense tests -TEST(Descriptors_Train, train_tdbdense_4d) -{ - int d = 4; - int nb = 10000; +TEST(Descriptors_Train, train_tdbdense_4d) { + int d = 4; + int nb = 10000; - float *xb = generate_desc_linear_increase(d, nb); + float *xb = generate_desc_linear_increase(d, nb); - auto class_map = animals_map(); + auto class_map = animals_map(); - std::string index_filename = "dbs/train_tdbdense_4d"; - VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBDense); + std::string index_filename = "dbs/train_tdbdense_4d"; + VCL::DescriptorSet index(index_filename, unsigned(d), VCL::TileDBDense); - index.set_labels_map(class_map); + index.set_labels_map(class_map); - int offset = 10; - std::vector classes = classes_increasing_offset(nb, offset); + int offset = 10; + std::vector classes = classes_increasing_offset(nb, offset); - index.add(xb, nb, classes); - index.train(); + index.add(xb, nb, classes); + index.train(); - std::vector distances; - std::vector desc_ids; - index.search(xb, 1, 4, desc_ids, distances); + std::vector distances; + std::vector desc_ids; + index.search(xb, 1, 4, desc_ids, distances); - int exp = 0; - for (auto& desc : desc_ids) { - EXPECT_EQ(desc, exp++); - } + int exp = 0; + for (auto &desc : desc_ids) { + EXPECT_EQ(desc, exp++); + } - int results[] = {0,4,16,36}; - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(distances[i], results[i]); - } + int results[] = {0, 4, 16, 36}; + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(distances[i], results[i]); + } - std::vector ret_ids = index.classify(xb, 60); + std::vector ret_ids = index.classify(xb, 60); - std::vector ret = index.label_id_to_string(ret_ids); + std::vector ret = index.label_id_to_string(ret_ids); - for (int i = 0; i < offset; ++i) { - EXPECT_EQ(ret[i], "parrot"); - EXPECT_EQ(ret[i+offset], "dog"); - EXPECT_EQ(ret[i+2*offset], "cat"); - EXPECT_EQ(ret[i+3*offset], "messi"); - EXPECT_EQ(ret[i+4*offset], "bird"); - EXPECT_EQ(ret[i+5*offset], "condor"); - } + for (int i = 0; i < offset; ++i) { + EXPECT_EQ(ret[i], "parrot"); + EXPECT_EQ(ret[i + offset], "dog"); + EXPECT_EQ(ret[i + 2 * offset], "cat"); + EXPECT_EQ(ret[i + 3 * offset], "messi"); + EXPECT_EQ(ret[i + 4 * offset], "bird"); + EXPECT_EQ(ret[i + 5 * offset], "condor"); + } - desc_ids.clear(); - distances.clear(); + desc_ids.clear(); + distances.clear(); - index.search(xb, 1, offset, desc_ids, distances); - ret = index.get_str_labels(desc_ids); + index.search(xb, 1, offset, desc_ids, distances); + ret = index.get_str_labels(desc_ids); - for (auto& label : ret) { - // std::cout << label << std::endl; - EXPECT_EQ(label, "parrot"); - } + for (auto &label : ret) { + // std::cout << label << std::endl; + EXPECT_EQ(label, "parrot"); + } - index.store(); + index.store(); - delete [] xb; + delete[] xb; } diff --git a/tests/unit_tests/Image_test.cc b/tests/unit_tests/Image_test.cc index c48be40e..779c5fba 100644 --- a/tests/unit_tests/Image_test.cc +++ b/tests/unit_tests/Image_test.cc @@ -27,6 +27,8 @@ * */ +#include "ImageLoop.h" +#include "stats/SystemStats.h" #include "vcl/Image.h" #include "gtest/gtest.h" @@ -35,611 +37,568 @@ #include #include -#include #include #include +#include #include #include class ImageTest : public ::testing::Test { - protected: - virtual void SetUp() { - img_ = "test_images/large1.jpg"; - tdb_img_ = "tdb/test_image.tdb"; - cv_img_ = cv::imread(img_, -1); - - size_ = cv_img_.rows * cv_img_.cols * cv_img_.channels(); - rect_ = VCL::Rectangle(100, 100, 100, 100); - bad_rect_ = VCL::Rectangle(1000, 1000, 10000, 10000); - dimension_ = 256; +protected: + virtual void SetUp() { + img_ = "test_images/large1.jpg"; + tdb_img_ = "tdb/test_image.tdb"; + cv_img_ = cv::imread(img_, -1); + + size_ = cv_img_.rows * cv_img_.cols * cv_img_.channels(); + rect_ = VCL::Rectangle(100, 100, 100, 100); + bad_rect_ = VCL::Rectangle(1000, 1000, 10000, 10000); + dimension_ = 256; + } + + void compare_mat_buffer(cv::Mat &img, unsigned char *buffer) { + int index = 0; + + int rows = img.rows; + int columns = img.cols; + int channels = img.channels(); + if (channels > 3) { + throw VCLException(OpenFailed, "Greater than 3 channels in image"); } - void compare_mat_buffer(cv::Mat &img, unsigned char* buffer) - { - int index = 0; - - int rows = img.rows; - int columns = img.cols; - int channels = img.channels(); - if(channels > 3) - { - throw VCLException(OpenFailed, "Greater than 3 channels in image"); - } - - - if ( img.isContinuous() ) { - columns *= rows; - rows = 1; - } - - for ( int i = 0; i < rows; ++i ) { - for ( int j = 0; j < columns; ++j ) { - if (channels == 1) { - unsigned char pixel = img.at(i, j); - ASSERT_EQ(pixel, buffer[index]); - } - else { - cv::Vec3b colors = img.at(i, j); - for ( int x = 0; x < channels; ++x ) { - ASSERT_EQ(colors.val[x], buffer[index + x]); - } - } - index += channels; - } - } + if (img.isContinuous()) { + columns *= rows; + rows = 1; } - void compare_mat_mat(cv::Mat &cv_img, cv::Mat &img) - { - int rows = img.rows; - int columns = img.cols; - int channels = img.channels(); - if(channels > 3) - { - throw VCLException(OpenFailed, "Greater than 3 channels in image"); + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (channels == 1) { + unsigned char pixel = img.at(i, j); + ASSERT_EQ(pixel, buffer[index]); + } else { + cv::Vec3b colors = img.at(i, j); + for (int x = 0; x < channels; ++x) { + ASSERT_EQ(colors.val[x], buffer[index + x]); + } } + index += channels; + } + } + } + + void compare_mat_mat(cv::Mat &cv_img, cv::Mat &img) { + int rows = img.rows; + int columns = img.cols; + int channels = img.channels(); + if (channels > 3) { + throw VCLException(OpenFailed, "Greater than 3 channels in image"); + } + if (img.isContinuous()) { + columns *= rows; + rows = 1; + } - if ( img.isContinuous() ) { - columns *= rows; - rows = 1; - } - - for ( int i = 0; i < rows; ++i ) { - for ( int j = 0; j < columns; ++j ) { - if (channels == 1) { - unsigned char pixel = img.at(i, j); - unsigned char test_pixel = cv_img.at(i, j); - ASSERT_EQ(pixel, test_pixel); - } - else { - cv::Vec3b colors = img.at(i, j); - cv::Vec3b test_colors = cv_img.at(i, j); - for ( int x = 0; x < channels; ++x ) { - ASSERT_EQ(colors.val[x], test_colors.val[x]); - } - } - } + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (channels == 1) { + unsigned char pixel = img.at(i, j); + unsigned char test_pixel = cv_img.at(i, j); + ASSERT_EQ(pixel, test_pixel); + } else { + cv::Vec3b colors = img.at(i, j); + cv::Vec3b test_colors = cv_img.at(i, j); + for (int x = 0; x < channels; ++x) { + ASSERT_EQ(colors.val[x], test_colors.val[x]); + } } + } } + } - VCL::Rectangle rect_; - VCL::Rectangle bad_rect_; - std::string img_; - std::string tdb_img_; + VCL::Rectangle rect_; + VCL::Rectangle bad_rect_; + std::string img_; + std::string tdb_img_; - cv::Mat cv_img_; + cv::Mat cv_img_; - int dimension_; - int size_; + int dimension_; + int size_; }; namespace VCL { - class ImageTest : public Image{ +class ImageTest : public Image { - public: - ImageTest() : Image() {} - ImageTest(std::string a) : Image(a) {} - ImageTest(cv::Mat& a) : Image(a) {} +public: + ImageTest() : Image() {} + ImageTest(std::string a) : Image(a) {} + ImageTest(cv::Mat &a) : Image(a) {} - using Image::perform_operations; - using Image::set_data_from_raw; - using Image::set_data_from_encoded; - using Image::set_format; - using Image::read; - }; + using Image::perform_operations; + using Image::read; + using Image::set_data_from_encoded; + using Image::set_data_from_raw; + using Image::set_format; }; +}; // namespace VCL -TEST_F(ImageTest, DefaultConstructor) -{ - VCL::ImageTest img_data; +TEST_F(ImageTest, DefaultConstructor) { + VCL::ImageTest img_data; - cv::Size dims = img_data.get_dimensions(); + cv::Size dims = img_data.get_dimensions(); - EXPECT_EQ(0, dims.height); - EXPECT_EQ(0, dims.width); + EXPECT_EQ(0, dims.height); + EXPECT_EQ(0, dims.width); } -// When setting from a filename, we set the type, number of channels, path, and format of the image, -// We also add a read operation to the list of operations -TEST_F(ImageTest, StringConstructor) -{ - VCL::Image img(img_); +// When setting from a filename, we set the type, number of channels, path, and +// format of the image, We also add a read operation to the list of operations +TEST_F(ImageTest, StringConstructor) { + VCL::Image img(img_); - EXPECT_EQ(VCL::Image::Format::JPG, img.get_image_format()); - EXPECT_EQ(img_, img.get_image_id()); + EXPECT_EQ(VCL::Image::Format::JPG, img.get_image_format()); + EXPECT_EQ(img_, img.get_image_id()); } -TEST_F(ImageTest, StringConstructorIMG) -{ - VCL::Image img_data(img_); +TEST_F(ImageTest, StringConstructorIMG) { + VCL::Image img_data(img_); - cv::Size dims = img_data.get_dimensions(); - EXPECT_EQ(cv_img_.rows, dims.height); - EXPECT_EQ(cv_img_.cols, dims.width); + cv::Size dims = img_data.get_dimensions(); + EXPECT_EQ(cv_img_.rows, dims.height); + EXPECT_EQ(cv_img_.cols, dims.width); - EXPECT_EQ(img_data.get_image_format(), VCL::Image::Format::JPG); + EXPECT_EQ(img_data.get_image_format(), VCL::Image::Format::JPG); } -TEST_F(ImageTest, StringConstructorTDB) -{ - VCL::Image img_data(tdb_img_); +TEST_F(ImageTest, StringConstructorTDB) { + VCL::Image img_data(tdb_img_); - cv::Size dims = img_data.get_dimensions(); + cv::Size dims = img_data.get_dimensions(); - EXPECT_EQ(cv_img_.rows, dims.height); - EXPECT_EQ(cv_img_.cols, dims.width); + EXPECT_EQ(cv_img_.rows, dims.height); + EXPECT_EQ(cv_img_.cols, dims.width); - EXPECT_EQ(img_data.get_image_format(), VCL::Image::Format::TDB); + EXPECT_EQ(img_data.get_image_format(), VCL::Image::Format::TDB); } -// When setting from a cv::mat, we set the type of the image and copy the image data -// We should know the height, width, number of channels, type, and have a non-empty Mat -TEST_F(ImageTest, MatConstructor) -{ - VCL::Image img(cv_img_); +// When setting from a cv::mat, we set the type of the image and copy the image +// data We should know the height, width, number of channels, type, and have a +// non-empty Mat +TEST_F(ImageTest, MatConstructor) { + VCL::Image img(cv_img_); - ASSERT_FALSE( img.get_cvmat().empty() ); - EXPECT_EQ(cv_img_.type(), img.get_image_type()); + ASSERT_FALSE(img.get_cvmat().empty()); + EXPECT_EQ(cv_img_.type(), img.get_image_type()); - cv::Size dims = img.get_dimensions(); + cv::Size dims = img.get_dimensions(); - EXPECT_EQ(cv_img_.rows, dims.height); - EXPECT_EQ(cv_img_.cols, dims.width); + EXPECT_EQ(cv_img_.rows, dims.height); + EXPECT_EQ(cv_img_.cols, dims.width); - cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img = img.get_cvmat(); - compare_mat_mat(cv_img, cv_img_); + compare_mat_mat(cv_img, cv_img_); } -TEST_F(ImageTest, EncodedBufferConstructor) -{ - std::fstream jpgimage("test_images/large1.jpg"); +TEST_F(ImageTest, EncodedBufferConstructor) { + std::fstream jpgimage("test_images/large1.jpg"); - jpgimage.seekg(0, jpgimage.end); - int length = jpgimage.tellg(); - jpgimage.seekg(0, jpgimage.beg); + jpgimage.seekg(0, jpgimage.end); + int length = jpgimage.tellg(); + jpgimage.seekg(0, jpgimage.beg); - char* buffer = new char[length]; - jpgimage.read(buffer, length); - jpgimage.close(); + char *buffer = new char[length]; + jpgimage.read(buffer, length); + jpgimage.close(); - int size = cv_img_.rows * cv_img_.cols * cv_img_.channels(); + int size = cv_img_.rows * cv_img_.cols * cv_img_.channels(); - VCL::Image img(buffer, size); + VCL::Image img(buffer, size); - ASSERT_FALSE(img.get_cvmat().empty()); - cv::Mat raw = img.get_cvmat(); + ASSERT_FALSE(img.get_cvmat().empty()); + cv::Mat raw = img.get_cvmat(); - compare_mat_mat(cv_img_, raw); + compare_mat_mat(cv_img_, raw); } -TEST_F(ImageTest, BufferConstructor) -{ - unsigned char* buffer = cv_img_.data; +TEST_F(ImageTest, BufferConstructor) { + unsigned char *buffer = cv_img_.data; - int size = cv_img_.rows * cv_img_.cols * cv_img_.channels(); + int size = cv_img_.rows * cv_img_.cols * cv_img_.channels(); - VCL::Image img_data(buffer, cv::Size(cv_img_.cols, cv_img_.rows), cv_img_.type()); + VCL::Image img_data(buffer, cv::Size(cv_img_.cols, cv_img_.rows), + cv_img_.type()); - cv::Size dims = img_data.get_dimensions(); + cv::Size dims = img_data.get_dimensions(); - EXPECT_EQ(cv_img_.rows, dims.height); - EXPECT_EQ(cv_img_.cols, dims.width); - EXPECT_EQ(cv_img_.type(), img_data.get_image_type()); + EXPECT_EQ(cv_img_.rows, dims.height); + EXPECT_EQ(cv_img_.cols, dims.width); + EXPECT_EQ(cv_img_.type(), img_data.get_image_type()); - unsigned char* buf = new unsigned char[size]; + unsigned char *buf = new unsigned char[size]; - img_data.get_raw_data(buf, size); + img_data.get_raw_data(buf, size); - compare_mat_buffer(cv_img_, buf); + compare_mat_buffer(cv_img_, buf); } -TEST_F(ImageTest, RawBufferConstructor) -{ - void* buffer = cv_img_.data; +TEST_F(ImageTest, RawBufferConstructor) { + void *buffer = cv_img_.data; - VCL::Image img(buffer, cv::Size(cv_img_.cols, cv_img_.rows), cv_img_.type()); + VCL::Image img(buffer, cv::Size(cv_img_.cols, cv_img_.rows), cv_img_.type()); - cv::Mat raw = img.get_cvmat(); + cv::Mat raw = img.get_cvmat(); - compare_mat_mat(cv_img_, raw); + compare_mat_mat(cv_img_, raw); } -TEST_F(ImageTest, CopyConstructor) -{ - VCL::Image img(cv_img_); +TEST_F(ImageTest, CopyConstructor) { + VCL::Image img(cv_img_); - EXPECT_EQ(cv_img_.type(), img.get_image_type()); + EXPECT_EQ(cv_img_.type(), img.get_image_type()); - VCL::Image test_img(img); + VCL::Image test_img(img); - EXPECT_EQ(cv_img_.type(), test_img.get_image_type()); + EXPECT_EQ(cv_img_.type(), test_img.get_image_type()); - cv::Mat test_cv = test_img.get_cvmat(); - ASSERT_FALSE( test_cv.empty() ); + cv::Mat test_cv = test_img.get_cvmat(); + ASSERT_FALSE(test_cv.empty()); - compare_mat_mat(test_cv, cv_img_); + compare_mat_mat(test_cv, cv_img_); } -TEST_F(ImageTest, CopyConstructorMat) -{ - VCL::Image img_data(cv_img_); +TEST_F(ImageTest, CopyConstructorMat) { + VCL::Image img_data(cv_img_); - VCL::Image img_copy(img_data); + VCL::Image img_copy(img_data); - cv::Mat cv_img = img_data.get_cvmat(); - cv::Mat cv_copy = img_copy.get_cvmat(); + cv::Mat cv_img = img_data.get_cvmat(); + cv::Mat cv_copy = img_copy.get_cvmat(); - compare_mat_mat(cv_img, cv_copy); + compare_mat_mat(cv_img, cv_copy); } -TEST_F(ImageTest, CopyConstructorTDB) -{ - VCL::Image img_data(tdb_img_); +TEST_F(ImageTest, CopyConstructorTDB) { + VCL::Image img_data(tdb_img_); - VCL::Image img_copy(img_data); + VCL::Image img_copy(img_data); - cv::Mat cv_img = img_data.get_cvmat(); - cv::Mat cv_copy = img_copy.get_cvmat(); + cv::Mat cv_img = img_data.get_cvmat(); + cv::Mat cv_copy = img_copy.get_cvmat(); - compare_mat_mat(cv_img, cv_copy); + compare_mat_mat(cv_img, cv_copy); } -TEST_F(ImageTest, CopyConstructorComplex) -{ - VCL::Image img(cv_img_); +TEST_F(ImageTest, CopyConstructorComplex) { + VCL::Image img(cv_img_); - EXPECT_EQ(cv_img_.type(), img.get_image_type()); + EXPECT_EQ(cv_img_.type(), img.get_image_type()); - img.crop(rect_); + img.crop(rect_); - VCL::Image test_img(img); + VCL::Image test_img(img); - EXPECT_EQ(cv_img_.type(), test_img.get_image_type()); - cv::Mat test_cv = test_img.get_cvmat(); + EXPECT_EQ(cv_img_.type(), test_img.get_image_type()); + cv::Mat test_cv = test_img.get_cvmat(); - cv::Mat cropped_cv(cv_img_, rect_); - compare_mat_mat(test_cv, cropped_cv); + cv::Mat cropped_cv(cv_img_, rect_); + compare_mat_mat(test_cv, cropped_cv); - cv::Size dims = test_img.get_dimensions(); - EXPECT_EQ(rect_.height, dims.height); + cv::Size dims = test_img.get_dimensions(); + EXPECT_EQ(rect_.height, dims.height); } -TEST_F(ImageTest, OperatorEqualsMat) -{ - VCL::ImageTest img_data(cv_img_); +TEST_F(ImageTest, OperatorEqualsMat) { + VCL::ImageTest img_data(cv_img_); - VCL::ImageTest img_copy; + VCL::ImageTest img_copy; - img_copy = img_data; + img_copy = img_data; - cv::Mat cv_img = img_data.get_cvmat(); - cv::Mat cv_copy = img_copy.get_cvmat(); + cv::Mat cv_img = img_data.get_cvmat(); + cv::Mat cv_copy = img_copy.get_cvmat(); - compare_mat_mat(cv_img, cv_copy); + compare_mat_mat(cv_img, cv_copy); } -TEST_F(ImageTest, OperatorEqualsTDB) -{ - VCL::ImageTest img_data(tdb_img_); +TEST_F(ImageTest, OperatorEqualsTDB) { + VCL::ImageTest img_data(tdb_img_); - VCL::ImageTest img_copy; + VCL::ImageTest img_copy; - img_copy = img_data; + img_copy = img_data; - cv::Mat cv_img = img_data.get_cvmat(); - cv::Mat cv_copy = img_copy.get_cvmat(); + cv::Mat cv_img = img_data.get_cvmat(); + cv::Mat cv_copy = img_copy.get_cvmat(); - compare_mat_mat(cv_img, cv_copy); + compare_mat_mat(cv_img, cv_copy); } -TEST_F(ImageTest, GetMatFromMat) -{ - VCL::Image img(cv_img_); +TEST_F(ImageTest, GetMatFromMat) { + VCL::Image img(cv_img_); - cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img = img.get_cvmat(); - EXPECT_FALSE(cv_img.empty()); + EXPECT_FALSE(cv_img.empty()); - compare_mat_mat(cv_img, cv_img_); + compare_mat_mat(cv_img, cv_img_); } -TEST_F(ImageTest, GetMatFromPNG) -{ - VCL::Image img(img_); +TEST_F(ImageTest, GetMatFromPNG) { + VCL::Image img(img_); - cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img = img.get_cvmat(); - EXPECT_FALSE(cv_img.empty()); + EXPECT_FALSE(cv_img.empty()); - compare_mat_mat(cv_img, cv_img_); + compare_mat_mat(cv_img, cv_img_); } -TEST_F(ImageTest, GetMatFromTDB) -{ - VCL::Image img(tdb_img_); +TEST_F(ImageTest, GetMatFromTDB) { + VCL::Image img(tdb_img_); - EXPECT_EQ(tdb_img_, img.get_image_id()); - EXPECT_EQ(VCL::Image::Format::TDB, img.get_image_format()); + EXPECT_EQ(tdb_img_, img.get_image_id()); + EXPECT_EQ(VCL::Image::Format::TDB, img.get_image_format()); - cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img = img.get_cvmat(); - EXPECT_FALSE(cv_img.empty()); + EXPECT_FALSE(cv_img.empty()); - compare_mat_mat(cv_img, cv_img_); + compare_mat_mat(cv_img, cv_img_); } -TEST_F(ImageTest, GetBufferFromMat) -{ - VCL::Image img(cv_img_); +TEST_F(ImageTest, GetBufferFromMat) { + VCL::Image img(cv_img_); - unsigned char* buffer = new unsigned char[img.get_raw_data_size()]; + unsigned char *buffer = new unsigned char[img.get_raw_data_size()]; - img.get_raw_data(buffer, img.get_raw_data_size()); + img.get_raw_data(buffer, img.get_raw_data_size()); - EXPECT_TRUE(buffer != NULL); - compare_mat_buffer(cv_img_, buffer); + EXPECT_TRUE(buffer != NULL); + compare_mat_buffer(cv_img_, buffer); - delete [] buffer; + delete[] buffer; } -TEST_F(ImageTest, GetBufferFromPNG) -{ - VCL::Image img(img_); +TEST_F(ImageTest, GetBufferFromPNG) { + VCL::Image img(img_); - unsigned char* buffer = new unsigned char[img.get_raw_data_size()]; + unsigned char *buffer = new unsigned char[img.get_raw_data_size()]; - img.get_raw_data(buffer, img.get_raw_data_size()); + img.get_raw_data(buffer, img.get_raw_data_size()); - EXPECT_TRUE(buffer != NULL); - compare_mat_buffer(cv_img_, buffer); + EXPECT_TRUE(buffer != NULL); + compare_mat_buffer(cv_img_, buffer); - delete [] buffer; + delete[] buffer; } -TEST_F(ImageTest, GetBufferFromTDB) -{ - VCL::Image img(tdb_img_); +TEST_F(ImageTest, GetBufferFromTDB) { + VCL::Image img(tdb_img_); - int size = img.get_raw_data_size(); - unsigned char* buffer = new unsigned char[size]; + int size = img.get_raw_data_size(); + unsigned char *buffer = new unsigned char[size]; - img.get_raw_data(buffer, size); + img.get_raw_data(buffer, size); - EXPECT_TRUE(buffer != NULL); - compare_mat_buffer(cv_img_, (unsigned char*)buffer); + EXPECT_TRUE(buffer != NULL); + compare_mat_buffer(cv_img_, (unsigned char *)buffer); - delete [] buffer; + delete[] buffer; } -TEST_F(ImageTest, GetArea) -{ - VCL::Image img_data(tdb_img_); +TEST_F(ImageTest, GetArea) { + VCL::Image img_data(tdb_img_); - VCL::Image new_data = img_data.get_area(rect_); + VCL::Image new_data = img_data.get_area(rect_); - cv::Size dims = new_data.get_dimensions(); + cv::Size dims = new_data.get_dimensions(); - EXPECT_EQ(rect_.height, dims.height); - EXPECT_EQ(rect_.width, dims.width); + EXPECT_EQ(rect_.height, dims.height); + EXPECT_EQ(rect_.width, dims.width); } -TEST_F(ImageTest, GetBuffer) -{ - VCL::Image img_data(tdb_img_); +TEST_F(ImageTest, GetBuffer) { + VCL::Image img_data(tdb_img_); - int size = cv_img_.rows * cv_img_.cols * cv_img_.channels(); - unsigned char* buf = new unsigned char[size]; + int size = cv_img_.rows * cv_img_.cols * cv_img_.channels(); + unsigned char *buf = new unsigned char[size]; - img_data.get_raw_data(buf, size); + img_data.get_raw_data(buf, size); - compare_mat_buffer(cv_img_, buf); + compare_mat_buffer(cv_img_, buf); } -TEST_F(ImageTest, GetCVMat) -{ - VCL::Image img_data(tdb_img_); +TEST_F(ImageTest, GetCVMat) { + VCL::Image img_data(tdb_img_); - cv::Mat cv_img = img_data.get_cvmat(); + cv::Mat cv_img = img_data.get_cvmat(); - compare_mat_mat(cv_img_, cv_img); + compare_mat_mat(cv_img_, cv_img); } -TEST_F(ImageTest, GetRectangleFromPNG) -{ - VCL::Image img(img_); +TEST_F(ImageTest, GetRectangleFromPNG) { + VCL::Image img(img_); - VCL::Image corner = img.get_area(rect_); + VCL::Image corner = img.get_area(rect_); - cv::Size dims = corner.get_dimensions(); + cv::Size dims = corner.get_dimensions(); - EXPECT_EQ(rect_.height, dims.height); - EXPECT_EQ(rect_.width, dims.width); + EXPECT_EQ(rect_.height, dims.height); + EXPECT_EQ(rect_.width, dims.width); } -TEST_F(ImageTest, GetRectangleFromTDB) -{ - VCL::Image img(tdb_img_); - try{ +TEST_F(ImageTest, GetRectangleFromTDB) { + VCL::Image img(tdb_img_); + try { VCL::Image corner = img.get_area(rect_); cv::Size dims = corner.get_dimensions(); EXPECT_EQ(rect_.height, dims.height); EXPECT_EQ(rect_.width, dims.width); - } catch(VCL::Exception &e) { + } catch (VCL::Exception &e) { print_exception(e); - } + } } -TEST_F(ImageTest, GetRectangleFromMat) -{ - VCL::Image img(cv_img_); +TEST_F(ImageTest, GetRectangleFromMat) { + VCL::Image img(cv_img_); - VCL::Image corner = img.get_area(rect_); + VCL::Image corner = img.get_area(rect_); - cv::Size dims = corner.get_dimensions(); + cv::Size dims = corner.get_dimensions(); - EXPECT_EQ(rect_.height, dims.height); - EXPECT_EQ(rect_.width, dims.width); + EXPECT_EQ(rect_.height, dims.height); + EXPECT_EQ(rect_.width, dims.width); } -TEST_F(ImageTest, SetDataFromRaw) -{ - VCL::ImageTest img_data; +TEST_F(ImageTest, SetDataFromRaw) { + VCL::ImageTest img_data; - void* buffer = cv_img_.data; - int size = cv_img_.rows * cv_img_.cols * cv_img_.channels(); + void *buffer = cv_img_.data; + int size = cv_img_.rows * cv_img_.cols * cv_img_.channels(); - img_data.set_data_from_raw(buffer, size); + img_data.set_data_from_raw(buffer, size); - cv::Mat raw = img_data.get_cvmat(); + cv::Mat raw = img_data.get_cvmat(); - compare_mat_mat(cv_img_, raw); + compare_mat_mat(cv_img_, raw); } -TEST_F(ImageTest, SetDataFromEncoded) -{ - VCL::ImageTest img_data; +TEST_F(ImageTest, SetDataFromEncoded) { + VCL::ImageTest img_data; - std::vector buffer; - cv::imencode(".png", cv_img_, buffer); + std::vector buffer; + cv::imencode(".png", cv_img_, buffer); - img_data.set_data_from_encoded(static_cast(&buffer[0]), buffer.size()); + img_data.set_data_from_encoded(static_cast(&buffer[0]), + buffer.size()); - cv::Mat raw = img_data.get_cvmat(); + cv::Mat raw = img_data.get_cvmat(); - compare_mat_mat(raw, cv_img_); + compare_mat_mat(raw, cv_img_); } -TEST_F(ImageTest, Read) -{ - VCL::ImageTest img_data; - img_data.set_format("jpg"); +TEST_F(ImageTest, Read) { + VCL::ImageTest img_data; + img_data.set_format("jpg"); - ASSERT_THROW(img_data.read("test_images/.jpg"), VCL::Exception); + ASSERT_THROW(img_data.read("test_images/.jpg"), VCL::Exception); - img_data.read("test_images/large1"); + img_data.read("test_images/large1"); - EXPECT_EQ("test_images/large1.jpg", img_data.get_image_id()); + EXPECT_EQ("test_images/large1.jpg", img_data.get_image_id()); } -TEST_F(ImageTest, WriteMatToJPG) -{ - VCL::Image img(cv_img_); - img.store("test_images/test_image", VCL::Image::Format::JPG); +TEST_F(ImageTest, WriteMatToJPG) { + VCL::Image img(cv_img_); + img.store("test_images/test_image", VCL::Image::Format::JPG); - cv::Mat test = cv::imread("test_images/test_image.jpg"); + cv::Mat test = cv::imread("test_images/test_image.jpg"); - EXPECT_FALSE( test.empty() ); + EXPECT_FALSE(test.empty()); } -TEST_F(ImageTest, WriteMatToTDB) -{ - VCL::Image img(cv_img_); - img.store("tdb/mat_to_tdb", VCL::Image::Format::TDB); +TEST_F(ImageTest, WriteMatToTDB) { + VCL::Image img(cv_img_); + img.store("tdb/mat_to_tdb", VCL::Image::Format::TDB); } -TEST_F(ImageTest, WriteStringToTDB) -{ - VCL::Image img(img_); - img.store("tdb/png_to_tdb.png", VCL::Image::Format::TDB); +TEST_F(ImageTest, WriteStringToTDB) { + VCL::Image img(img_); + img.store("tdb/png_to_tdb.png", VCL::Image::Format::TDB); } -TEST_F(ImageTest, ResizeMat) -{ - VCL::Image img(img_); - img.resize(dimension_, dimension_); +TEST_F(ImageTest, ResizeMat) { + VCL::Image img(img_); + img.resize(dimension_, dimension_); - cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img = img.get_cvmat(); - EXPECT_FALSE(cv_img.empty()); - EXPECT_EQ(dimension_, cv_img.rows); + EXPECT_FALSE(cv_img.empty()); + EXPECT_EQ(dimension_, cv_img.rows); } -TEST_F(ImageTest, ResizeTDB) -{ - VCL::Image img(tdb_img_); - img.resize(dimension_, dimension_); +TEST_F(ImageTest, ResizeTDB) { + VCL::Image img(tdb_img_); + img.resize(dimension_, dimension_); - cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img = img.get_cvmat(); - EXPECT_FALSE(cv_img.empty()); - EXPECT_EQ(dimension_, cv_img.rows); + EXPECT_FALSE(cv_img.empty()); + EXPECT_EQ(dimension_, cv_img.rows); } -TEST_F(ImageTest, CropMatThrow) -{ - VCL::Image img(img_); - img.crop(bad_rect_); +TEST_F(ImageTest, CropMatThrow) { + VCL::Image img(img_); + img.crop(bad_rect_); - ASSERT_THROW(img.get_cvmat(), VCL::Exception); + ASSERT_THROW(img.get_cvmat(), VCL::Exception); } -TEST_F(ImageTest, CropMat) -{ - VCL::Image img(img_); - img.crop(rect_); +TEST_F(ImageTest, CropMat) { + VCL::Image img(img_); + img.crop(rect_); - cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img = img.get_cvmat(); - EXPECT_FALSE(cv_img.empty()); + EXPECT_FALSE(cv_img.empty()); - cv::Size dims = img.get_dimensions(); + cv::Size dims = img.get_dimensions(); - EXPECT_EQ(rect_.height, dims.height); - EXPECT_EQ(rect_.width, dims.width); + EXPECT_EQ(rect_.height, dims.height); + EXPECT_EQ(rect_.width, dims.width); - cv::Mat mat(cv_img_, rect_); - compare_mat_mat(cv_img, mat); + cv::Mat mat(cv_img_, rect_); + compare_mat_mat(cv_img, mat); } -TEST_F(ImageTest, Threshold) -{ - VCL::ImageTest img_data(tdb_img_); +TEST_F(ImageTest, Threshold) { + VCL::ImageTest img_data(tdb_img_); - img_data.read(tdb_img_); + img_data.read(tdb_img_); - img_data.threshold(200); + img_data.threshold(200); - img_data.perform_operations(); + img_data.perform_operations(); - cv::Mat cv_bright = img_data.get_cvmat(); + cv::Mat cv_bright = img_data.get_cvmat(); - cv::threshold(cv_img_, cv_img_, 200, 200, cv::THRESH_TOZERO); + cv::threshold(cv_img_, cv_img_, 200, 200, cv::THRESH_TOZERO); - compare_mat_mat(cv_bright, cv_img_); + compare_mat_mat(cv_bright, cv_img_); } -TEST_F(ImageTest, DeleteTDB) -{ - VCL::ImageTest img_data("tdb/no_metadata.tdb"); +TEST_F(ImageTest, DeleteTDB) { + VCL::ImageTest img_data("tdb/no_metadata.tdb"); - img_data.delete_image(); + img_data.delete_image(); - img_data.read("tdb/no_metadata.tdb"); - ASSERT_THROW(img_data.perform_operations(), VCL::Exception); + img_data.read("tdb/no_metadata.tdb"); + ASSERT_THROW(img_data.perform_operations(), VCL::Exception); } // This test is not passing @@ -658,187 +617,247 @@ TEST_F(ImageTest, DeleteTDB) // ASSERT_THROW(img_data.perform_operations(), VCL::Exception); // } -TEST_F(ImageTest, SetMinimum) -{ - VCL::Image img_data(cv_img_); +TEST_F(ImageTest, SetMinimum) { + VCL::Image img_data(cv_img_); - img_data.set_minimum_dimension(3); + img_data.set_minimum_dimension(3); } -TEST_F(ImageTest, FlipVertical) -{ - VCL::Image img(img_); - cv::Mat cv_img = img.get_cvmat(); - cv::Mat cv_img_flipped = cv::Mat(cv_img.rows, cv_img.cols, cv_img.type()); - cv::flip(cv_img, cv_img_flipped, 0); +TEST_F(ImageTest, FlipVertical) { + VCL::Image img(img_); + cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img_flipped = cv::Mat(cv_img.rows, cv_img.cols, cv_img.type()); + cv::flip(cv_img, cv_img_flipped, 0); - img.flip(0); - cv::Mat vcl_img_flipped = img.get_cvmat(); + img.flip(0); + cv::Mat vcl_img_flipped = img.get_cvmat(); - EXPECT_FALSE(vcl_img_flipped.empty()); - compare_mat_mat(vcl_img_flipped, cv_img_flipped); + EXPECT_FALSE(vcl_img_flipped.empty()); + compare_mat_mat(vcl_img_flipped, cv_img_flipped); } -TEST_F(ImageTest, FlipHorizontal) -{ - VCL::Image img(img_); - cv::Mat cv_img = img.get_cvmat(); - cv::Mat cv_img_flipped = cv::Mat(cv_img.rows, cv_img.cols, cv_img.type()); - cv::flip(cv_img, cv_img_flipped, 1); +TEST_F(ImageTest, FlipHorizontal) { + VCL::Image img(img_); + cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img_flipped = cv::Mat(cv_img.rows, cv_img.cols, cv_img.type()); + cv::flip(cv_img, cv_img_flipped, 1); - img.flip(1); - cv::Mat vcl_img_flipped = img.get_cvmat(); + img.flip(1); + cv::Mat vcl_img_flipped = img.get_cvmat(); - EXPECT_FALSE(vcl_img_flipped.empty()); - compare_mat_mat(vcl_img_flipped, cv_img_flipped); + EXPECT_FALSE(vcl_img_flipped.empty()); + compare_mat_mat(vcl_img_flipped, cv_img_flipped); } -TEST_F(ImageTest, FlipBoth) -{ - VCL::Image img(img_); - cv::Mat cv_img = img.get_cvmat(); - cv::Mat cv_img_flipped = cv::Mat(cv_img.rows, cv_img.cols, cv_img.type()); - cv::flip(cv_img, cv_img_flipped, -1); +TEST_F(ImageTest, FlipBoth) { + VCL::Image img(img_); + cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img_flipped = cv::Mat(cv_img.rows, cv_img.cols, cv_img.type()); + cv::flip(cv_img, cv_img_flipped, -1); - img.flip(-1); - cv::Mat vcl_img_flipped = img.get_cvmat(); + img.flip(-1); + cv::Mat vcl_img_flipped = img.get_cvmat(); - EXPECT_FALSE(vcl_img_flipped.empty()); - compare_mat_mat(vcl_img_flipped, cv_img_flipped); + EXPECT_FALSE(vcl_img_flipped.empty()); + compare_mat_mat(vcl_img_flipped, cv_img_flipped); } -TEST_F(ImageTest, Rotate) -{ - float angle = 30; - VCL::Image img(img_); - cv::Mat cv_img = img.get_cvmat(); - cv::Mat cv_img_rot = cv::Mat(cv_img.rows, cv_img.cols, cv_img.type()); +TEST_F(ImageTest, Rotate) { + float angle = 30; + VCL::Image img(img_); + cv::Mat cv_img = img.get_cvmat(); + cv::Mat cv_img_rot = cv::Mat(cv_img.rows, cv_img.cols, cv_img.type()); - cv::Point2f pc(cv_img.cols/2., cv_img.rows/2.); - cv::Mat r = cv::getRotationMatrix2D(pc, angle, 1.0); - cv::warpAffine(cv_img, cv_img_rot, r, cv_img.size()); + cv::Point2f pc(cv_img.cols / 2., cv_img.rows / 2.); + cv::Mat r = cv::getRotationMatrix2D(pc, angle, 1.0); + cv::warpAffine(cv_img, cv_img_rot, r, cv_img.size()); - img.rotate(angle, true); - cv::Mat vcl_img_rot = img.get_cvmat(); + img.rotate(angle, true); + cv::Mat vcl_img_rot = img.get_cvmat(); - EXPECT_FALSE(vcl_img_rot.empty()); - compare_mat_mat(vcl_img_rot, cv_img_rot); + EXPECT_FALSE(vcl_img_rot.empty()); + compare_mat_mat(vcl_img_rot, cv_img_rot); } -TEST_F(ImageTest, RotateResize) -{ - float angle = 30; - VCL::Image img(img_); - cv::Mat cv_img = img.get_cvmat(); +TEST_F(ImageTest, RotateResize) { + float angle = 30; + VCL::Image img(img_); + cv::Mat cv_img = img.get_cvmat(); - cv::Point2f im_c((cv_img.cols-1)/2.0, (cv_img.rows-1)/2.0); - cv::Mat r = cv::getRotationMatrix2D(im_c, angle, 1.0); + cv::Point2f im_c((cv_img.cols - 1) / 2.0, (cv_img.rows - 1) / 2.0); + cv::Mat r = cv::getRotationMatrix2D(im_c, angle, 1.0); - cv::Rect2f bbox = cv::RotatedRect(cv::Point2f(), cv_img.size(), - angle).boundingRect2f(); - // Transformation Matrix - r.at(0,2) += bbox.width/2.0 - cv_img.cols/2.0; - r.at(1,2) += bbox.height/2.0 - cv_img.rows/2.0; + cv::Rect2f bbox = + cv::RotatedRect(cv::Point2f(), cv_img.size(), angle).boundingRect2f(); + // Transformation Matrix + r.at(0, 2) += bbox.width / 2.0 - cv_img.cols / 2.0; + r.at(1, 2) += bbox.height / 2.0 - cv_img.rows / 2.0; - cv::Mat cv_img_rot; - cv::warpAffine(cv_img, cv_img_rot, r, bbox.size()); + cv::Mat cv_img_rot; + cv::warpAffine(cv_img, cv_img_rot, r, bbox.size()); - img.rotate(angle, false); - cv::Mat vcl_img_rot = img.get_cvmat(); + img.rotate(angle, false); + cv::Mat vcl_img_rot = img.get_cvmat(); - EXPECT_FALSE(vcl_img_rot.empty()); - compare_mat_mat(vcl_img_rot, cv_img_rot); + EXPECT_FALSE(vcl_img_rot.empty()); + compare_mat_mat(vcl_img_rot, cv_img_rot); } -TEST_F(ImageTest, TDBMatThrow) -{ - VCL::Image img(tdb_img_); - img.crop(bad_rect_); +TEST_F(ImageTest, TDBMatThrow) { + VCL::Image img(tdb_img_); + img.crop(bad_rect_); - ASSERT_THROW(img.get_cvmat(), VCL::Exception); + ASSERT_THROW(img.get_cvmat(), VCL::Exception); } -TEST_F(ImageTest, CropTDB) -{ - cv::Mat cv_img; +TEST_F(ImageTest, CropTDB) { + cv::Mat cv_img; - VCL::Image img(tdb_img_); + VCL::Image img(tdb_img_); - img.crop(rect_); + img.crop(rect_); - cv_img = img.get_cvmat(); + cv_img = img.get_cvmat(); - EXPECT_FALSE(cv_img.empty()); - EXPECT_EQ(rect_.height, cv_img.rows); + EXPECT_FALSE(cv_img.empty()); + EXPECT_EQ(rect_.height, cv_img.rows); } -TEST_F(ImageTest, CompareMatAndBuffer) -{ - VCL::Image img(img_); +TEST_F(ImageTest, CompareMatAndBuffer) { + VCL::Image img(img_); - unsigned char* data_buffer = new unsigned char[img.get_raw_data_size()]; - img.get_raw_data(data_buffer, img.get_raw_data_size()); + unsigned char *data_buffer = new unsigned char[img.get_raw_data_size()]; + img.get_raw_data(data_buffer, img.get_raw_data_size()); - compare_mat_buffer(cv_img_, data_buffer); + compare_mat_buffer(cv_img_, data_buffer); } -TEST_F(ImageTest, TDBToPNG) -{ - VCL::Image img(tdb_img_); +TEST_F(ImageTest, TDBToPNG) { + VCL::Image img(tdb_img_); - img.store("test_images/tdb_to_png", VCL::Image::Format::PNG); + img.store("test_images/tdb_to_png", VCL::Image::Format::PNG); } -TEST_F(ImageTest, TDBToJPG) -{ - VCL::Image img(tdb_img_); +TEST_F(ImageTest, TDBToJPG) { + VCL::Image img(tdb_img_); - img.store("test_images/tdb_to_jpg", VCL::Image::Format::JPG); + img.store("test_images/tdb_to_jpg", VCL::Image::Format::JPG); } -TEST_F(ImageTest, EncodedImage) -{ - VCL::Image img(tdb_img_); +TEST_F(ImageTest, EncodedImage) { + VCL::Image img(tdb_img_); - std::vector buffer = img.get_encoded_image(VCL::Image::Format::PNG); + std::vector buffer = + img.get_encoded_image(VCL::Image::Format::PNG); - cv::Mat mat = cv::imdecode(buffer, cv::IMREAD_ANYCOLOR); - compare_mat_mat(cv_img_, mat); + cv::Mat mat = cv::imdecode(buffer, cv::IMREAD_ANYCOLOR); + compare_mat_mat(cv_img_, mat); } -TEST_F(ImageTest, CreateNamePNG) -{ - VCL::ImageTest img_data(cv_img_); +TEST_F(ImageTest, CreateNamePNG) { + VCL::ImageTest img_data(cv_img_); - auto unique_name = VCL::create_unique("image_results/", "png"); + auto unique_name = VCL::create_unique("image_results/", "png"); - img_data.store(unique_name, VCL::Image::Format::PNG); - img_data.perform_operations(); + img_data.store(unique_name, VCL::Image::Format::PNG); + img_data.perform_operations(); } -TEST_F(ImageTest, CreateNameTDB) -{ - VCL::Image img(cv_img_); +TEST_F(ImageTest, CreateNameTDB) { + VCL::Image img(cv_img_); - for ( int i = 0; i < 10; ++i ) { - std::string name = VCL::create_unique("tdb/", "tdb"); - img.store(name, VCL::Image::Format::TDB); - } + for (int i = 0; i < 10; ++i) { + std::string name = VCL::create_unique("tdb/", "tdb"); + img.store(name, VCL::Image::Format::TDB); + } } -TEST_F(ImageTest, NoMetadata){ - VCL::Image img(cv_img_); +TEST_F(ImageTest, NoMetadata) { + VCL::Image img(cv_img_); - std::string name = VCL::create_unique("tdb/", "tdb"); - img.store(name, VCL::Image::Format::TDB, false); + std::string name = VCL::create_unique("tdb/", "tdb"); + img.store(name, VCL::Image::Format::TDB, false); + + cv::Size dims = img.get_dimensions(); + int cv_type = img.get_image_type(); + + VCL::Image tdbimg(name); + + tdbimg.set_image_type(cv_type); + tdbimg.set_dimensions(dims); + + cv::Mat mat = tdbimg.get_cvmat(); +} + +TEST_F(ImageTest, SyncRemote) { + VCL::Image img(img_); + + cv::Mat cv_img_flipped = cv::imread("../remote_function_test/syncremote.jpg"); + + std::string _url = "http://localhost:5010/image"; + Json::Value _options; + _options["format"] = "jpg"; + _options["id"] = "flip"; + img.syncremoteOperation(_url, _options); + cv::Mat vcl_img_flipped = img.get_cvmat(); - cv::Size dims = img.get_dimensions(); - int cv_type = img.get_image_type(); + EXPECT_FALSE(vcl_img_flipped.empty()); + compare_mat_mat(vcl_img_flipped, cv_img_flipped); +} + +TEST_F(ImageTest, UDF) { + SystemStats systemStats; + VCL::Image img(img_); + + cv::Mat cv_img_flipped = cv::imread("../udf_test/syncremote.jpg"); + + Json::Value _options; + _options["format"] = "jpg"; + _options["id"] = "flip"; + _options["port"] = 5555; + img.userOperation(_options); + cv::Mat vcl_img_flipped = img.get_cvmat(); - VCL::Image tdbimg(name); + systemStats.log_stats("TestUDF"); - tdbimg.set_image_type(cv_type); - tdbimg.set_dimensions(dims); + FILE *f = fopen(systemStats.logFileName.data(), "r"); + ASSERT_TRUE(f != NULL); - cv::Mat mat = tdbimg.get_cvmat(); + if (f) { + fclose(f); + } + + EXPECT_FALSE(vcl_img_flipped.empty()); + compare_mat_mat(vcl_img_flipped, cv_img_flipped); } + +TEST_F(ImageTest, ImageLoop) { + VCL::Image img(img_); + ImageLoop imageLoop; + + std::string _url = "http://localhost:5010/image"; + Json::Value _options; + _options["format"] = "jpg"; + _options["id"] = "flip"; + + img.flip(0); + img.remoteOperation(_url, _options); + + imageLoop.set_nrof_entities(1); + + imageLoop.enqueue(&img); + + while (imageLoop.is_loop_running()) { + continue; + } + + std::map imageMap = imageLoop.get_image_map(); + std::map::iterator iter = imageMap.begin(); + + while (iter != imageMap.end()) { + std::vector img_enc = + iter->second->get_encoded_image_async(img.get_image_format()); + ASSERT_TRUE(!img_enc.empty()); + iter++; + } +} \ No newline at end of file diff --git a/tests/unit_tests/RemoteConnection_test.cc b/tests/unit_tests/RemoteConnection_test.cc new file mode 100644 index 00000000..9b1191de --- /dev/null +++ b/tests/unit_tests/RemoteConnection_test.cc @@ -0,0 +1,297 @@ +/** + * @file ImageData_test.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Image.h" +#include "TDBImage.h" +#include "gtest/gtest.h" + +#include "RemoteConnection.h" + +#include +#include +#include + +#include + +class RemoteConnectionTest : public ::testing::Test { +protected: + virtual void SetUp() { + img_ = "test_images/large1.jpg"; + tdb_img_ = "tdb/test_image.tdb"; + video_ = "test_videos/Megamind.avi"; + cv_img_ = cv::imread(img_, cv::IMREAD_ANYCOLOR); + rect_ = VCL::Rectangle(100, 100, 100, 100); + + connection_ = new VCL::RemoteConnection(); + connection_->_bucket_name = "minio-bucket"; + connection_->start(); + } + + virtual void TearDown() { + connection_->end(); + delete connection_; + } + + void compare_mat_mat(cv::Mat &cv_img, cv::Mat &img) { + int rows = img.rows; + int columns = img.cols; + int channels = img.channels(); + + if (img.isContinuous()) { + columns *= rows; + rows = 1; + } + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (channels == 1) { + unsigned char pixel = img.at(i, j); + unsigned char test_pixel = cv_img.at(i, j); + ASSERT_EQ(pixel, test_pixel); + } else { + cv::Vec3b colors = img.at(i, j); + cv::Vec3b test_colors = cv_img.at(i, j); + for (int x = 0; x < channels; ++x) { + ASSERT_EQ(colors.val[x], test_colors.val[x]); + } + } + } + } + } + + // needed a special compare function for JPGs because of small encoding + // differences pixel values can vary by up to 19 in my observations (tmcourie) + void compare_mat_mat_jpg(cv::Mat &cv_img, cv::Mat &img) { + int rows = img.rows; + int columns = img.cols; + int channels = img.channels(); + + if (img.isContinuous()) { + columns *= rows; + rows = 1; + } + + // TODO determine an appropriate value for this + int pixel_similarity_threshhold = 20; + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (channels == 1) { + unsigned char pixel = img.at(i, j); + unsigned char test_pixel = cv_img.at(i, j); + ASSERT_LE(abs(pixel - test_pixel), pixel_similarity_threshhold); + } else { + cv::Vec3b colors = img.at(i, j); + cv::Vec3b test_colors = cv_img.at(i, j); + for (int x = 0; x < channels; ++x) { + ASSERT_LE(abs(colors.val[x] - test_colors.val[x]), + pixel_similarity_threshhold); + } + } + } + } + } + + void compare_mat_buffer(cv::Mat &img, unsigned char *buffer) { + int index = 0; + + int rows = img.rows; + int columns = img.cols; + int channels = img.channels(); + + if (img.isContinuous()) { + columns *= rows; + rows = 1; + } + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (channels == 1) { + unsigned char pixel = img.at(i, j); + ASSERT_EQ(pixel, buffer[index]); + } else { + cv::Vec3b colors = img.at(i, j); + for (int x = 0; x < channels; ++x) { + ASSERT_EQ(colors.val[x], buffer[index + x]); + } + } + index += channels; + } + } + } + + std::string img_; + std::string video_; + std::string tdb_img_; + std::string test_img_; + cv::Mat cv_img_; + VCL::Rectangle rect_; + VCL::RemoteConnection *connection_; +}; + +namespace VCL { + +class ImageTest : public Image { + +public: + ImageTest() : Image() {} + ImageTest(std::string a) : Image(a) {} + ImageTest(cv::Mat &a) : Image(a) {} + + using Image::perform_operations; + using Image::read; + using Image::set_data_from_encoded; + using Image::set_data_from_raw; + using Image::set_format; +}; +}; // namespace VCL + +// Basic Remote Connection Tests + +TEST_F(RemoteConnectionTest, RemoteWriteFilename) { connection_->Write(img_); } + +TEST_F(RemoteConnectionTest, RemoteReadWriteBuffer) { + std::vector img_data = connection_->Read(img_); + connection_->Write(img_, img_data); +} + +TEST_F(RemoteConnectionTest, RemoteListRetrieveFile) { + std::vector file_list = + connection_->ListFilesInFolder("test_images"); + connection_->RetrieveFile(file_list[0]); +} + +TEST_F(RemoteConnectionTest, RemoteWriteVideoFilename) { + connection_->Write(video_); +} + +TEST_F(RemoteConnectionTest, RemoteReadVideoFilename) { + connection_->Read_Video(video_); +} + +//#### Regular Image tests #### + +TEST_F(RemoteConnectionTest, ImageRemoteWritePNG) { + VCL::ImageTest img(cv_img_); + + img.set_connection(connection_); + std::string path = "pngs/test_image.png"; + + img.store(path, VCL::Image::Format::PNG); + img.perform_operations(); +} + +TEST_F(RemoteConnectionTest, ImageRemoteReadPNG) { + VCL::ImageTest img; + + img.set_connection(connection_); + std::string path = "pngs/test_image.png"; + + img.read(path); + + cv::Mat data = img.get_cvmat(); + compare_mat_mat(data, cv_img_); +} + +TEST_F(RemoteConnectionTest, ImageRemoteRemovePNG) { + VCL::Image img("pngs/test_image.png"); + img.set_connection(connection_); + img.delete_image(); +} + +TEST_F(RemoteConnectionTest, ImageRemoteWriteJPG) { + VCL::Image img(cv_img_); + + img.set_connection(connection_); + std::string path = "jpgs/large1.jpg"; + + img.store(path, VCL::Image::Format::JPG); +} + +TEST_F(RemoteConnectionTest, ImageRemoteReadJPG) { + VCL::Image img("jpgs/large1.jpg"); + img.set_connection(connection_); + + cv::Mat mat = img.get_cvmat(); + compare_mat_mat_jpg(mat, cv_img_); +} + +TEST_F(RemoteConnectionTest, ImageRemoteRemoveJPG) { + VCL::Image img("jpgs/large1.jpg"); + img.set_connection(connection_); + img.delete_image(); +} + +//#### TileDB Image tests #### +TEST_F(RemoteConnectionTest, TDBImageWriteS3) { + VCL::TDBImage tdb("tdb/test_image.tdb", *connection_); + tdb.write(cv_img_); +} + +// Basic Remote Connection Tests (no remote connected, expected failures) + +TEST_F(RemoteConnectionTest, RemoteDisconnectedWriteFilename) { + VCL::RemoteConnection not_a_connection; + not_a_connection.Write(img_); +} + +TEST_F(RemoteConnectionTest, RemoteDisconnectedReadBuffer) { + VCL::RemoteConnection not_a_connection; + std::vector img_data = not_a_connection.Read(img_); + connection_->Write(img_, img_data); +} + +TEST_F(RemoteConnectionTest, RemoteDisconnectedWriteBuffer) { + VCL::RemoteConnection not_a_connection; + std::vector img_data = connection_->Read(img_); + not_a_connection.Write(img_, img_data); +} + +TEST_F(RemoteConnectionTest, RemoteDisconnectedListFiles) { + VCL::RemoteConnection not_a_connection; + std::vector file_list = + not_a_connection.ListFilesInFolder("test_images"); +} + +TEST_F(RemoteConnectionTest, RemoteDisconnectedRetrieveFile) { + VCL::RemoteConnection not_a_connection; + std::vector file_list = + connection_->ListFilesInFolder("test_images"); + not_a_connection.RetrieveFile(file_list[0]); +} + +TEST_F(RemoteConnectionTest, RemoteDisconnectedWriteVideoFilename) { + VCL::RemoteConnection not_a_connection; + not_a_connection.Write(video_); +} + +TEST_F(RemoteConnectionTest, RemoteDisconnectedReadVideoFilename) { + VCL::RemoteConnection not_a_connection; + not_a_connection.Read_Video(video_); +} diff --git a/tests/unit_tests/TDBImage_test.cc b/tests/unit_tests/TDBImage_test.cc index 2b9097f2..1c4afee5 100644 --- a/tests/unit_tests/TDBImage_test.cc +++ b/tests/unit_tests/TDBImage_test.cc @@ -27,9 +27,8 @@ * */ - -#include "TDBObject.h" #include "TDBImage.h" +#include "TDBObject.h" #include "gtest/gtest.h" #include @@ -40,443 +39,411 @@ class TDBImageTest : public ::testing::Test { protected: - virtual void SetUp() { - tdb_img_ = "tdb/test_image.tdb"; - tdb_test_ = "tdb/write_test.tdb"; - cv_img_ = cv::imread("test_images/large1.jpg", cv::IMREAD_ANYCOLOR); - rect_ = VCL::Rectangle(100, 100, 100, 100); + virtual void SetUp() { + tdb_img_ = "tdb/test_image.tdb"; + tdb_test_ = "tdb/write_test.tdb"; + cv_img_ = cv::imread("test_images/large1.jpg", cv::IMREAD_ANYCOLOR); + rect_ = VCL::Rectangle(100, 100, 100, 100); + } + + void compare_mat_buffer(cv::Mat &img, unsigned char *buffer) { + int index = 0; + + int rows = img.rows; + int columns = img.cols; + int channels = img.channels(); + if (channels > 3) { + throw VCLException(OpenFailed, "Greater than 3 channels in image"); } - void compare_mat_buffer(cv::Mat &img, unsigned char* buffer) - { - int index = 0; - - int rows = img.rows; - int columns = img.cols; - int channels = img.channels(); - if(channels > 3) - { - throw VCLException(OpenFailed, "Greater than 3 channels in image"); - } - - - if ( img.isContinuous() ) { - columns *= rows; - rows = 1; - } - - for ( int i = 0; i < rows; ++i ) { - for ( int j = 0; j < columns; ++j ) { - if (channels == 1) { - unsigned char pixel = img.at(i, j); - ASSERT_EQ(pixel, buffer[index]); - } - else { - cv::Vec3b colors = img.at(i, j); - for ( int x = 0; x < channels; ++x ) { - ASSERT_EQ(colors.val[x], buffer[index + x]); - } - } - index += channels; - } - } + if (img.isContinuous()) { + columns *= rows; + rows = 1; } - void compare_mat_mat(cv::Mat &cv_img, cv::Mat &img) - { - int rows = img.rows; - int columns = img.cols; - int channels = img.channels(); - if(channels > 3) - { - throw VCLException(OpenFailed, "Greater than 3 channels in image"); + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (channels == 1) { + unsigned char pixel = img.at(i, j); + ASSERT_EQ(pixel, buffer[index]); + } else { + cv::Vec3b colors = img.at(i, j); + for (int x = 0; x < channels; ++x) { + ASSERT_EQ(colors.val[x], buffer[index + x]); + } } + index += channels; + } + } + } + + void compare_mat_mat(cv::Mat &cv_img, cv::Mat &img) { + int rows = img.rows; + int columns = img.cols; + int channels = img.channels(); + if (channels > 3) { + throw VCLException(OpenFailed, "Greater than 3 channels in image"); + } - if ( img.isContinuous() ) { - columns *= rows; - rows = 1; - } + if (img.isContinuous()) { + columns *= rows; + rows = 1; + } - for ( int i = 0; i < rows; ++i ) { - for ( int j = 0; j < columns; ++j ) { - if (channels == 1) { - unsigned char pixel = img.at(i, j); - unsigned char test_pixel = cv_img.at(i, j); - ASSERT_EQ(pixel, test_pixel); - } - else { - cv::Vec3b colors = img.at(i, j); - cv::Vec3b test_colors = cv_img.at(i, j); - for ( int x = 0; x < channels; ++x ) { - ASSERT_EQ(colors.val[x], test_colors.val[x]); - } - } - } + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (channels == 1) { + unsigned char pixel = img.at(i, j); + unsigned char test_pixel = cv_img.at(i, j); + ASSERT_EQ(pixel, test_pixel); + } else { + cv::Vec3b colors = img.at(i, j); + cv::Vec3b test_colors = cv_img.at(i, j); + for (int x = 0; x < channels; ++x) { + ASSERT_EQ(colors.val[x], test_colors.val[x]); + } } + } } + } - void compare_buffer_buffer(unsigned char* buffer1, unsigned char* buffer2, int length) - { - for ( int i = 0; i < length; ++i ) { - ASSERT_EQ(buffer1[i], buffer2[i]); - } + void compare_buffer_buffer(unsigned char *buffer1, unsigned char *buffer2, + int length) { + for (int i = 0; i < length; ++i) { + ASSERT_EQ(buffer1[i], buffer2[i]); } + } - std::string tdb_img_; - std::string tdb_test_; - cv::Mat cv_img_; - VCL::Rectangle rect_; + std::string tdb_img_; + std::string tdb_test_; + cv::Mat cv_img_; + VCL::Rectangle rect_; }; +TEST_F(TDBImageTest, DefaultConstructor) { + VCL::TDBImage tdb; - - -TEST_F(TDBImageTest, DefaultConstructor) -{ - VCL::TDBImage tdb; - - ASSERT_THROW(tdb.get_image_height(), VCL::Exception); - ASSERT_THROW(tdb.get_image_width(), VCL::Exception); - ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); + ASSERT_THROW(tdb.get_image_height(), VCL::Exception); + ASSERT_THROW(tdb.get_image_width(), VCL::Exception); + ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); } -TEST_F(TDBImageTest, StringConstructor) -{ - VCL::TDBImage tdb(tdb_img_); +TEST_F(TDBImageTest, StringConstructor) { + VCL::TDBImage tdb(tdb_img_); - ASSERT_THROW(tdb.get_image_height(), VCL::Exception); - ASSERT_THROW(tdb.get_image_width(), VCL::Exception); - ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); + ASSERT_THROW(tdb.get_image_height(), VCL::Exception); + ASSERT_THROW(tdb.get_image_width(), VCL::Exception); + ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); - EXPECT_EQ("tdb/test_image.tdb", tdb.get_object_id()); + EXPECT_EQ("tdb/test_image.tdb", tdb.get_object_id()); } -TEST_F(TDBImageTest, BufferConstructor) -{ - unsigned char* buffer = cv_img_.data; +TEST_F(TDBImageTest, BufferConstructor) { + unsigned char *buffer = cv_img_.data; - long size = long(cv_img_.rows) * long(cv_img_.cols) * cv_img_.channels(); + long size = long(cv_img_.rows) * long(cv_img_.cols) * cv_img_.channels(); - VCL::TDBImage tdb(buffer, size); + VCL::TDBImage tdb(buffer, size); - ASSERT_THROW(tdb.get_image_height(), VCL::Exception); - ASSERT_THROW(tdb.get_image_width(), VCL::Exception); - ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); + ASSERT_THROW(tdb.get_image_height(), VCL::Exception); + ASSERT_THROW(tdb.get_image_width(), VCL::Exception); + ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); - unsigned char* buf = new unsigned char[size]; - tdb.get_buffer(buf, size); + unsigned char *buf = new unsigned char[size]; + tdb.get_buffer(buf, size); - compare_mat_buffer(cv_img_, buf); + compare_mat_buffer(cv_img_, buf); - delete [] buf; + delete[] buf; } -TEST_F(TDBImageTest, CopyConstructorNoData) -{ - VCL::TDBImage tdb("tdb/copy_construct.tdb"); +TEST_F(TDBImageTest, CopyConstructorNoData) { + VCL::TDBImage tdb("tdb/copy_construct.tdb"); - ASSERT_THROW(tdb.get_image_height(), VCL::Exception); - ASSERT_THROW(tdb.get_image_width(), VCL::Exception); - ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); + ASSERT_THROW(tdb.get_image_height(), VCL::Exception); + ASSERT_THROW(tdb.get_image_width(), VCL::Exception); + ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); - EXPECT_EQ("tdb/copy_construct.tdb", tdb.get_object_id()); + EXPECT_EQ("tdb/copy_construct.tdb", tdb.get_object_id()); - VCL::TDBImage imgcopy(tdb); - ASSERT_THROW(imgcopy.get_image_height(), VCL::Exception); - ASSERT_THROW(imgcopy.get_image_width(), VCL::Exception); - ASSERT_THROW(imgcopy.get_image_channels(), VCL::Exception); - ASSERT_FALSE(imgcopy.has_data()); + VCL::TDBImage imgcopy(tdb); + ASSERT_THROW(imgcopy.get_image_height(), VCL::Exception); + ASSERT_THROW(imgcopy.get_image_width(), VCL::Exception); + ASSERT_THROW(imgcopy.get_image_channels(), VCL::Exception); + ASSERT_FALSE(imgcopy.has_data()); } -TEST_F(TDBImageTest, CopyConstructorData) -{ - VCL::TDBImage tdb("tdb/copy_construct.tdb"); +TEST_F(TDBImageTest, CopyConstructorData) { + VCL::TDBImage tdb("tdb/copy_construct.tdb"); - ASSERT_THROW(tdb.get_image_height(), VCL::Exception); - ASSERT_THROW(tdb.get_image_width(), VCL::Exception); - ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); + ASSERT_THROW(tdb.get_image_height(), VCL::Exception); + ASSERT_THROW(tdb.get_image_width(), VCL::Exception); + ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); - EXPECT_EQ("tdb/copy_construct.tdb", tdb.get_object_id()); - tdb.write(cv_img_); + EXPECT_EQ("tdb/copy_construct.tdb", tdb.get_object_id()); + tdb.write(cv_img_); - VCL::TDBImage imgcopy(tdb); + VCL::TDBImage imgcopy(tdb); - EXPECT_EQ(tdb.get_image_size(), imgcopy.get_image_size()); - ASSERT_TRUE(imgcopy.has_data()); + EXPECT_EQ(tdb.get_image_size(), imgcopy.get_image_size()); + ASSERT_TRUE(imgcopy.has_data()); - long img_size = tdb.get_image_size(); - unsigned char* buffer1 = new unsigned char[img_size]; - unsigned char* buffer2 = new unsigned char[img_size]; + long img_size = tdb.get_image_size(); + unsigned char *buffer1 = new unsigned char[img_size]; + unsigned char *buffer2 = new unsigned char[img_size]; - tdb.get_buffer(buffer1, img_size); - imgcopy.get_buffer(buffer2, img_size); + tdb.get_buffer(buffer1, img_size); + imgcopy.get_buffer(buffer2, img_size); - compare_buffer_buffer(buffer1, buffer2, img_size); - compare_mat_buffer(cv_img_, buffer1); - compare_mat_buffer(cv_img_, buffer2); + compare_buffer_buffer(buffer1, buffer2, img_size); + compare_mat_buffer(cv_img_, buffer1); + compare_mat_buffer(cv_img_, buffer2); - delete [] buffer2; - delete [] buffer1; + delete[] buffer2; + delete[] buffer1; } -TEST_F(TDBImageTest, CopyConstructor) -{ - VCL::TDBImage tdb("tdb/copy_construct.tdb"); +TEST_F(TDBImageTest, CopyConstructor) { + VCL::TDBImage tdb("tdb/copy_construct.tdb"); - EXPECT_EQ("tdb/copy_construct.tdb", tdb.get_object_id()); - ASSERT_FALSE(tdb.has_data()); + EXPECT_EQ("tdb/copy_construct.tdb", tdb.get_object_id()); + ASSERT_FALSE(tdb.has_data()); - long size = long(cv_img_.rows) * long(cv_img_.cols) * cv_img_.channels(); - unsigned char* buf = new unsigned char[size]; - tdb.get_buffer(buf, size); + long size = long(cv_img_.rows) * long(cv_img_.cols) * cv_img_.channels(); + unsigned char *buf = new unsigned char[size]; + tdb.get_buffer(buf, size); - compare_mat_buffer(cv_img_, buf); + compare_mat_buffer(cv_img_, buf); - VCL::TDBImage imgcopy(tdb); + VCL::TDBImage imgcopy(tdb); - EXPECT_EQ(tdb.get_image_size(), imgcopy.get_image_size()); - ASSERT_TRUE(imgcopy.has_data()); - ASSERT_TRUE(tdb.has_data()); + EXPECT_EQ(tdb.get_image_size(), imgcopy.get_image_size()); + ASSERT_TRUE(imgcopy.has_data()); + ASSERT_TRUE(tdb.has_data()); - tdb.delete_image(); - ASSERT_FALSE(tdb.has_data()); + tdb.delete_image(); + ASSERT_FALSE(tdb.has_data()); - cv::Mat copy = imgcopy.get_cvmat(); - compare_mat_mat(copy, cv_img_); + cv::Mat copy = imgcopy.get_cvmat(); + compare_mat_mat(copy, cv_img_); - imgcopy.write("tdb/copied.tdb"); + imgcopy.write("tdb/copied.tdb"); } -TEST_F(TDBImageTest, OperatorEqualsNoData) -{ - VCL::TDBImage tdb("tdb/operator_equals.tdb"); +TEST_F(TDBImageTest, OperatorEqualsNoData) { + VCL::TDBImage tdb("tdb/operator_equals.tdb"); - ASSERT_THROW(tdb.get_image_height(), VCL::Exception); - ASSERT_THROW(tdb.get_image_width(), VCL::Exception); - ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); + ASSERT_THROW(tdb.get_image_height(), VCL::Exception); + ASSERT_THROW(tdb.get_image_width(), VCL::Exception); + ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); - EXPECT_EQ("tdb/operator_equals.tdb", tdb.get_object_id()); + EXPECT_EQ("tdb/operator_equals.tdb", tdb.get_object_id()); - VCL::TDBImage imgcopy; + VCL::TDBImage imgcopy; - imgcopy = tdb; + imgcopy = tdb; - ASSERT_THROW(imgcopy.get_image_height(), VCL::Exception); - ASSERT_THROW(imgcopy.get_image_width(), VCL::Exception); - ASSERT_THROW(imgcopy.get_image_channels(), VCL::Exception); - ASSERT_FALSE(imgcopy.has_data()); + ASSERT_THROW(imgcopy.get_image_height(), VCL::Exception); + ASSERT_THROW(imgcopy.get_image_width(), VCL::Exception); + ASSERT_THROW(imgcopy.get_image_channels(), VCL::Exception); + ASSERT_FALSE(imgcopy.has_data()); } -TEST_F(TDBImageTest, OperatorEqualsData) -{ - VCL::TDBImage tdb("tdb/operator_equals.tdb"); +TEST_F(TDBImageTest, OperatorEqualsData) { + VCL::TDBImage tdb("tdb/operator_equals.tdb"); - ASSERT_THROW(tdb.get_image_height(), VCL::Exception); - ASSERT_THROW(tdb.get_image_width(), VCL::Exception); - ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); + ASSERT_THROW(tdb.get_image_height(), VCL::Exception); + ASSERT_THROW(tdb.get_image_width(), VCL::Exception); + ASSERT_THROW(tdb.get_image_channels(), VCL::Exception); - EXPECT_EQ("tdb/operator_equals.tdb", tdb.get_object_id()); + EXPECT_EQ("tdb/operator_equals.tdb", tdb.get_object_id()); - tdb.write(cv_img_); + tdb.write(cv_img_); - VCL::TDBImage imgcopy; + VCL::TDBImage imgcopy; - imgcopy = tdb; + imgcopy = tdb; - EXPECT_EQ(tdb.get_image_size(), imgcopy.get_image_size()); - ASSERT_TRUE(imgcopy.has_data()); + EXPECT_EQ(tdb.get_image_size(), imgcopy.get_image_size()); + ASSERT_TRUE(imgcopy.has_data()); - long size = tdb.get_image_size(); - unsigned char* buffer1 = new unsigned char[size]; - unsigned char* buffer2 = new unsigned char[size]; + long size = tdb.get_image_size(); + unsigned char *buffer1 = new unsigned char[size]; + unsigned char *buffer2 = new unsigned char[size]; - tdb.get_buffer(buffer1, size); - imgcopy.get_buffer(buffer2, size); + tdb.get_buffer(buffer1, size); + imgcopy.get_buffer(buffer2, size); - compare_buffer_buffer(buffer1, buffer2, size); + compare_buffer_buffer(buffer1, buffer2, size); - delete [] buffer2; - delete [] buffer1; + delete[] buffer2; + delete[] buffer1; } -TEST_F(TDBImageTest, OperatorEquals) -{ - VCL::TDBImage tdb("tdb/operator_equals.tdb"); - EXPECT_EQ("tdb/operator_equals.tdb", tdb.get_object_id()); +TEST_F(TDBImageTest, OperatorEquals) { + VCL::TDBImage tdb("tdb/operator_equals.tdb"); + EXPECT_EQ("tdb/operator_equals.tdb", tdb.get_object_id()); - EXPECT_EQ(tdb.get_image_height(), cv_img_.rows); + EXPECT_EQ(tdb.get_image_height(), cv_img_.rows); - VCL::TDBImage imgcopy; + VCL::TDBImage imgcopy; - imgcopy = tdb; + imgcopy = tdb; - EXPECT_EQ(tdb.get_image_size(), imgcopy.get_image_size()); - ASSERT_TRUE(imgcopy.has_data()); + EXPECT_EQ(tdb.get_image_size(), imgcopy.get_image_size()); + ASSERT_TRUE(imgcopy.has_data()); - long size = tdb.get_image_size(); - unsigned char* buffer1 = new unsigned char[size]; - unsigned char* buffer2 = new unsigned char[size]; + long size = tdb.get_image_size(); + unsigned char *buffer1 = new unsigned char[size]; + unsigned char *buffer2 = new unsigned char[size]; - tdb.get_buffer(buffer1, size); - imgcopy.get_buffer(buffer2, size); + tdb.get_buffer(buffer1, size); + imgcopy.get_buffer(buffer2, size); - compare_buffer_buffer(buffer1, buffer2, size); + compare_buffer_buffer(buffer1, buffer2, size); - delete [] buffer1; - delete [] buffer2; + delete[] buffer1; + delete[] buffer2; } -TEST_F(TDBImageTest, GetImageSize) -{ - VCL::TDBImage tdb(tdb_img_); - tdb.write(cv_img_); +TEST_F(TDBImageTest, GetImageSize) { + VCL::TDBImage tdb(tdb_img_); + tdb.write(cv_img_); - long h = tdb.get_image_height(); - long w = tdb.get_image_width(); - long c = tdb.get_image_channels(); + long h = tdb.get_image_height(); + long w = tdb.get_image_width(); + long c = tdb.get_image_channels(); - EXPECT_EQ(h*w*c, tdb.get_image_size()); + EXPECT_EQ(h * w * c, tdb.get_image_size()); } -TEST_F(TDBImageTest, GetCVMat) -{ - VCL::TDBImage tdb(tdb_img_); +TEST_F(TDBImageTest, GetCVMat) { + VCL::TDBImage tdb(tdb_img_); - cv::Mat cv_img = tdb.get_cvmat(); - compare_mat_mat(cv_img, cv_img_); + cv::Mat cv_img = tdb.get_cvmat(); + compare_mat_mat(cv_img, cv_img_); } -TEST_F(TDBImageTest, GetBuffer) -{ - VCL::TDBImage tdb(tdb_img_); +TEST_F(TDBImageTest, GetBuffer) { + VCL::TDBImage tdb(tdb_img_); - long size = tdb.get_image_size(); + long size = tdb.get_image_size(); - unsigned char* buf = new unsigned char[size]; + unsigned char *buf = new unsigned char[size]; - tdb.get_buffer(buf, size); + tdb.get_buffer(buf, size); - compare_mat_buffer(cv_img_, buf); + compare_mat_buffer(cv_img_, buf); - delete [] buf; + delete[] buf; } -TEST_F(TDBImageTest, SetProperties) -{ - VCL::TDBImage tdb("tdb/no_metadata.tdb"); - tdb.write(cv_img_, false); +TEST_F(TDBImageTest, SetProperties) { + VCL::TDBImage tdb("tdb/no_metadata.tdb"); + tdb.write(cv_img_, false); - tdb.set_image_properties(cv_img_.rows, cv_img_.cols, cv_img_.channels()); + tdb.set_image_properties(cv_img_.rows, cv_img_.cols, cv_img_.channels()); - EXPECT_EQ(cv_img_.rows*cv_img_.cols*cv_img_.channels(), tdb.get_image_size()); + EXPECT_EQ(cv_img_.rows * cv_img_.cols * cv_img_.channels(), + tdb.get_image_size()); } -TEST_F(TDBImageTest, WriteCVMat) -{ - VCL::TDBImage tdb(tdb_img_); +TEST_F(TDBImageTest, WriteCVMat) { + VCL::TDBImage tdb(tdb_img_); - tdb.write(cv_img_); + tdb.write(cv_img_); - EXPECT_EQ(cv_img_.rows, tdb.get_image_height()); - EXPECT_EQ(cv_img_.cols, tdb.get_image_width()); + EXPECT_EQ(cv_img_.rows, tdb.get_image_height()); + EXPECT_EQ(cv_img_.cols, tdb.get_image_width()); } -TEST_F(TDBImageTest, WriteCVMatNoMetadata) -{ - VCL::TDBImage tdb("tdb/no_metadata.tdb"); +TEST_F(TDBImageTest, WriteCVMatNoMetadata) { + VCL::TDBImage tdb("tdb/no_metadata.tdb"); - tdb.write(cv_img_, false); + tdb.write(cv_img_, false); - tdb.set_image_properties(cv_img_.rows, cv_img_.cols, cv_img_.channels()); + tdb.set_image_properties(cv_img_.rows, cv_img_.cols, cv_img_.channels()); - EXPECT_EQ(cv_img_.rows, tdb.get_image_height()); - EXPECT_EQ(cv_img_.cols, tdb.get_image_width()); + EXPECT_EQ(cv_img_.rows, tdb.get_image_height()); + EXPECT_EQ(cv_img_.cols, tdb.get_image_width()); } -TEST_F(TDBImageTest, WriteString) -{ - VCL::TDBImage tdb(tdb_img_); +TEST_F(TDBImageTest, WriteString) { + VCL::TDBImage tdb(tdb_img_); - ASSERT_THROW(tdb.write(tdb_test_), VCL::Exception); + ASSERT_THROW(tdb.write(tdb_test_), VCL::Exception); - tdb.read(); + tdb.read(); - tdb.write(tdb_test_); + tdb.write(tdb_test_); - EXPECT_EQ(cv_img_.rows, tdb.get_image_height()); - EXPECT_EQ(cv_img_.cols, tdb.get_image_width()); + EXPECT_EQ(cv_img_.rows, tdb.get_image_height()); + EXPECT_EQ(cv_img_.cols, tdb.get_image_width()); } -TEST_F(TDBImageTest, Read) -{ - VCL::TDBImage tdb(tdb_img_); +TEST_F(TDBImageTest, Read) { + VCL::TDBImage tdb(tdb_img_); - tdb.read(); + tdb.read(); - EXPECT_EQ(cv_img_.rows, tdb.get_image_height()); - EXPECT_EQ(cv_img_.cols, tdb.get_image_width()); + EXPECT_EQ(cv_img_.rows, tdb.get_image_height()); + EXPECT_EQ(cv_img_.cols, tdb.get_image_width()); } -TEST_F(TDBImageTest, ReadRectangle) -{ - VCL::TDBImage tdb(tdb_test_); +TEST_F(TDBImageTest, ReadRectangle) { + VCL::TDBImage tdb(tdb_test_); - tdb.read(rect_); + tdb.read(rect_); - EXPECT_EQ(100, tdb.get_image_height()); - EXPECT_EQ(100, tdb.get_image_width()); + EXPECT_EQ(100, tdb.get_image_height()); + EXPECT_EQ(100, tdb.get_image_width()); } -TEST_F(TDBImageTest, Resize) -{ - VCL::TDBImage tdb(tdb_img_); +TEST_F(TDBImageTest, Resize) { + VCL::TDBImage tdb(tdb_img_); - tdb.resize(rect_); + tdb.resize(rect_); - cv::Mat cv_small = tdb.get_cvmat(); + cv::Mat cv_small = tdb.get_cvmat(); - EXPECT_EQ(100, tdb.get_image_height()); - EXPECT_EQ(100, tdb.get_image_width()); + EXPECT_EQ(100, tdb.get_image_height()); + EXPECT_EQ(100, tdb.get_image_width()); } -TEST_F(TDBImageTest, Threshold) -{ - VCL::TDBImage tdb(tdb_img_); +TEST_F(TDBImageTest, Threshold) { + VCL::TDBImage tdb(tdb_img_); - tdb.read(); + tdb.read(); - tdb.threshold(200); + tdb.threshold(200); - cv::Mat cv_bright = tdb.get_cvmat(); + cv::Mat cv_bright = tdb.get_cvmat(); - cv::threshold(cv_img_, cv_img_, 200, 200, cv::THRESH_TOZERO); + cv::threshold(cv_img_, cv_img_, 200, 200, cv::THRESH_TOZERO); - compare_mat_mat(cv_bright, cv_img_); + compare_mat_mat(cv_bright, cv_img_); } -TEST_F(TDBImageTest, DeleteImage) -{ - VCL::TDBImage tdb("tdb/operator_equals.tdb"); +TEST_F(TDBImageTest, DeleteImage) { + VCL::TDBImage tdb("tdb/operator_equals.tdb"); - tdb.delete_image(); + tdb.delete_image(); - ASSERT_FALSE(tdb.has_data()); - ASSERT_THROW(tdb.get_image_size(), VCL::Exception); + ASSERT_FALSE(tdb.has_data()); + ASSERT_THROW(tdb.get_image_size(), VCL::Exception); } -TEST_F(TDBImageTest, DeleteImageAfterRead) -{ - VCL::TDBImage tdb("tdb/copied.tdb"); +TEST_F(TDBImageTest, DeleteImageAfterRead) { + VCL::TDBImage tdb("tdb/copied.tdb"); - tdb.read(); - ASSERT_TRUE(tdb.has_data()); - tdb.delete_image(); + tdb.read(); + ASSERT_TRUE(tdb.has_data()); + tdb.delete_image(); - ASSERT_FALSE(tdb.has_data()); + ASSERT_FALSE(tdb.has_data()); } -TEST_F(TDBImageTest, SetMinimum) -{ - VCL::TDBImage tdb; - tdb.set_minimum(3); +TEST_F(TDBImageTest, SetMinimum) { + VCL::TDBImage tdb; + tdb.set_minimum(3); } diff --git a/tests/unit_tests/Video_test.cc b/tests/unit_tests/Video_test.cc index 52af15d2..05fe9ad5 100644 --- a/tests/unit_tests/Video_test.cc +++ b/tests/unit_tests/Video_test.cc @@ -31,18 +31,18 @@ #include "gtest/gtest.h" #include +#include +#include #include #include #include -#include -#include -#include -#include #include +#include +#include -#include /* srand, rand */ -#include /* time */ +#include /* srand, rand */ +#include /* time */ #include "helpers.h" @@ -51,155 +51,244 @@ using namespace std; class VideoTest : public ::testing::Test { protected: + std::string _video_path_avi_xvid; + std::string _video_path_mp4_h264; + std::vector _frames_xvid; + std::vector _frames_h264; - std::string _video_path_avi_xvid; - std::string _video_path_mp4_h264; - std::vector _frames_xvid; - std::vector _frames_h264; + virtual void SetUp() { + _video_path_avi_xvid = "videos/Megamind.avi"; + _video_path_mp4_h264 = "videos/Megamind.mp4"; - virtual void SetUp() { - _video_path_avi_xvid = "videos/Megamind.avi"; - _video_path_mp4_h264 = "videos/Megamind.mp4"; + cv::VideoCapture testVideo_xvid(_video_path_avi_xvid); - cv::VideoCapture testVideo_xvid(_video_path_avi_xvid); + // Read the video once for speed + while (true) { + cv::Mat frame; + testVideo_xvid >> frame; - // Read the video once for speed - while (true) { - cv::Mat frame; - testVideo_xvid >> frame; + if (frame.empty()) + break; - if (frame.empty()) - break; - - _frames_xvid.push_back(frame); - } + _frames_xvid.push_back(frame); + } - cv::VideoCapture testVideo_h264(_video_path_mp4_h264); + cv::VideoCapture testVideo_h264(_video_path_mp4_h264); - // Read the video once for speed - while (true) { - cv::Mat frame; - testVideo_h264 >> frame; + // Read the video once for speed + while (true) { + cv::Mat frame; + testVideo_h264 >> frame; - if (frame.empty()) - break; + if (frame.empty()) + break; - _frames_h264.push_back(frame); - } + _frames_h264.push_back(frame); } + } - int get_fourcc() { - return cv::VideoWriter::fourcc('H', '2', '6', '4'); - } + int get_fourcc() { return cv::VideoWriter::fourcc('H', '2', '6', '4'); } }; namespace VCL { - class VideoTest : public Video { +class VideoTest : public Video { - public: - VideoTest() : Video() {} - VideoTest(std::string a) : Video(a) {} +public: + VideoTest() : Video() {} + VideoTest(std::string a) : Video(a) {} - using Video::perform_operations; - }; + using Video::perform_operations; }; +}; // namespace VCL -TEST_F(VideoTest, DefaultConstructor) -{ - VCL::Video video_data; - ASSERT_THROW(video_data.get_frame_count(), VCL::Exception); +TEST_F(VideoTest, DefaultConstructor) { + VCL::Video video_data; + ASSERT_THROW(video_data.get_frame_count(), VCL::Exception); } -TEST_F(VideoTest, StringConstructor) -{ - VCL::Video video_data(_video_path_avi_xvid); - long input_frame_count = video_data.get_frame_count(); +TEST_F(VideoTest, StringConstructor) { + VCL::Video video_data(_video_path_avi_xvid); + long input_frame_count = video_data.get_frame_count(); - cv::VideoCapture testVideo(_video_path_avi_xvid); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - ASSERT_EQ(input_frame_count, test_frame_count); + cv::VideoCapture testVideo(_video_path_avi_xvid); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + ASSERT_EQ(input_frame_count, test_frame_count); } -TEST_F(VideoTest, StringConstructorNoFormat) -{ - VCL::Video video_data("videos/megamind"); - long input_frame_count = video_data.get_frame_count(); +TEST_F(VideoTest, StringConstructorNoFormat) { + VCL::Video video_data("videos/megamind"); + long input_frame_count = video_data.get_frame_count(); - cv::VideoCapture testVideo(_video_path_mp4_h264); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - ASSERT_EQ(input_frame_count, test_frame_count); + cv::VideoCapture testVideo(_video_path_mp4_h264); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + ASSERT_EQ(input_frame_count, test_frame_count); } -TEST_F(VideoTest, StringConstructorNoExists) -{ - VCL::Video video_data("this/path/does/not/exist.wrongformat"); - ASSERT_THROW(video_data.get_frame_count(), VCL::Exception); +TEST_F(VideoTest, StringConstructorNoExists) { + VCL::Video video_data("this/path/does/not/exist.wrongformat"); + ASSERT_THROW(video_data.get_frame_count(), VCL::Exception); +} + +TEST_F(VideoTest, CopyConstructor) { + VCL::Video testVideo4copy(_video_path_avi_xvid); + + VCL::Video video_data(testVideo4copy); + long input_frame_count = video_data.get_frame_count(); + + cv::VideoCapture testVideo(_video_path_avi_xvid); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + + ASSERT_EQ(input_frame_count, test_frame_count); + + for (int i = 0; i < input_frame_count; ++i) { + cv::Mat input_frame = video_data.get_frame(i); + compare_mat_mat(input_frame, _frames_xvid.at(i)); + } } +TEST_F(VideoTest, BlobConstructor) { + std::ifstream ifile; + ifile.open(_video_path_avi_xvid); + + int fsize; + char *inBuf; + ifile.seekg(0, std::ios::end); + fsize = (long)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + ifile.close(); + + std::string vcl_from_buffer("videos_tests/from_buffer.avi"); + { + VCL::Video video_data(inBuf, fsize); + video_data.store(vcl_from_buffer, VCL::Video::Codec::XVID); + } + + delete[] inBuf; + + // OpenCV writing the video H264 + // We need to write again to make sure we use the same parameters + // when writting the video. + std::string write_output_ocv("videos_tests/write_test_ocv.avi"); + { + cv::VideoCapture testWriteVideo(_video_path_avi_xvid); + + cv::VideoWriter testResultVideo( + write_output_ocv, cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), + testWriteVideo.get(cv::CAP_PROP_FPS), + cv::Size(testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), + testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT))); + + for (auto &frame : _frames_xvid) { + testResultVideo << frame; + } + } + + VCL::Video video_data(vcl_from_buffer); + long input_frame_count = video_data.get_frame_count(); + + cv::VideoCapture testVideo(write_output_ocv); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); -TEST_F(VideoTest, CopyConstructor) -{ - VCL::Video testVideo4copy(_video_path_avi_xvid); + ASSERT_EQ(input_frame_count, test_frame_count); + + for (int i = 0; i < input_frame_count; ++i) { + cv::Mat input_frame = video_data.get_frame(i); + cv::Mat test_frame; + testVideo >> test_frame; + + if (test_frame.empty()) + break; // should not happen + + compare_mat_mat(input_frame, test_frame); + } +} + +TEST_F(VideoTest, CreateUnique) { + try { + VCL::Video video_data(_video_path_mp4_h264); + std::string uname = VCL::create_unique("videos_tests/", "mp4"); + video_data.store(uname, VCL::Video::Codec::H264); + + VCL::Video video_read(uname); + + ASSERT_GE(video_data.get_frame_count(), 1); + ASSERT_EQ(video_data.get_frame_count(), video_read.get_frame_count()); + + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } +} - VCL::Video video_data(testVideo4copy); +TEST_F(VideoTest, ReadAVI_XVID) { + try { + VCL::Video video_data(_video_path_avi_xvid); long input_frame_count = video_data.get_frame_count(); cv::VideoCapture testVideo(_video_path_avi_xvid); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); ASSERT_EQ(input_frame_count, test_frame_count); for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - compare_mat_mat(input_frame, _frames_xvid.at(i)); + cv::Mat input_frame = video_data.get_frame(i); + compare_mat_mat(input_frame, _frames_xvid.at(i)); } + + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, BlobConstructor) -{ - std::ifstream ifile; - ifile.open(_video_path_avi_xvid); - - int fsize; - char* inBuf; - ifile.seekg(0, std::ios::end); - fsize = (long)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - ifile.close(); - - std::string vcl_from_buffer("videos_tests/from_buffer.avi"); - { - VCL::Video video_data(inBuf, fsize); - video_data.store(vcl_from_buffer, VCL::Video::Codec::XVID); +TEST_F(VideoTest, ReadMP4_H264) { + try { + VCL::Video video_data(_video_path_mp4_h264); + long input_frame_count = video_data.get_frame_count(); + + cv::VideoCapture testVideo(_video_path_mp4_h264); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + + ASSERT_EQ(input_frame_count, test_frame_count); + + for (int i = 0; i < input_frame_count; ++i) { + cv::Mat input_frame = video_data.get_frame(i); + compare_mat_mat(input_frame, _frames_h264.at(i)); } - delete[] inBuf; + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } +} + +TEST_F(VideoTest, WriteMP4_H264) { + try { + std::string write_output_vcl("videos_tests/write_test_vcl.mp4"); + { + VCL::Video video_data(_video_path_avi_xvid); + video_data.store(write_output_vcl, VCL::Video::Codec::H264); + } // OpenCV writing the video H264 - // We need to write again to make sure we use the same parameters - // when writting the video. - std::string write_output_ocv("videos_tests/write_test_ocv.avi"); + std::string write_output_ocv("videos_tests/write_test_ocv.mp4"); { - cv::VideoCapture testWriteVideo(_video_path_avi_xvid); - - cv::VideoWriter testResultVideo( - write_output_ocv, - cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), - testWriteVideo.get(cv::CAP_PROP_FPS), - cv::Size( - testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), - testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT)) - ); - - for (auto& frame : _frames_xvid) { - testResultVideo << frame; - } + cv::VideoCapture testWriteVideo(_video_path_avi_xvid); + + cv::VideoWriter testResultVideo( + write_output_ocv, get_fourcc(), testWriteVideo.get(cv::CAP_PROP_FPS), + cv::Size(testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), + testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT))); + + for (auto &frame : _frames_xvid) { + testResultVideo << frame; + } } - VCL::Video video_data(vcl_from_buffer); + VCL::Video video_data(write_output_vcl); long input_frame_count = video_data.get_frame_count(); cv::VideoCapture testVideo(write_output_ocv); @@ -208,607 +297,470 @@ TEST_F(VideoTest, BlobConstructor) ASSERT_EQ(input_frame_count, test_frame_count); for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - cv::Mat test_frame; - testVideo >> test_frame; + cv::Mat input_frame = video_data.get_frame(i); + cv::Mat test_frame; + testVideo >> test_frame; - if (test_frame.empty()) - break; // should not happen + if (test_frame.empty()) + break; // should not happen - compare_mat_mat(input_frame, test_frame); + compare_mat_mat(input_frame, test_frame); } -} - -TEST_F(VideoTest, CreateUnique) -{ - try { - VCL::Video video_data(_video_path_mp4_h264); - std::string uname = VCL::create_unique("videos_tests/", "mp4"); - video_data.store(uname, VCL::Video::Codec::H264); - - VCL::Video video_read(uname); - ASSERT_GE(video_data.get_frame_count(), 1); - ASSERT_EQ(video_data.get_frame_count(), video_read.get_frame_count()); - - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); - } + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, ReadAVI_XVID) -{ - try { - VCL::Video video_data(_video_path_avi_xvid); - long input_frame_count = video_data.get_frame_count(); - - cv::VideoCapture testVideo(_video_path_avi_xvid); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); +TEST_F(VideoTest, WriteAVI_XVID) { + try { + std::string write_output_vcl("videos_tests/write_test_vcl.avi"); + { + VCL::Video video_data(_video_path_avi_xvid); + video_data.store(write_output_vcl, VCL::Video::Codec::XVID); + } - ASSERT_EQ(input_frame_count, test_frame_count); + // OpenCV writing the video H264 + std::string write_output_ocv("videos_tests/write_test_ocv.avi"); + { + cv::VideoCapture testWriteVideo(_video_path_avi_xvid); - for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - compare_mat_mat(input_frame, _frames_xvid.at(i)); - } + cv::VideoWriter testResultVideo( + write_output_ocv, cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), + testWriteVideo.get(cv::CAP_PROP_FPS), + cv::Size(testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), + testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT))); - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); + for (auto &frame : _frames_xvid) { + testResultVideo << frame; + } } -} -TEST_F(VideoTest, ReadMP4_H264) -{ - try { - VCL::Video video_data(_video_path_mp4_h264); - long input_frame_count = video_data.get_frame_count(); + VCL::Video video_data(write_output_vcl); + long input_frame_count = video_data.get_frame_count(); - cv::VideoCapture testVideo(_video_path_mp4_h264); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + cv::VideoCapture testVideo(write_output_ocv); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - ASSERT_EQ(input_frame_count, test_frame_count); + ASSERT_EQ(input_frame_count, test_frame_count); - for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - compare_mat_mat(input_frame, _frames_h264.at(i)); - } + for (int i = 0; i < input_frame_count; ++i) { + cv::Mat input_frame = video_data.get_frame(i); + cv::Mat test_frame; + testVideo >> test_frame; - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); - } -} + if (test_frame.empty()) + break; // should not happen -TEST_F(VideoTest, WriteMP4_H264) -{ - try { - std::string write_output_vcl("videos_tests/write_test_vcl.mp4"); - { - VCL::Video video_data(_video_path_avi_xvid); - video_data.store(write_output_vcl, VCL::Video::Codec::H264); - } - - // OpenCV writing the video H264 - std::string write_output_ocv("videos_tests/write_test_ocv.mp4"); - { - cv::VideoCapture testWriteVideo(_video_path_avi_xvid); - - cv::VideoWriter testResultVideo( - write_output_ocv, - get_fourcc(), - testWriteVideo.get(cv::CAP_PROP_FPS), - cv::Size( - testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), - testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT)) - ); - - for (auto& frame : _frames_xvid) { - testResultVideo << frame; - } - } - - VCL::Video video_data(write_output_vcl); - long input_frame_count = video_data.get_frame_count(); - - cv::VideoCapture testVideo(write_output_ocv); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - - ASSERT_EQ(input_frame_count, test_frame_count); - - for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - cv::Mat test_frame; - testVideo >> test_frame; - - if (test_frame.empty()) - break; // should not happen - - compare_mat_mat(input_frame, test_frame); - } - - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); + compare_mat_mat(input_frame, test_frame); } -} -TEST_F(VideoTest, WriteAVI_XVID) -{ - try { - std::string write_output_vcl("videos_tests/write_test_vcl.avi"); - { - VCL::Video video_data(_video_path_avi_xvid); - video_data.store(write_output_vcl, VCL::Video::Codec::XVID); - } - - // OpenCV writing the video H264 - std::string write_output_ocv("videos_tests/write_test_ocv.avi"); - { - cv::VideoCapture testWriteVideo(_video_path_avi_xvid); - - cv::VideoWriter testResultVideo( - write_output_ocv, - cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), - testWriteVideo.get(cv::CAP_PROP_FPS), - cv::Size( - testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), - testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT)) - ); - - for (auto& frame : _frames_xvid) { - testResultVideo << frame; - } - } - - VCL::Video video_data(write_output_vcl); - long input_frame_count = video_data.get_frame_count(); - - cv::VideoCapture testVideo(write_output_ocv); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - - ASSERT_EQ(input_frame_count, test_frame_count); - - for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - cv::Mat test_frame; - testVideo >> test_frame; - - if (test_frame.empty()) - break; // should not happen - - compare_mat_mat(input_frame, test_frame); - } - - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); - } + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, ResizeWrite) -{ - int new_w = 160; - int new_h = 90; - - try { +TEST_F(VideoTest, ResizeWrite) { + int new_w = 160; + int new_h = 90; - std::string resize_name_vcl("videos_tests/resize_vcl.mp4"); - { - VCL::Video video_data(_video_path_avi_xvid); // - video_data.resize(new_w, new_h); - video_data.store(resize_name_vcl, VCL::Video::Codec::H264); - } + try { - // OpenCV writing the video H264 - std::string resize_name_ocv("videos_tests/resize_ocv.mp4"); - { - cv::VideoCapture testWriteVideo(_video_path_avi_xvid); + std::string resize_name_vcl("videos_tests/resize_vcl.mp4"); + { + VCL::Video video_data(_video_path_avi_xvid); // + video_data.resize(new_w, new_h); + video_data.store(resize_name_vcl, VCL::Video::Codec::H264); + } - cv::VideoWriter testResultVideo( - resize_name_ocv, - get_fourcc(), - testWriteVideo.get(cv::CAP_PROP_FPS), - cv::Size(new_w, new_h) - ); + // OpenCV writing the video H264 + std::string resize_name_ocv("videos_tests/resize_ocv.mp4"); + { + cv::VideoCapture testWriteVideo(_video_path_avi_xvid); - for (auto& ff : _frames_xvid) { - cv::Mat cv_resized; - cv::resize(ff, cv_resized, cv::Size(new_w, new_h)); - testResultVideo << cv_resized; - } + cv::VideoWriter testResultVideo(resize_name_ocv, get_fourcc(), + testWriteVideo.get(cv::CAP_PROP_FPS), + cv::Size(new_w, new_h)); - testWriteVideo.release(); - } + for (auto &ff : _frames_xvid) { + cv::Mat cv_resized; + cv::resize(ff, cv_resized, cv::Size(new_w, new_h)); + testResultVideo << cv_resized; + } - VCL::Video video_data(resize_name_vcl); - long input_frame_count = video_data.get_frame_count(); + testWriteVideo.release(); + } - cv::VideoCapture testVideo(resize_name_ocv); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + VCL::Video video_data(resize_name_vcl); + long input_frame_count = video_data.get_frame_count(); - ASSERT_EQ(input_frame_count, test_frame_count); + cv::VideoCapture testVideo(resize_name_ocv); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - cv::Mat test_frame; - testVideo >> test_frame; + ASSERT_EQ(input_frame_count, test_frame_count); - if (test_frame.empty()) - break; // should not happen + for (int i = 0; i < input_frame_count; ++i) { + cv::Mat input_frame = video_data.get_frame(i); + cv::Mat test_frame; + testVideo >> test_frame; - compare_mat_mat(input_frame, test_frame); - } + if (test_frame.empty()) + break; // should not happen - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); + compare_mat_mat(input_frame, test_frame); } -} -TEST_F(VideoTest, IntervalWrite) -{ - int init = 10; - int end = 100; - int step = 5; + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } +} - try { +TEST_F(VideoTest, IntervalWrite) { + int init = 10; + int end = 100; + int step = 5; - std::string interval_name_vcl("videos_tests/interval_vcl.mp4"); - { - VCL::Video video_data(_video_path_avi_xvid); // - video_data.interval(VCL::Video::FRAMES, init, end, step); - video_data.store(interval_name_vcl, VCL::Video::Codec::H264); - } + try { - // OpenCV writing the video H264 - std::string interval_name_ocv("videos_tests/interval_ocv.mp4"); - { - cv::VideoCapture testWriteVideo(_video_path_avi_xvid); + std::string interval_name_vcl("videos_tests/interval_vcl.mp4"); + { + VCL::Video video_data(_video_path_avi_xvid); // + video_data.interval(VCL::Video::FRAMES, init, end, step); + video_data.store(interval_name_vcl, VCL::Video::Codec::H264); + } - cv::VideoWriter testResultVideo( - interval_name_ocv, - get_fourcc(), - testWriteVideo.get(cv::CAP_PROP_FPS) / step, - cv::Size( - testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), - testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT)) - ); + // OpenCV writing the video H264 + std::string interval_name_ocv("videos_tests/interval_ocv.mp4"); + { + cv::VideoCapture testWriteVideo(_video_path_avi_xvid); - if (end >= _frames_xvid.size()) - ASSERT_TRUE(false); + cv::VideoWriter testResultVideo( + interval_name_ocv, get_fourcc(), + testWriteVideo.get(cv::CAP_PROP_FPS) / step, + cv::Size(testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), + testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT))); - for (int i = init; i < end; i += step) { - testResultVideo << _frames_xvid.at(i); - } + if (end >= _frames_xvid.size()) + ASSERT_TRUE(false); - testWriteVideo.release(); - } + for (int i = init; i < end; i += step) { + testResultVideo << _frames_xvid.at(i); + } - VCL::Video video_data(interval_name_vcl); - long input_frame_count = video_data.get_frame_count(); + testWriteVideo.release(); + } - cv::VideoCapture testVideo(interval_name_ocv); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + VCL::Video video_data(interval_name_vcl); + long input_frame_count = video_data.get_frame_count(); - ASSERT_EQ(input_frame_count, test_frame_count); + cv::VideoCapture testVideo(interval_name_ocv); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - cv::Mat test_frame; - testVideo >> test_frame; + ASSERT_EQ(input_frame_count, test_frame_count); - if (test_frame.empty()) - break; // should not happen + for (int i = 0; i < input_frame_count; ++i) { + cv::Mat input_frame = video_data.get_frame(i); + cv::Mat test_frame; + testVideo >> test_frame; - compare_mat_mat(input_frame, test_frame); - } + if (test_frame.empty()) + break; // should not happen - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); + compare_mat_mat(input_frame, test_frame); } + + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, IntervalOutOfBounds) -{ - // Video has 270 frames, we test out of bounds here. - - int init = 10; - int end = 270; // This should cause error - int step = 5; - try { - VCL::Video video_data(_video_path_avi_xvid); // - video_data.interval(VCL::Video::FRAMES, init, end, step); - // It will only throw when the operations are performed - ASSERT_THROW(video_data.get_frame_count(), VCL::Exception); - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); - } +TEST_F(VideoTest, IntervalOutOfBounds) { + // Video has 270 frames, we test out of bounds here. - init = 270; - end = 250; - try { - VCL::Video video_data(_video_path_avi_xvid); // - video_data.interval(VCL::Video::FRAMES, init, end, step); - // It will only throw when the operations are performed - ASSERT_THROW(video_data.get_frame_count(), VCL::Exception); - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); - } + int init = 10; + int end = 270; // This should cause error + int step = 5; + try { + VCL::Video video_data(_video_path_avi_xvid); // + video_data.interval(VCL::Video::FRAMES, init, end, step); + // It will only throw when the operations are performed + ASSERT_THROW(video_data.get_frame_count(), VCL::Exception); + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } + + init = 270; + end = 250; + try { + VCL::Video video_data(_video_path_avi_xvid); // + video_data.interval(VCL::Video::FRAMES, init, end, step); + // It will only throw when the operations are performed + ASSERT_THROW(video_data.get_frame_count(), VCL::Exception); + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, ThresholdWrite) -{ - int ths = 100; +TEST_F(VideoTest, ThresholdWrite) { + int ths = 100; - try { + try { - std::string threshold_name_vcl("videos_tests/threshold_vcl.mp4"); - { - VCL::Video video_data(_video_path_avi_xvid); // - video_data.threshold(ths); - video_data.store(threshold_name_vcl, VCL::Video::Codec::H264); - } - - // OpenCV writing the video H264 - std::string threshold_name_ocv("videos_tests/threshold_ocv.mp4"); - { - cv::VideoCapture testWriteVideo(_video_path_avi_xvid); + std::string threshold_name_vcl("videos_tests/threshold_vcl.mp4"); + { + VCL::Video video_data(_video_path_avi_xvid); // + video_data.threshold(ths); + video_data.store(threshold_name_vcl, VCL::Video::Codec::H264); + } - cv::VideoWriter testResultVideo( - threshold_name_ocv, - get_fourcc(), - testWriteVideo.get(cv::CAP_PROP_FPS), - cv::Size( - testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), - testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT)) - ); + // OpenCV writing the video H264 + std::string threshold_name_ocv("videos_tests/threshold_ocv.mp4"); + { + cv::VideoCapture testWriteVideo(_video_path_avi_xvid); - for (auto& ff : _frames_xvid) { - cv::Mat cv_ths; - cv::threshold(ff, cv_ths, ths, ths, cv::THRESH_TOZERO); - testResultVideo << cv_ths; - } + cv::VideoWriter testResultVideo( + threshold_name_ocv, get_fourcc(), + testWriteVideo.get(cv::CAP_PROP_FPS), + cv::Size(testWriteVideo.get(cv::CAP_PROP_FRAME_WIDTH), + testWriteVideo.get(cv::CAP_PROP_FRAME_HEIGHT))); - testWriteVideo.release(); - } + for (auto &ff : _frames_xvid) { + cv::Mat cv_ths; + cv::threshold(ff, cv_ths, ths, ths, cv::THRESH_TOZERO); + testResultVideo << cv_ths; + } - VCL::Video video_data(threshold_name_vcl); - long input_frame_count = video_data.get_frame_count(); + testWriteVideo.release(); + } - cv::VideoCapture testVideo(threshold_name_ocv); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + VCL::Video video_data(threshold_name_vcl); + long input_frame_count = video_data.get_frame_count(); - ASSERT_EQ(input_frame_count, test_frame_count); + cv::VideoCapture testVideo(threshold_name_ocv); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - cv::Mat test_frame; - testVideo >> test_frame; + ASSERT_EQ(input_frame_count, test_frame_count); - if (test_frame.empty()) - break; // should not happen + for (int i = 0; i < input_frame_count; ++i) { + cv::Mat input_frame = video_data.get_frame(i); + cv::Mat test_frame; + testVideo >> test_frame; - compare_mat_mat(input_frame, test_frame); - } + if (test_frame.empty()) + break; // should not happen - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); + compare_mat_mat(input_frame, test_frame); } -} -TEST_F(VideoTest, CropWrite) -{ - int new_w = 160; - int new_h = 90; + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } +} - cv::Rect ocv_rect(100, 100, new_w, new_h); - VCL::Rectangle rect(100, 100, new_w, new_h); +TEST_F(VideoTest, CropWrite) { + int new_w = 160; + int new_h = 90; - try { + cv::Rect ocv_rect(100, 100, new_w, new_h); + VCL::Rectangle rect(100, 100, new_w, new_h); - std::string crop_name_vcl("videos_tests/crop_vcl.mp4"); - { - VCL::Video video_data(_video_path_avi_xvid); // - video_data.crop(rect); - video_data.store(crop_name_vcl, VCL::Video::Codec::H264); - } + try { - // OpenCV writing the video H264 - std::string crop_name_ocv("videos_tests/crop_ocv.mp4"); - { - cv::VideoCapture testWriteVideo(_video_path_avi_xvid); + std::string crop_name_vcl("videos_tests/crop_vcl.mp4"); + { + VCL::Video video_data(_video_path_avi_xvid); // + video_data.crop(rect); + video_data.store(crop_name_vcl, VCL::Video::Codec::H264); + } - cv::VideoWriter testResultVideo( - crop_name_ocv, - get_fourcc(), - testWriteVideo.get(cv::CAP_PROP_FPS), - cv::Size(new_w, new_h) - ); + // OpenCV writing the video H264 + std::string crop_name_ocv("videos_tests/crop_ocv.mp4"); + { + cv::VideoCapture testWriteVideo(_video_path_avi_xvid); - for (auto& ff : _frames_xvid) { - cv::Mat roi_frame(ff, ocv_rect); - testResultVideo << roi_frame; - } + cv::VideoWriter testResultVideo(crop_name_ocv, get_fourcc(), + testWriteVideo.get(cv::CAP_PROP_FPS), + cv::Size(new_w, new_h)); - testWriteVideo.release(); - } + for (auto &ff : _frames_xvid) { + cv::Mat roi_frame(ff, ocv_rect); + testResultVideo << roi_frame; + } - VCL::Video video_data(crop_name_vcl); - long input_frame_count = video_data.get_frame_count(); + testWriteVideo.release(); + } - cv::VideoCapture testVideo(crop_name_ocv); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + VCL::Video video_data(crop_name_vcl); + long input_frame_count = video_data.get_frame_count(); - ASSERT_EQ(input_frame_count, test_frame_count); + cv::VideoCapture testVideo(crop_name_ocv); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - for (int i = 0; i < input_frame_count; ++i) { - cv::Mat input_frame = video_data.get_frame(i); - cv::Mat test_frame; - testVideo >> test_frame; + ASSERT_EQ(input_frame_count, test_frame_count); - if (test_frame.empty()) - break; // should not happen + for (int i = 0; i < input_frame_count; ++i) { + cv::Mat input_frame = video_data.get_frame(i); + cv::Mat test_frame; + testVideo >> test_frame; - compare_mat_mat(input_frame, test_frame); - } + if (test_frame.empty()) + break; // should not happen - } catch(VCL::Exception &e) { - print_exception(e); - ASSERT_TRUE(false); + compare_mat_mat(input_frame, test_frame); } + + } catch (VCL::Exception &e) { + print_exception(e); + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, KeyFrameExtractionSuccess) -{ - try { - VCL::VideoTest video_data(_video_path_mp4_h264); +TEST_F(VideoTest, KeyFrameExtractionSuccess) { + try { + VCL::VideoTest video_data(_video_path_mp4_h264); - auto key_frame_list = video_data.get_key_frame_list(); + auto key_frame_list = video_data.get_key_frame_list(); - // We know that this video contains exactly four I-frames. - // Changing the video will fail this test. If the functionality - // is to be tested with other videos, either create a seperate test - // or update the assertion below accordingly. - ASSERT_TRUE(key_frame_list.size() == 4); + // We know that this video contains exactly four I-frames. + // Changing the video will fail this test. If the functionality + // is to be tested with other videos, either create a seperate test + // or update the assertion below accordingly. + ASSERT_TRUE(key_frame_list.size() == 4); - } catch (VCL::Exception e) { - print_exception(e); - ASSERT_TRUE(false); - } + } catch (VCL::Exception e) { + print_exception(e); + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, KeyFrameExtractionFailure) -{ - VCL::KeyFrameList key_frame_list; - try { - VCL::VideoTest video_data(_video_path_mp4_h264); +TEST_F(VideoTest, KeyFrameExtractionFailure) { + VCL::KeyFrameList key_frame_list; + try { + VCL::VideoTest video_data(_video_path_mp4_h264); - key_frame_list = video_data.get_key_frame_list(); + key_frame_list = video_data.get_key_frame_list(); - } catch (VCL::Exception e) { - ASSERT_TRUE(key_frame_list.empty()); - } + } catch (VCL::Exception e) { + ASSERT_TRUE(key_frame_list.empty()); + } } -TEST_F(VideoTest, KeyFrameDecodingSuccess) -{ - try { - VCL::VideoTest video_data(_video_path_mp4_h264); +TEST_F(VideoTest, KeyFrameDecodingSuccess) { + try { + VCL::VideoTest video_data(_video_path_mp4_h264); - VCL::KeyFrameList key_frame_list; - // The base here is wrong for all keyframes, but is does not matter as - // h.264 seeking is based on time (frame_idx * 1/fps) and not base. - key_frame_list.push_back({.idx = 155, .base = 495756}); - key_frame_list.push_back({.idx = 0, .base = 564}); - key_frame_list.push_back({.idx = 201, .base = 648600}); - key_frame_list.push_back({.idx = 99, .base = 319224}); - - video_data.set_key_frame_list(key_frame_list); - - std:vector frame_query = {15, 30, 110, 150}; - int first_query_len = frame_query.size(); + VCL::KeyFrameList key_frame_list; + // The base here is wrong for all keyframes, but is does not matter as + // h.264 seeking is based on time (frame_idx * 1/fps) and not base. + key_frame_list.push_back({.idx = 155, .base = 495756}); + key_frame_list.push_back({.idx = 0, .base = 564}); + key_frame_list.push_back({.idx = 201, .base = 648600}); + key_frame_list.push_back({.idx = 99, .base = 319224}); - std::vector mat_list = video_data.get_frames(frame_query); - ASSERT_TRUE(mat_list.size() == frame_query.size()); + video_data.set_key_frame_list(key_frame_list); - frame_query.clear(); + std::vector frame_query = {15, 30, 110, 150}; + int first_query_len = frame_query.size(); - frame_query = {100, 120, 130}; - int second_query_len = frame_query.size(); - for (auto& m : video_data.get_frames(frame_query)) - mat_list.push_back(m); - ASSERT_TRUE(mat_list.size() == (first_query_len + second_query_len)); + std::vector mat_list = video_data.get_frames(frame_query); + ASSERT_TRUE(mat_list.size() == frame_query.size()); + frame_query.clear(); - for (int i = 0; i < mat_list.size(); ++i) { + frame_query = {100, 120, 130}; + int second_query_len = frame_query.size(); + for (auto &m : video_data.get_frames(frame_query)) + mat_list.push_back(m); + ASSERT_TRUE(mat_list.size() == (first_query_len + second_query_len)); - std::string s = std::to_string(i); - s.insert(s.begin(), 5 - s.length(), '0'); - std::string filename = "videos_tests/kf_frame_" + s; + for (int i = 0; i < mat_list.size(); ++i) { - VCL::Image img(mat_list[i], false); - img.store(filename, VCL::Image::Format::PNG, false); - } + std::string s = std::to_string(i); + s.insert(s.begin(), 5 - s.length(), '0'); + std::string filename = "videos_tests/kf_frame_" + s; - } catch (VCL::Exception e) { - ASSERT_TRUE(false); + VCL::Image img(mat_list[i], false); + img.store(filename, VCL::Image::Format::PNG, false); } + + } catch (VCL::Exception e) { + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, CheckDecodedSequentialFrames) -{ - std::string video_to_test = _video_path_mp4_h264; +TEST_F(VideoTest, CheckDecodedSequentialFrames) { + std::string video_to_test = _video_path_mp4_h264; - cv::VideoCapture testVideo(video_to_test); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + cv::VideoCapture testVideo(video_to_test); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - try { + try { VCL::VideoTest video_data_kf(video_to_test); video_data_kf.get_key_frame_list(); VCL::VideoTest video_data_ocv(video_to_test); - for (int i = 0; i < test_frame_count; ++i) { + for (int i = 0; i < test_frame_count; ++i) { - const unsigned frame_idx = i; + const unsigned frame_idx = i; - cv::Mat decoded_with_keyframe; - decoded_with_keyframe = video_data_kf.get_frame(frame_idx); + cv::Mat decoded_with_keyframe; + decoded_with_keyframe = video_data_kf.get_frame(frame_idx); - cv::Mat decoded_with_opencv; - decoded_with_opencv = video_data_ocv.get_frame(frame_idx); + cv::Mat decoded_with_opencv; + decoded_with_opencv = video_data_ocv.get_frame(frame_idx); - compare_mat_mat(decoded_with_keyframe, decoded_with_opencv); - } - } catch (VCL::Exception e) { - print_exception(e); - ASSERT_TRUE(false); + compare_mat_mat(decoded_with_keyframe, decoded_with_opencv); } + } catch (VCL::Exception e) { + print_exception(e); + ASSERT_TRUE(false); + } } -TEST_F(VideoTest, CheckDecodedRandomFrames) -{ - std::string video_to_test = _video_path_mp4_h264; +TEST_F(VideoTest, CheckDecodedRandomFrames) { + std::string video_to_test = _video_path_mp4_h264; - cv::VideoCapture testVideo(video_to_test); - long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); + cv::VideoCapture testVideo(video_to_test); + long test_frame_count = testVideo.get(cv::CAP_PROP_FRAME_COUNT); - /* initialize random seed: */ - srand(24); // (time(NULL)); + /* initialize random seed: */ + srand(24); // (time(NULL)); - try { + try { VCL::VideoTest video_data_kf(video_to_test); video_data_kf.get_key_frame_list(); VCL::VideoTest video_data_ocv(video_to_test); - for (int i = 0; i < test_frame_count * 2; ++i) { + for (int i = 0; i < test_frame_count * 2; ++i) { - // generate random number between 0 and test_frame_count - // every 2 calls. - int frame_idx; - if (i % 2 == 0) - frame_idx = rand() % test_frame_count; - else - frame_idx = frame_idx + 4 < test_frame_count ? - frame_idx + 4 : frame_idx; + // generate random number between 0 and test_frame_count + // every 2 calls. + int frame_idx; + if (i % 2 == 0) + frame_idx = rand() % test_frame_count; + else + frame_idx = + frame_idx + 4 < test_frame_count ? frame_idx + 4 : frame_idx; - cv::Mat decoded_with_keyframe; - decoded_with_keyframe = video_data_kf.get_frame(frame_idx); + cv::Mat decoded_with_keyframe; + decoded_with_keyframe = video_data_kf.get_frame(frame_idx); - cv::Mat decoded_with_opencv; - decoded_with_opencv = video_data_ocv.get_frame(frame_idx); + cv::Mat decoded_with_opencv; + decoded_with_opencv = video_data_ocv.get_frame(frame_idx); - compare_mat_mat(decoded_with_keyframe, decoded_with_opencv); - } - } catch (VCL::Exception e) { - print_exception(e); - ASSERT_TRUE(false); + compare_mat_mat(decoded_with_keyframe, decoded_with_opencv); } + } catch (VCL::Exception e) { + print_exception(e); + ASSERT_TRUE(false); + } } diff --git a/tests/unit_tests/client_add_entity.cc b/tests/unit_tests/client_add_entity.cc index ed8e3cad..9a7d7c04 100644 --- a/tests/unit_tests/client_add_entity.cc +++ b/tests/unit_tests/client_add_entity.cc @@ -1,230 +1,203 @@ #include "meta_data_helper.h" -TEST(CLIENT_CPP, add_two_CLIENT_CPP_with_connection) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple.append(meta_obj->construct_add_query(1, false, false)); - - tuple.append(meta_obj->construct_add_area(2, false)); - tuple.append(meta_obj->construct_add_connection(1,2,false)); - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - int status1 = result[0]["AddEntity"]["status"].asInt(); - int status2 = result[1]["AddEntity"]["status"].asInt(); - int status3 = result[1]["AddConnection"]["status"].asInt(); - - - EXPECT_EQ(status1, 0); - EXPECT_EQ(status2, 0); - EXPECT_EQ(status3, 0); - - -} - -TEST(CLIENT_CPP, add_single_entity) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple.append(meta_obj->construct_add_query(1, false, false)); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - int status1 = result[0]["AddEntity"]["status"].asInt(); - - - - EXPECT_EQ(status1, 0); - +TEST(CLIENT_CPP, add_two_CLIENT_CPP_with_connection) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple.append(meta_obj->construct_add_query(1, false, false)); + + tuple.append(meta_obj->construct_add_area(2, false)); + tuple.append(meta_obj->construct_add_connection(1, 2, false)); + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + int status1 = result[0]["AddEntity"]["status"].asInt(); + int status2 = result[1]["AddEntity"]["status"].asInt(); + int status3 = result[1]["AddConnection"]["status"].asInt(); + + EXPECT_EQ(status1, 0); + EXPECT_EQ(status2, 0); + EXPECT_EQ(status3, 0); } -TEST(CLIENT_CPP, add_single_entity_expiration) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple.append(meta_obj->construct_add_query(1, false, true)); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - int status1 = result[0]["AddEntity"]["status"].asInt(); - +TEST(CLIENT_CPP, add_single_entity) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple.append(meta_obj->construct_add_query(1, false, false)); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); - - EXPECT_EQ(status1, 0); + int status1 = result[0]["AddEntity"]["status"].asInt(); + EXPECT_EQ(status1, 0); } -TEST(CLIENT_CPP, add_single_entity_constraints) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple.append(meta_obj->construct_add_query(1, true, false)); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - int status1 = result[0]["AddEntity"]["status"].asInt(); - - EXPECT_EQ(status1, 0); +TEST(CLIENT_CPP, add_single_entity_expiration) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple.append(meta_obj->construct_add_query(1, false, true)); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + int status1 = result[0]["AddEntity"]["status"].asInt(); + EXPECT_EQ(status1, 0); } +TEST(CLIENT_CPP, add_single_entity_constraints) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple.append(meta_obj->construct_add_query(1, true, false)); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); -TEST(CLIENT_CPP, add_multiple_CLIENT_CPP) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - int num_queries =4; - for (int i=1; i<=num_queries; i++){ - tuple.append(meta_obj->construct_add_query(i, false, false)); - - } - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - for(int i=0; i_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(),meta_obj->get_port())); - - - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("../tests/unit_tests/queries.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - - VDMS::Response response =meta_obj->_aclient->query(json_query); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - for(int i=0; i_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + int num_queries = 4; + for (int i = 1; i <= num_queries; i++) { + tuple.append(meta_obj->construct_add_query(i, false, false)); + } + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + for (int i = 0; i < result.size(); i++) { + int status = result[i]["AddEntity"]["status"].asInt(); + + EXPECT_EQ(status, 0); + } } - -TEST (CLIENT_CPP, add_two_from_file){ - - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(),meta_obj->get_port())); - - - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("../tests/unit_tests/two_entities.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - - VDMS::Response response =meta_obj->_aclient->query(json_query); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - for(int i=0; i_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("../tests/unit_tests/queries.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + VDMS::Response response = meta_obj->_aclient->query(json_query); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + for (int i = 0; i < result.size(); i++) { + int status = result[i]["AddEntity"]["status"].asInt(); + EXPECT_EQ(status, 0); + } } -TEST (CLIENT_CPP, add_connection_from_file){ - - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - - - std::ifstream ifile; - int fsize; - char * inBuf; - ifile.open("../tests/unit_tests/connection.json", std::ifstream::in); - ifile.seekg(0, std::ios::end); - fsize = (int)ifile.tellg(); - ifile.seekg(0, std::ios::beg); - inBuf = new char[fsize]; - ifile.read(inBuf, fsize); - std::string json_query = std::string(inBuf); - ifile.close(); - delete[] inBuf; - - - VDMS::Response response =meta_obj->_aclient->query(json_query); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - for(int i=0; i_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("../tests/unit_tests/two_entities.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + VDMS::Response response = meta_obj->_aclient->query(json_query); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + for (int i = 0; i < result.size(); i++) { + int status = result[i]["AddEntity"]["status"].asInt(); + EXPECT_EQ(status, 0); + } } -TEST(CLIENT_CPP, add_multiple_CLIENT_CPP_constraints) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - int num_queries =4; - for (int i=1; i<=num_queries; i++){ - tuple.append(meta_obj->construct_add_query(i, true, false)); - - } - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - for(int i=0; i_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + + std::ifstream ifile; + int fsize; + char *inBuf; + ifile.open("../tests/unit_tests/connection.json", std::ifstream::in); + ifile.seekg(0, std::ios::end); + fsize = (int)ifile.tellg(); + ifile.seekg(0, std::ios::beg); + inBuf = new char[fsize]; + ifile.read(inBuf, fsize); + std::string json_query = std::string(inBuf); + ifile.close(); + delete[] inBuf; + + VDMS::Response response = meta_obj->_aclient->query(json_query); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + for (int i = 0; i < result.size() - 1; i++) { + int status = result[i]["FindEntity"]["status"].asInt(); + EXPECT_EQ(status, 0); + } } - - +TEST(CLIENT_CPP, add_multiple_CLIENT_CPP_constraints) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + int num_queries = 4; + for (int i = 1; i <= num_queries; i++) { + tuple.append(meta_obj->construct_add_query(i, true, false)); + } + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + for (int i = 0; i < result.size(); i++) { + int status = result[i]["AddEntity"]["status"].asInt(); + EXPECT_EQ(status, 0); + } +} diff --git a/tests/unit_tests/client_blob.cc b/tests/unit_tests/client_blob.cc index 7af5259d..bdb16a77 100644 --- a/tests/unit_tests/client_blob.cc +++ b/tests/unit_tests/client_blob.cc @@ -1,57 +1,62 @@ -#include "meta_data_helper.h" #include "CSVParserUtil.h" -TEST(BLOB, add_Blob){ - std::string filename ="../tests/test_images/large1.jpg"; - std::vector blobs; - VDMS::CSVParserUtil csv_util; - std::string* blob_data_ptr = nullptr; - - csv_util.read_blob_image(filename, &blob_data_ptr); - - if(blob_data_ptr!=nullptr){ - blobs.push_back(blob_data_ptr); - // std::cout <<*blobs[0] <read_blob(filename)); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->construct_Blob(); - - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); - Json::Value result; - - meta_obj->_reader.parse(response.json.c_str(), result); - int status1 = result[0]["AddBlob"]["status"].asInt(); - EXPECT_EQ(status1, 0); +#include "meta_data_helper.h" +TEST(BLOB, add_Blob) { + std::string filename = "../tests/test_images/large1.jpg"; + std::vector blobs; + VDMS::CSVParserUtil csv_util; + std::string *blob_data_ptr = nullptr; + + csv_util.read_blob_image(filename, &blob_data_ptr); + + if (blob_data_ptr != nullptr) { + blobs.push_back(blob_data_ptr); + // std::cout <<*blobs[0] <read_blob(filename)); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->construct_Blob(); + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); + Json::Value result; + + meta_obj->_reader.parse(response.json.c_str(), result); + int status1 = result[0]["AddBlob"]["status"].asInt(); + EXPECT_EQ(status1, 0); } -TEST(BLOB, update_Blob){ +TEST(BLOB, update_Blob) { - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->construct_updateBlob(); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->construct_updateBlob(); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - int status1 = result[0]["status"].asInt(); + meta_obj->_reader.parse(response.json.c_str(), result); + int status1 = result[0]["status"].asInt(); - EXPECT_EQ(status1, 0); + EXPECT_EQ(status1, 0); } -TEST(BLOB, find_Blob){ +TEST(BLOB, find_Blob) { - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->construct_findBlob(); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->construct_findBlob(); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - int status1 = result[0]["status"].asInt(); + meta_obj->_reader.parse(response.json.c_str(), result); + int status1 = result[0]["status"].asInt(); - EXPECT_EQ(status1, 0); + EXPECT_EQ(status1, 0); } \ No newline at end of file diff --git a/tests/unit_tests/client_bounding_box.cc b/tests/unit_tests/client_bounding_box.cc index 0bde4d75..e1eb2b8f 100644 --- a/tests/unit_tests/client_bounding_box.cc +++ b/tests/unit_tests/client_bounding_box.cc @@ -1,34 +1,38 @@ #include "meta_data_helper.h" -TEST(CLIENT_CPP, add_BB){ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->constuct_BB(false); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); +TEST(CLIENT_CPP, add_BB) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->constuct_BB(false); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); - int status1 = result[0]["AddBoundingBox"]["status"].asInt(); - EXPECT_EQ(status1, 0); + int status1 = result[0]["AddBoundingBox"]["status"].asInt(); + EXPECT_EQ(status1, 0); } -TEST(CLIENT_CPP, add_BB_with_image){ - std::string filename ="../tests/test_images/large1.jpg"; +TEST(CLIENT_CPP, add_BB_with_image) { + std::string filename = "../tests/test_images/large1.jpg"; - std::vector blobs; + std::vector blobs; - Meta_Data* meta_obj=new Meta_Data(); - blobs.push_back(meta_obj->read_blob(filename)); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->constuct_BB(true); - // std::cout<_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - // std::cout << result <read_blob(filename)); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->constuct_BB(true); + // std::cout<_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + // std::cout << result < all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["AddEntity"]["status"].asInt(), 0); - } +#include "meta_data_helper.h" +TEST(CLIENT_CPP_CSV, parse_csv_entity) { + + std::string filename = "../tests/csv_samples/CSVformat100.csv"; + size_t num_threads = 5; + std::string vdms_server = "localhost"; + int port = 55558; + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["AddEntity"]["status"].asInt(), 0); + } } // TEST(CLIENT_CPP_CSV, parse_update_csv_entity) @@ -41,198 +39,182 @@ TEST(CLIENT_CPP_CSV, parse_csv_entity) // } // } -TEST(CLIENT_CPP_CSV, parse_csv_connection) -{ - - std::string filename = "../tests/csv_samples/connection.csv"; - size_t num_threads = 5; - std::string vdms_server = "localhost"; - int port = 55558; - - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["AddConnection"]["status"].asInt(), 0); - } +TEST(CLIENT_CPP_CSV, parse_csv_connection) { + + std::string filename = "../tests/csv_samples/connection.csv"; + size_t num_threads = 5; + std::string vdms_server = "localhost"; + int port = 55558; + + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["AddConnection"]["status"].asInt(), 0); + } } -TEST(CLIENT_CPP_CSV, parse_csv_images) -{ - std::string filename = "../tests/csv_samples/Image.csv"; - size_t num_threads = 5; - std::string vdms_server = "localhost"; - int port = 55558; - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["AddImage"]["status"].asInt(), 0); - } +TEST(CLIENT_CPP_CSV, parse_csv_images) { + std::string filename = "../tests/csv_samples/Image.csv"; + size_t num_threads = 5; + std::string vdms_server = "localhost"; + int port = 55558; + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["AddImage"]["status"].asInt(), 0); + } } -TEST(CLIENT_CPP_CSV, parse_csv_descriptor_set) -{ - std::string filename = "../tests/csv_samples/DescriptorSet.csv"; - size_t num_threads = 5; - std::string vdms_server = "localhost"; - int port = 55558; - - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["AddDescriptorSet"]["status"].asInt(), 0); - } +TEST(CLIENT_CPP_CSV, parse_csv_descriptor_set) { + std::string filename = "../tests/csv_samples/DescriptorSet.csv"; + size_t num_threads = 5; + std::string vdms_server = "localhost"; + int port = 55558; + + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["AddDescriptorSet"]["status"].asInt(), 0); + } } -TEST(CLIENT_CPP_CSV, parse_csv_descriptor) -{ - std::string filename = "../tests/csv_samples/Descriptor.csv"; - size_t num_threads = 5; - std::string vdms_server = "localhost"; - int port = 55558; - - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["AddDescriptor"]["status"].asInt(), 0); - } +TEST(CLIENT_CPP_CSV, parse_csv_descriptor) { + std::string filename = "../tests/csv_samples/Descriptor.csv"; + size_t num_threads = 5; + std::string vdms_server = "localhost"; + int port = 55558; + + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["AddDescriptor"]["status"].asInt(), 0); + } } -TEST(CLIENT_CPP_CSV, parse_csv_bb) -{ - std::string filename = "../tests/csv_samples/Rectangle.csv"; - size_t num_threads = 5; - std::string vdms_server = "localhost"; - int port = 55558; - - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["AddBoundingBox"]["status"].asInt(), 0); - } +TEST(CLIENT_CPP_CSV, parse_csv_bb) { + std::string filename = "../tests/csv_samples/Rectangle.csv"; + size_t num_threads = 5; + std::string vdms_server = "localhost"; + int port = 55558; + + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["AddBoundingBox"]["status"].asInt(), 0); + } } -TEST(CLIENT_CPP_CSV, parse_csv_video) -{ - std::string filename = "../tests/csv_samples/Video.csv"; - size_t num_threads = 5; - std::string vdms_server = "localhost"; - int port = 55558; - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["AddVideo"]["status"].asInt(), 0); - } +TEST(CLIENT_CPP_CSV, parse_csv_video) { + std::string filename = "../tests/csv_samples/Video.csv"; + size_t num_threads = 5; + std::string vdms_server = "localhost"; + int port = 55558; + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["AddVideo"]["status"].asInt(), 0); + } } -TEST(CLIENT_CPP_CSV, parse_csv_invalid_entity) -{ - std::string filename = "../tests/csv_samples/invalid.csv"; - std::ofstream csv_file; - csv_file.open(filename); - csv_file << "EntityInvalidTest,prop_name,prop_lastname,prop_id,prop_age\n"; - csv_file << "Person,Ali,Hum,1,2\n"; - csv_file.close(); - - size_t num_threads = 1; - std::string vdms_server = "localhost"; - int port = 55558; - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - remove(filename.c_str()); - - Json::Value result; - Json::Reader _reader; - _reader.parse(all_results[0].json.c_str(), result); - EXPECT_EQ(result["status"].asInt(), -1); - EXPECT_EQ(result["info"].asString(), "Command does not exist"); +TEST(CLIENT_CPP_CSV, parse_csv_invalid_entity) { + std::string filename = "../tests/csv_samples/invalid.csv"; + std::ofstream csv_file; + csv_file.open(filename); + csv_file << "EntityInvalidTest,prop_name,prop_lastname,prop_id,prop_age\n"; + csv_file << "Person,Ali,Hum,1,2\n"; + csv_file.close(); + + size_t num_threads = 1; + std::string vdms_server = "localhost"; + int port = 55558; + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + remove(filename.c_str()); + + Json::Value result; + Json::Reader _reader; + _reader.parse(all_results[0].json.c_str(), result); + EXPECT_EQ(result["status"].asInt(), -1); + EXPECT_EQ(result["info"].asString(), "Command does not exist"); } -TEST(CLIENT_CPP_CSV, parse_csv_invalid_image) -{ - std::string filename = "../tests/csv_samples/invalid_file.csv"; - std::ofstream csv_file; - csv_file.open(filename); - csv_file << "ImagePath,ops_threshold,ops_crop,ops_resize,ops_flip,ops_rotate,prop_type,prop_part,format,cons_1\n"; - csv_file << "../tests/test_images/large1_invalid.jpg,350,,,,,,image1,jpg,part==image1\n"; - csv_file.close(); - - size_t num_threads = 1; - std::string vdms_server = "localhost"; - int port = 55558; - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - remove(filename.c_str()); - - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["status"].asInt(), -1); - } +TEST(CLIENT_CPP_CSV, parse_csv_invalid_image) { + std::string filename = "../tests/csv_samples/invalid_file.csv"; + std::ofstream csv_file; + csv_file.open(filename); + csv_file << "ImagePath,ops_threshold,ops_crop,ops_resize,ops_flip,ops_rotate," + "prop_type,prop_part,format,cons_1\n"; + csv_file << "../tests/test_images/" + "large1_invalid.jpg,350,,,,,,image1,jpg,part==image1\n"; + csv_file.close(); + + size_t num_threads = 1; + std::string vdms_server = "localhost"; + int port = 55558; + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + remove(filename.c_str()); + + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["status"].asInt(), -1); + } } -TEST(CLIENT_CPP_CSV, parse_csv_invalid_video) -{ - std::string filename = "../tests/csv_samples/invalid_file.csv"; - std::ofstream csv_file; - csv_file.open(filename); - csv_file << "VideoPath,format,compressto,prop_name,ops_resize,ops_interval\n"; - csv_file << "../tests/test_videos/Megamind_invalid.avi,avi,h264,Good,,\n"; - csv_file.close(); - - size_t num_threads = 1; - std::string vdms_server = "localhost"; - int port = 55558; - std::vector all_results; - VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); - - all_results = csv_parser.parse(); - remove(filename.c_str()); - - Json::Value result; - Json::Reader _reader; - for (int k = 0; k < all_results.size(); k++) - { - _reader.parse(all_results[k].json.c_str(), result); - EXPECT_EQ(result[k]["status"].asInt(), -1); - } +TEST(CLIENT_CPP_CSV, parse_csv_invalid_video) { + std::string filename = "../tests/csv_samples/invalid_file.csv"; + std::ofstream csv_file; + csv_file.open(filename); + csv_file << "VideoPath,format,compressto,prop_name,ops_resize,ops_interval\n"; + csv_file << "../tests/test_videos/Megamind_invalid.avi,avi,h264,Good,,\n"; + csv_file.close(); + + size_t num_threads = 1; + std::string vdms_server = "localhost"; + int port = 55558; + std::vector all_results; + VDMS::CSVParser csv_parser(filename, num_threads, vdms_server, port); + + all_results = csv_parser.parse(); + remove(filename.c_str()); + + Json::Value result; + Json::Reader _reader; + for (int k = 0; k < all_results.size(); k++) { + _reader.parse(all_results[k].json.c_str(), result); + EXPECT_EQ(result[k]["status"].asInt(), -1); + } } - diff --git a/tests/unit_tests/client_descriptors.cc b/tests/unit_tests/client_descriptors.cc index 979df9f6..5dd65a6f 100644 --- a/tests/unit_tests/client_descriptors.cc +++ b/tests/unit_tests/client_descriptors.cc @@ -1,97 +1,98 @@ #include "meta_data_helper.h" -TEST(CLIENT_CPP, add_descriptor) -{ - std::vector fv_values; - srand( (unsigned)time( NULL ) ); - for (int i = 0; i < 1000; i++) - fv_values.push_back((float) rand()/RAND_MAX); - - std::vector blobs; - std::string *bytes_str = new std::string(); - bytes_str->resize(fv_values.size() * sizeof(float)); - std::memcpy((void*) bytes_str->data(), fv_values.data(), fv_values.size() * sizeof(float)); - blobs.push_back(bytes_str); - - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->construct_descriptor(); - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - - int status1 = result[0]["AddDescriptor"]["status"].asInt(); - - EXPECT_EQ(status1, 0); +TEST(CLIENT_CPP, add_descriptor) { + std::vector fv_values; + srand((unsigned)time(NULL)); + for (int i = 0; i < 1000; i++) + fv_values.push_back((float)rand() / RAND_MAX); + + std::vector blobs; + std::string *bytes_str = new std::string(); + bytes_str->resize(fv_values.size() * sizeof(float)); + std::memcpy((void *)bytes_str->data(), fv_values.data(), + fv_values.size() * sizeof(float)); + blobs.push_back(bytes_str); + + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->construct_descriptor(); + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + int status1 = result[0]["AddDescriptor"]["status"].asInt(); + + EXPECT_EQ(status1, 0); } -TEST(CLIENT_CPP, add_flinng_descriptor) -{ - std::vector fv_values; - srand( (unsigned)time( NULL ) ); - for (int i = 0; i < 100; i++) - fv_values.push_back((float) rand()/RAND_MAX); - - std::vector blobs; - std::string *bytes_str = new std::string(); - bytes_str->resize(fv_values.size() * sizeof(float)); - std::memcpy((void*) bytes_str->data(), fv_values.data(), fv_values.size() * sizeof(float)); - blobs.push_back(bytes_str); - - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->construct_descriptor(); - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - - int status1 = result[0]["AddDescriptor"]["status"].asInt(); - - EXPECT_EQ(status1, 0); +TEST(CLIENT_CPP, add_flinng_descriptor) { + std::vector fv_values; + srand((unsigned)time(NULL)); + for (int i = 0; i < 100; i++) + fv_values.push_back((float)rand() / RAND_MAX); + + std::vector blobs; + std::string *bytes_str = new std::string(); + bytes_str->resize(fv_values.size() * sizeof(float)); + std::memcpy((void *)bytes_str->data(), fv_values.data(), + fv_values.size() * sizeof(float)); + blobs.push_back(bytes_str); + + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->construct_descriptor(); + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + int status1 = result[0]["AddDescriptor"]["status"].asInt(); + + EXPECT_EQ(status1, 0); } -TEST(CLIENT_CPP, find_descriptor){ - - std::vector fv_values; - srand( (unsigned)time( NULL ) ); - - for (int i = 0; i < 1000; i++) - { - fv_values.push_back((float) rand()/RAND_MAX); - } - - std::vector blobs; - std::string *bytes_str = new std::string(); - bytes_str->resize(fv_values.size() * sizeof(float)); - std::memcpy((void*) bytes_str->data(), fv_values.data(), fv_values.size() * sizeof(float)); - - blobs.push_back(bytes_str); - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->construct_find_descriptor(); - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - int status1; - - if (!result.isArray()) - status1=-10; - - if( result[0]["FindDescriptor"]["status"] == -1) - - status1=-1; - else - status1 = result[0]["FindDescriptor"]["status"].asInt(); - - - - EXPECT_EQ(status1, 0); +TEST(CLIENT_CPP, find_descriptor) { + + std::vector fv_values; + srand((unsigned)time(NULL)); + + for (int i = 0; i < 1000; i++) { + fv_values.push_back((float)rand() / RAND_MAX); + } + + std::vector blobs; + std::string *bytes_str = new std::string(); + bytes_str->resize(fv_values.size() * sizeof(float)); + std::memcpy((void *)bytes_str->data(), fv_values.data(), + fv_values.size() * sizeof(float)); + + blobs.push_back(bytes_str); + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->construct_find_descriptor(); + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + int status1; + + if (!result.isArray()) + status1 = -10; + + if (result[0]["FindDescriptor"]["status"] == -1) + + status1 = -1; + else + status1 = result[0]["FindDescriptor"]["status"].asInt(); + EXPECT_EQ(status1, 0); } \ No newline at end of file diff --git a/tests/unit_tests/client_find_entities.cc b/tests/unit_tests/client_find_entities.cc index 25127fb6..94a6cc08 100644 --- a/tests/unit_tests/client_find_entities.cc +++ b/tests/unit_tests/client_find_entities.cc @@ -1,76 +1,69 @@ #include "meta_data_helper.h" +TEST(CLIENT_CPP, find_single_entity) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple.append(meta_obj->construct_find_entity(false, false)); -TEST(CLIENT_CPP, find_single_entity) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple.append(meta_obj->construct_find_entity(false,false)); - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - int status = result[0]["FindEntity"]["status"].asInt(); - - EXPECT_EQ(status, 0); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + int status = result[0]["FindEntity"]["status"].asInt(); + EXPECT_EQ(status, 0); } -TEST(CLIENT_CPP, find_single_delete_flag) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple.append(meta_obj->construct_find_entity(true,false)); +TEST(CLIENT_CPP, find_single_delete_flag) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple.append(meta_obj->construct_find_entity(true, false)); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); - int status = result[0]["FindEntity"]["status"].asInt(); - - EXPECT_EQ(status, 0); + int status = result[0]["FindEntity"]["status"].asInt(); + EXPECT_EQ(status, 0); } +TEST(CLIENT_CPP, find_single_expiration_flag) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple.append(meta_obj->construct_find_entity(false, true)); -TEST(CLIENT_CPP, find_single_expiration_flag) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple.append(meta_obj->construct_find_entity(false,true)); - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - int status = result[0]["FindEntity"]["status"].asInt(); - - EXPECT_EQ(status, 0); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + int status = result[0]["FindEntity"]["status"].asInt(); + EXPECT_EQ(status, 0); } -TEST(CLIENT_CPP, find_single_expiration_flag_auto_delete) -{ - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple.append(meta_obj->construct_find_entity(true,true)); +TEST(CLIENT_CPP, find_single_expiration_flag_auto_delete) { + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple.append(meta_obj->construct_find_entity(true, true)); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - int status = result[0]["FindEntity"]["status"].asInt(); - - EXPECT_EQ(status, 0); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + int status = result[0]["FindEntity"]["status"].asInt(); + EXPECT_EQ(status, 0); } - - diff --git a/tests/unit_tests/client_image.cc b/tests/unit_tests/client_image.cc index 8ab44d6e..970e70bc 100644 --- a/tests/unit_tests/client_image.cc +++ b/tests/unit_tests/client_image.cc @@ -1,82 +1,146 @@ #include "meta_data_helper.h" +TEST(CLIENT_CPP, add_image) { + std::string filename = "../tests/test_images/large1.jpg"; -TEST(CLIENT_CPP, add_image){ + std::vector blobs; + Meta_Data *meta_obj = new Meta_Data(); + blobs.push_back(meta_obj->read_blob(filename)); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->constuct_image(); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); - std::string filename ="../tests/test_images/large1.jpg"; - - std::vector blobs; - - Meta_Data* meta_obj=new Meta_Data(); - blobs.push_back(meta_obj->read_blob(filename)); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->constuct_image(); - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - int status1 = result[0]["AddImage"]["status"].asInt(); - EXPECT_EQ(status1, 0); + int status1 = result[0]["AddImage"]["status"].asInt(); + EXPECT_EQ(status1, 0); } +TEST(CLIENT_CPP, add_image_resize_operation) { + std::string image; -TEST(CLIENT_CPP, add_image_resize_operation){ - - std::string image; - - std::fstream file("../tests/test_images/large1.jpg", + std::fstream file("../tests/test_images/large1.jpg", std::ios::in | std::ios::binary | std::ios::ate); - image.resize(file.tellg()); - - file.seekg(0, std::ios::beg); - if( !file.read(&image[ 0 ], image.size())) - std::cout << "error" << std::endl; + image.resize(file.tellg()); - std::vector blobs; + file.seekg(0, std::ios::beg); + if (!file.read(&image[0], image.size())) + std::cout << "error" << std::endl; + std::vector blobs; - std::string *bytes_str = new std::string(image); + std::string *bytes_str = new std::string(image); - blobs.push_back(bytes_str); - Json::Value op; - op["type"]="resize"; - op["width"]=100; - op["height"]=100; - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->constuct_image(true, op); + blobs.push_back(bytes_str); + Json::Value op; + op["type"] = "resize"; + op["width"] = 100; + op["height"] = 100; + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->constuct_image(true, op); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); - - - int status1 = result[0]["AddImage"]["status"].asInt(); - EXPECT_EQ(status1, 0); + int status1 = result[0]["AddImage"]["status"].asInt(); + EXPECT_EQ(status1, 0); } -TEST(CLIENT_CPP, find_image){ +TEST(CLIENT_CPP, find_image) { + + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->construct_find_image(); - Meta_Data* meta_obj=new Meta_Data(); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->construct_find_image(); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + int status1 = result[0]["FindImage"]["status"].asInt(); + EXPECT_EQ(status1, 0); +} - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); +TEST(CLIENT_CPP, find_image_remote) { + + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + Json::Value op; + op["type"] = "remoteOp"; + op["url"] = "http://localhost:5010/image"; + op["options"]["id"] = "flip"; + op["options"]["format"] = "jpg"; + tuple = meta_obj->construct_find_image_withop(op); + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + int status1 = result[0]["FindImage"]["status"].asInt(); + EXPECT_EQ(status1, 0); + delete meta_obj; +} +TEST(CLIENT_CPP, find_image_syncremote) { + + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + Json::Value op; + op["type"] = "syncremoteOp"; + op["url"] = "http://localhost:5010/image"; + op["options"]["id"] = "flip"; + op["options"]["format"] = "jpg"; + tuple = meta_obj->construct_find_image_withop(op); + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + int status1 = result[0]["FindImage"]["status"].asInt(); + EXPECT_EQ(status1, 0); + delete meta_obj; +} - int status1 = result[0]["FindImage"]["status"].asInt(); - EXPECT_EQ(status1, 0); +TEST(CLIENT_CPP, find_image_udf) { + + Meta_Data *meta_obj = new Meta_Data(); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + Json::Value op; + op["type"] = "userOp"; + op["options"]["id"] = "flip"; + op["options"]["format"] = "jpg"; + op["options"]["port"] = 5555; + tuple = meta_obj->construct_find_image_withop(op); + + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple)); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + + int status1 = result[0]["FindImage"]["status"].asInt(); + EXPECT_EQ(status1, 0); + delete meta_obj; } \ No newline at end of file diff --git a/tests/unit_tests/client_videos.cc b/tests/unit_tests/client_videos.cc index 887ea75f..57acf3a8 100644 --- a/tests/unit_tests/client_videos.cc +++ b/tests/unit_tests/client_videos.cc @@ -1,53 +1,49 @@ #include "meta_data_helper.h" -#include +#include #include +#include #include #include -#include #include -using std::cout; using std::cerr; -using std::endl; using std::string; -using std::ifstream; using std::ostringstream; - -string readFileIntoString(const string& path) { - auto ss = ostringstream{}; - ifstream input_file(path); - if (!input_file.is_open()) { - cerr << "Could not open the file - '" - << path << "'" << endl; - exit(EXIT_FAILURE); - } - ss << input_file.rdbuf(); - return ss.str(); +using std::cerr; +using std::cout; +using std::endl; +using std::ifstream; +using std::ostringstream; +using std::string; + +string readFileIntoString(const string &path) { + auto ss = ostringstream{}; + ifstream input_file(path); + if (!input_file.is_open()) { + cerr << "Could not open the file - '" << path << "'" << endl; + exit(EXIT_FAILURE); + } + ss << input_file.rdbuf(); + return ss.str(); } +TEST(CLIENT_CPP_Video, add_single_video) { + // std::string video; + std::stringstream video; + std::vector blobs; -TEST(CLIENT_CPP_Video, add_single_video){ - - - // std::string video; - std::stringstream video; - std::vector blobs; - - - std::string filename ="../tests/videos/Megamind.avi"; - - - Meta_Data* meta_obj=new Meta_Data(); - blobs.push_back(meta_obj->read_blob(filename)); - meta_obj->_aclient.reset ( new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); - Json::Value tuple ; - tuple=meta_obj->constuct_video(false); - - - VDMS::Response response =meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); - Json::Value result; - meta_obj->_reader.parse(response.json.c_str(), result); + std::string filename = "../tests/videos/Megamind.avi"; - int status1 = result[0]["AddVideo"]["status"].asInt(); - EXPECT_EQ(status1, 0); + Meta_Data *meta_obj = new Meta_Data(); + blobs.push_back(meta_obj->read_blob(filename)); + meta_obj->_aclient.reset( + new VDMS::VDMSClient(meta_obj->get_server(), meta_obj->get_port())); + Json::Value tuple; + tuple = meta_obj->constuct_video(false); + VDMS::Response response = + meta_obj->_aclient->query(meta_obj->_fastwriter.write(tuple), blobs); + Json::Value result; + meta_obj->_reader.parse(response.json.c_str(), result); + int status1 = result[0]["AddVideo"]["status"].asInt(); + EXPECT_EQ(status1, 0); } diff --git a/tests/unit_tests/config-aws-tests.json b/tests/unit_tests/config-aws-tests.json new file mode 100644 index 00000000..23f50bb2 --- /dev/null +++ b/tests/unit_tests/config-aws-tests.json @@ -0,0 +1,11 @@ +// VDMS Config File +// This is the run-time config file +// Sets database paths and other parameters +{ + + "port": 55557, + "db_root_path": "test_db_1", + "storage_type": "aws", //local, aws, etc + "bucket_name": "minio-bucket", + "more-info": "github.com/IntelLabs/vdms" +} diff --git a/tests/unit_tests/helpers.cc b/tests/unit_tests/helpers.cc index 47351370..ad9f1846 100644 --- a/tests/unit_tests/helpers.cc +++ b/tests/unit_tests/helpers.cc @@ -27,103 +27,93 @@ * */ +#include +#include #include #include -#include #include #include -#include #include // memcmp #include "gtest/gtest.h" -#include "helpers.h" #include "Exception.h" +#include "helpers.h" - -#include #include - - +#include // Image / Video Helpers -void compare_mat_mat(cv::Mat &cv_img, cv::Mat &img, float error) -{ - bool exact_comparison = (error == 0.0); +void compare_mat_mat(cv::Mat &cv_img, cv::Mat &img, float error) { + bool exact_comparison = (error == 0.0); - ASSERT_EQ(cv_img.rows, img.rows); - ASSERT_EQ(cv_img.cols, img.cols); - ASSERT_EQ(cv_img.channels(), img.channels()); + ASSERT_EQ(cv_img.rows, img.rows); + ASSERT_EQ(cv_img.cols, img.cols); + ASSERT_EQ(cv_img.channels(), img.channels()); - int rows = img.rows; - int columns = img.cols; - int channels = img.channels(); - if(channels > 3) - { - throw VCLException(OpenFailed, "Greater than 3 channels in image"); - } + int rows = img.rows; + int columns = img.cols; + int channels = img.channels(); + if (channels > 3) { + throw VCLException(OpenFailed, "Greater than 3 channels in image"); + } - // We make then continuous for faster comparison, if exact. - if (exact_comparison && !img.isContinuous()) { - cv::Mat aux = cv_img.clone(); - cv_img = aux.clone(); - aux = img.clone(); - img = aux.clone(); - } + // We make then continuous for faster comparison, if exact. + if (exact_comparison && !img.isContinuous()) { + cv::Mat aux = cv_img.clone(); + cv_img = aux.clone(); + aux = img.clone(); + img = aux.clone(); + } - // For exact comparison, we use memcmp. - if (exact_comparison) { - size_t data_size = rows * columns * channels; - int ret = ::memcmp(cv_img.data, img.data, data_size); - ASSERT_EQ(ret, 0); - return; - } + // For exact comparison, we use memcmp. + if (exact_comparison) { + size_t data_size = rows * columns * channels; + int ret = ::memcmp(cv_img.data, img.data, data_size); + ASSERT_EQ(ret, 0); + return; + } - // For debugging, or near comparison, we check value by value. - - for ( int i = 0; i < rows; ++i ) { - for ( int j = 0; j < columns; ++j ) { - if (channels == 1) { - unsigned char pixel = img.at(i, j); - unsigned char test_pixel = cv_img.at(i, j); - if (exact_comparison) - ASSERT_EQ(pixel, test_pixel); - else - ASSERT_NEAR(pixel, test_pixel, error); - } - else { - cv::Vec3b colors = img.at(i, j); - cv::Vec3b test_colors = cv_img.at(i, j); - for ( int x = 0; x < channels; ++x ) { - if (exact_comparison) - ASSERT_EQ(colors.val[x], test_colors.val[x]); - else - ASSERT_NEAR(colors.val[x], test_colors.val[x], error); - } - } + // For debugging, or near comparison, we check value by value. + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + if (channels == 1) { + unsigned char pixel = img.at(i, j); + unsigned char test_pixel = cv_img.at(i, j); + if (exact_comparison) + ASSERT_EQ(pixel, test_pixel); + else + ASSERT_NEAR(pixel, test_pixel, error); + } else { + cv::Vec3b colors = img.at(i, j); + cv::Vec3b test_colors = cv_img.at(i, j); + for (int x = 0; x < channels; ++x) { + if (exact_comparison) + ASSERT_EQ(colors.val[x], test_colors.val[x]); + else + ASSERT_NEAR(colors.val[x], test_colors.val[x], error); } + } } + } } -void compare_cvcapture_cvcapture(cv::VideoCapture v1, cv::VideoCapture v2) -{ - while (true) { - cv::Mat frame1; - cv::Mat frame2; - if ( v1.read(frame1) && v2.read(frame2)) { - if ( !frame1.empty() && !frame2.empty()) { - compare_mat_mat(frame1,frame2); - } - else if ( frame1.empty() && frame2.empty()) { - return; - } - else - throw VCLException(ObjectEmpty, "One video ended before"); - } - else - throw VCLException(ObjectEmpty, "Error reading frames"); - } +void compare_cvcapture_cvcapture(cv::VideoCapture v1, cv::VideoCapture v2) { + while (true) { + cv::Mat frame1; + cv::Mat frame2; + if (v1.read(frame1) && v2.read(frame2)) { + if (!frame1.empty() && !frame2.empty()) { + compare_mat_mat(frame1, frame2); + } else if (frame1.empty() && frame2.empty()) { + return; + } else + throw VCLException(ObjectEmpty, "One video ended before"); + } else + throw VCLException(ObjectEmpty, "Error reading frames"); + } } // Descriptors Helpers @@ -134,145 +124,157 @@ void compare_cvcapture_cvcapture(cv::VideoCapture v1, cv::VideoCapture v2) // ... // init+nb-1 init+nb-1 ... init+nb-1 (d times) -void generate_desc_linear_increase(int d, int nb, float* xb, float init) -{ - float val = init; - for (int i = 1; i <= nb*d; ++i) { - xb[i-1] = val; - if ( i%d == 0) val++; - } +void generate_desc_linear_increase(int d, int nb, float *xb, float init) { + float val = init; + for (int i = 1; i <= nb * d; ++i) { + xb[i - 1] = val; + if (i % d == 0) + val++; + } } -float* generate_desc_linear_increase(int d, int nb, float init) -{ - float *xb = new float[d * nb]; - generate_desc_linear_increase(d, nb, xb, init); - return xb; +float *generate_desc_linear_increase(int d, int nb, float init) { + float *xb = new float[d * nb]; + generate_desc_linear_increase(d, nb, xb, init); + return xb; } -void generate_desc_normal_cluster(int d, int nb, float* xb, float init, int cluster_size, float clusterhead_std, float cluster_std){ - //std::cout << "\n Creating a Clustered Dataset ... \n"; - //std::cout << "nb= " < cluster_head_dist(0.0f, clusterhead_std); //cluster head standard deviation can be arbitrary - std::normal_distribution cluster_dist(0.0f, cluster_std); //cluster (neighbors close to cluster head) standard deviation should be a small noise (e.g. 1%-10%) - - if((nb % cluster_size) != 0) { - std::cout << "NOTE: Clustered Dataset Not Balanced, total number of elements not a multiple of cluster size, clusters will not have same number of items\n"; + std::normal_distribution cluster_head_dist( + 0.0f, + clusterhead_std); // cluster head standard deviation can be arbitrary + std::normal_distribution cluster_dist( + 0.0f, cluster_std); // cluster (neighbors close to cluster head) standard + // deviation should be a small noise (e.g. 1%-10%) + + if ((nb % cluster_size) != 0) { + std::cout << "NOTE: Clustered Dataset Not Balanced, total number of " + "elements not a multiple of cluster size, clusters will not " + "have same number of items\n"; } - int n_clusters= floor((nb/cluster_size)); - int total = (floor((nb/cluster_size)) * cluster_size); + int n_clusters = floor((nb / cluster_size)); + int total = (floor((nb / cluster_size)) * cluster_size); int remaining = nb - total; - - std::vector cluster_head(n_clusters * d); - - for (uint64_t i = 0; i < cluster_head.size(); ++i) { //create cluster heads, they will be used as the list queries - cluster_head[i] = cluster_head_dist(gen); + + std::vector cluster_head(n_clusters * d); + + for (uint64_t i = 0; i < cluster_head.size(); + ++i) { // create cluster heads, they will be used as the list queries + cluster_head[i] = cluster_head_dist(gen); } - //create total dataset, cluster heads with neighbors around each - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < cluster_size; j++){ - if((i*cluster_size + j) % cluster_size == 0) { //cluster head + // create total dataset, cluster heads with neighbors around each + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < cluster_size; j++) { + if ((i * cluster_size + j) % cluster_size == 0) { // cluster head + for (int z = 0; z < d; z++) + xb[d * (i * cluster_size + j) + z] = cluster_head[i * d + z]; + } else { // cluster neighbor for (int z = 0; z < d; z++) - xb[ d*(i*cluster_size + j) + z] = cluster_head[i * d + z]; + xb[d * (i * cluster_size + j) + z] = + cluster_head[i * d + z] + cluster_dist(gen); } - else{ //cluster neighbor - for (int z = 0; z < d; z++) - xb[d*(i*cluster_size + j) + z] = cluster_head[i * d + z] + cluster_dist(gen); - } } } - for (int i = 0; i < remaining; i++) { - for (int z = 0; z < d; z++) { - xb[total*d + i*d + z] = cluster_head[n_clusters*d + z] + cluster_dist(gen); - } + for (int i = 0; i < remaining; i++) { + for (int z = 0; z < d; z++) { + xb[total * d + i * d + z] = + cluster_head[n_clusters * d + z] + cluster_dist(gen); + } } - //end create total dataset + // end create total dataset } -float* generate_desc_normal_cluster(int d, int nb, float init, int cluster_size, float clusterhead_std, float cluster_std){ - float *xb = new float[d * nb]; //total dataset - generate_desc_normal_cluster(d, nb, xb, init, cluster_size, clusterhead_std, cluster_std); - return xb; +float *generate_desc_normal_cluster(int d, int nb, float init, int cluster_size, + float clusterhead_std, float cluster_std) { + float *xb = new float[d * nb]; // total dataset + generate_desc_normal_cluster(d, nb, xb, init, cluster_size, clusterhead_std, + cluster_std); + return xb; } +void create_additional_neighbors(int d, int cluster_increment, int n_clusters, + float *cluster_heads, float cluster_std, + float *neighbors) { -void create_additional_neighbors(int d, int cluster_increment, int n_clusters, float* cluster_heads, float cluster_std, float *neighbors){ - - std::default_random_engine gen; - std::normal_distribution cluster_dist(0.0f, cluster_std); //cluster (neighbors close to cluster head) standard deviation should be a small noise (e.g. 1%-10%) - - //create increment neighbors dataset as new neihgbors near cluster heads - for (int i = 0; i < n_clusters ; i++) { - for (int j = 0; j < cluster_increment; j++){ - for (int z = 0; z < d; z++){ - neighbors[d*(i*cluster_increment + j) + z] = cluster_heads[i*d + z] + cluster_dist(gen); - } - - } - } + std::default_random_engine gen; + std::normal_distribution cluster_dist( + 0.0f, cluster_std); // cluster (neighbors close to cluster head) standard + // deviation should be a small noise (e.g. 1%-10%) + // create increment neighbors dataset as new neihgbors near cluster heads + for (int i = 0; i < n_clusters; i++) { + for (int j = 0; j < cluster_increment; j++) { + for (int z = 0; z < d; z++) { + neighbors[d * (i * cluster_increment + j) + z] = + cluster_heads[i * d + z] + cluster_dist(gen); + } + } + } } - -float* create_additional_neighbors(int d, int cluster_increment, int n_clusters, float* cluster_heads, float cluster_std){ - float *neighbors = new float[d * cluster_increment * n_clusters]; //total additional neighbors - create_additional_neighbors(d, cluster_increment, n_clusters, cluster_heads, cluster_std , neighbors); - return neighbors; +float *create_additional_neighbors(int d, int cluster_increment, int n_clusters, + float *cluster_heads, float cluster_std) { + float *neighbors = new float[d * cluster_increment * + n_clusters]; // total additional neighbors + create_additional_neighbors(d, cluster_increment, n_clusters, cluster_heads, + cluster_std, neighbors); + return neighbors; } -std::map animals_map() -{ - std::map class_map; - class_map[0] = "parrot"; - class_map[1] = "dog"; - class_map[2] = "cat"; - class_map[3] = "messi"; - class_map[4] = "bird"; - class_map[5] = "condor"; - class_map[6] = "panda"; - - return class_map; +std::map animals_map() { + std::map class_map; + class_map[0] = "parrot"; + class_map[1] = "dog"; + class_map[2] = "cat"; + class_map[3] = "messi"; + class_map[4] = "bird"; + class_map[5] = "condor"; + class_map[6] = "panda"; + + return class_map; } -std::vector classes_increasing_offset(unsigned nb, unsigned offset) -{ - std::vector classes(nb, 0); +std::vector classes_increasing_offset(unsigned nb, unsigned offset) { + std::vector classes(nb, 0); - for (int i = 0; i < nb/offset; ++i) { - for (int j = 0; j < offset; ++j) { - classes[i*offset + j] = i; - } + for (int i = 0; i < nb / offset; ++i) { + for (int j = 0; j < offset; ++j) { + classes[i * offset + j] = i; } + } - return classes; + return classes; } -std::vector get_engines() -{ - std::vector engs; - engs.push_back(VCL::FaissFlat); - engs.push_back(VCL::FaissIVFFlat); - engs.push_back(VCL::TileDBDense); - engs.push_back(VCL::TileDBSparse); - //engs.push_back(VCL::Flinng); - //FLINNG only supports normalized dataset - //disable general tests until support for arbitrary datasets is added - - return engs; +std::vector get_engines() { + std::vector engs; + engs.push_back(VCL::FaissFlat); + engs.push_back(VCL::FaissIVFFlat); + engs.push_back(VCL::TileDBDense); + engs.push_back(VCL::TileDBSparse); + // engs.push_back(VCL::Flinng); + // FLINNG only supports normalized dataset + // disable general tests until support for arbitrary datasets is added + + return engs; } -std::list get_dimensions_list() -{ - // std::list dims = {64, 97, 128, 256, 300, 453, 1000, 1024, 2045}; - // std::list dims = {128, 300, 453, 1024}; - // std::list dims = {128, 300, 453}; - // std::list dims = {128, 255}; - std::list dims = {128}; +std::list get_dimensions_list() { + // std::list dims = {64, 97, 128, 256, 300, 453, 1000, 1024, 2045}; + // std::list dims = {128, 300, 453, 1024}; + // std::list dims = {128, 300, 453}; + // std::list dims = {128, 255}; + std::list dims = {128}; - return dims; + return dims; } diff --git a/tests/unit_tests/helpers.h b/tests/unit_tests/helpers.h index 7302fea6..f106aa9c 100644 --- a/tests/unit_tests/helpers.h +++ b/tests/unit_tests/helpers.h @@ -35,35 +35,44 @@ #include #include +#include +#include #include #include #include -#include -#include #include "vcl/VCL.h" // Image / Video Helpers -void compare_mat_mat(cv::Mat& cv_img, cv::Mat& img, float error = 0.0); +void compare_mat_mat(cv::Mat &cv_img, cv::Mat &img, float error = 0.0); void compare_cvcapture_cvcapture(cv::VideoCapture v1, cv::VideoCapture v2); // Descriptors Helpers -void generate_desc_linear_increase(int d, int nb, float* xb, float init = 0); +void generate_desc_linear_increase(int d, int nb, float *xb, float init = 0); -float* generate_desc_linear_increase(int d, int nb, float init = 0); +float *generate_desc_linear_increase(int d, int nb, float init = 0); -void generate_desc_normal_cluster(int d, int nb, float* xb, float init = 0, int cluster_size=5, float clusterhead_std=1.0, float cluster_std=0.1); +void generate_desc_normal_cluster(int d, int nb, float *xb, float init = 0, + int cluster_size = 5, + float clusterhead_std = 1.0, + float cluster_std = 0.1); -float* generate_desc_normal_cluster(int d, int nb, float init = 0, int cluster_size=5, float clusterhead_std=1.0, float cluster_std=0.1); +float *generate_desc_normal_cluster(int d, int nb, float init = 0, + int cluster_size = 5, + float clusterhead_std = 1.0, + float cluster_std = 0.1); -void create_additional_neighbors(int d, int cluster_increment, int n_clusters, float* cluster_heads, float cluster_std, float *neighbors); +void create_additional_neighbors(int d, int cluster_increment, int n_clusters, + float *cluster_heads, float cluster_std, + float *neighbors); -float* create_additional_neighbors(int d, int cluster_increment, int n_clusters, float* cluster_heads, float cluster_std); +float *create_additional_neighbors(int d, int cluster_increment, int n_clusters, + float *cluster_heads, float cluster_std); -void check_arrays_float(float* a, float* b, int d); +void check_arrays_float(float *a, float *b, int d); std::map animals_map(); diff --git a/tests/unit_tests/meta_data.cc b/tests/unit_tests/meta_data.cc index e4f51340..7896d4f3 100644 --- a/tests/unit_tests/meta_data.cc +++ b/tests/unit_tests/meta_data.cc @@ -1,380 +1,385 @@ #include "meta_data_helper.h" -Meta_Data::Meta_Data(){ - +Meta_Data::Meta_Data() {} + +Json::Value Meta_Data::construct_Flinng_Set(std::string &name, int &dim) { + + Json::Value descriptor_set; + Json::Value set_query; + Json::Value tuple; + descriptor_set["name"] = name; + descriptor_set["dimensions"] = dim; + descriptor_set["metric"] = "IP"; + descriptor_set["engine"] = "Flinng"; + descriptor_set["flinng_num_rows"] = 3; + descriptor_set["flinng_cells_per_row"] = 100; + descriptor_set["flinng_num_hash_tables"] = 12; + descriptor_set["flinng_hashes_per_table"] = 10; + descriptor_set["flinng_sub_hash_bits"] = 2; + descriptor_set["flinng_cut_off"] = 6; + set_query["AddDescriptorSet"] = descriptor_set; + + return set_query; } -Json::Value Meta_Data::construct_Flinng_Set( std::string& name, int& dim ){ - - Json::Value descriptor_set; - Json::Value set_query; - Json::Value tuple; - descriptor_set["name"] = name ; - descriptor_set["dimensions"] = dim; - descriptor_set["metric"] ="IP"; - descriptor_set["engine"]="Flinng"; - descriptor_set["flinng_num_rows"]=3; - descriptor_set["flinng_cells_per_row"]=100; - descriptor_set["flinng_num_hash_tables"]=12; - descriptor_set["flinng_hashes_per_table"]=10; - descriptor_set["flinng_sub_hash_bits"]=2; - descriptor_set["flinng_cut_off"]=6; - set_query["AddDescriptorSet"] = descriptor_set; - - return set_query; - +Json::Value Meta_Data::construct_flinng_descriptor() { + Json::Value tuple; + std::shared_ptr test_aclient; + std::string name = "flinng_test_2060"; + int dim = 100; + tuple.append(construct_Flinng_Set(name, dim)); + test_aclient.reset(new VDMS::VDMSClient(get_server(), get_port())); + VDMS::Response response = test_aclient->query(_fastwriter.write(tuple)); + Json::Value result; + _reader.parse(response.json.c_str(), result); + Json::Value AddDesc; + Json::Value Desc; + + Desc["set"] = "flinng_test_2060"; + Desc["label"] = "Person"; + Desc["_ref"] = 1; + Desc["properties"]["id"] = 123; + Desc["properties"]["name"] = "Ali"; + AddDesc["AddDescriptor"] = Desc; + tuple.append(AddDesc); + return tuple; } -Json::Value Meta_Data::construct_flinng_descriptor(){ - Json::Value tuple; - std::shared_ptr test_aclient; - std::string name="flinng_test_2060"; - int dim =100; - tuple.append(construct_Flinng_Set(name, dim)); - test_aclient.reset ( new VDMS::VDMSClient(get_server(), get_port())); - VDMS::Response response =test_aclient->query(_fastwriter.write(tuple)); - Json::Value result; - _reader.parse(response.json.c_str(), result); - Json::Value AddDesc; - Json::Value Desc; - - Desc["set"] ="flinng_test_2060"; - Desc["label"] ="Person"; - Desc["_ref"]=1; - Desc["properties"]["id"]=123; - Desc["properties"]["name"]="Ali"; - AddDesc["AddDescriptor"] = Desc; - tuple.append(AddDesc); - return tuple; +Json::Value Meta_Data::construct_descriptor() { + Json::Value descriptor_set; + Json::Value set_query; + Json::Value tuple; + std::shared_ptr test_aclient; + descriptor_set["name"] = "features_vectors_store1"; + descriptor_set["dimensions"] = 1000; + set_query["AddDescriptorSet"] = descriptor_set; + tuple.append(set_query); + test_aclient.reset(new VDMS::VDMSClient(get_server(), get_port())); + VDMS::Response response = test_aclient->query(_fastwriter.write(tuple)); + Json::Value result; + _reader.parse(response.json.c_str(), result); + Json::Value AddDesc; + Json::Value Desc; + + Desc["set"] = "features_vectors_store1"; + Desc["label"] = "Person"; + Desc["_ref"] = 1; + Desc["properties"]["id"] = 123; + Desc["properties"]["name"] = "Ali"; + AddDesc["AddDescriptor"] = Desc; + tuple.append(AddDesc); + return tuple; } -Json::Value Meta_Data::construct_descriptor(){ - Json::Value descriptor_set; - Json::Value set_query; - Json::Value tuple; - std::shared_ptr test_aclient; - descriptor_set["name"] = "features_vectors_store1"; - descriptor_set["dimensions"] = 1000; - set_query["AddDescriptorSet"] = descriptor_set; - tuple.append(set_query); - test_aclient.reset ( new VDMS::VDMSClient(get_server(), get_port())); - VDMS::Response response =test_aclient->query(_fastwriter.write(tuple)); - Json::Value result; - _reader.parse(response.json.c_str(), result); - Json::Value AddDesc; - Json::Value Desc; - - Desc["set"] ="features_vectors_store1"; - Desc["label"] ="Person"; - Desc["_ref"]=1; - Desc["properties"]["id"]=123; - Desc["properties"]["name"]="Ali"; - AddDesc["AddDescriptor"] = Desc; - tuple.append(AddDesc); - return tuple; - +Json::Value Meta_Data::construct_find_descriptor() { + Json::Value FindDesc; + Json::Value Desc; + Json::Value tuple; + // Desc["results"]["count"] = ""; + // Desc["constraints"]["id"][0] =">="; + // Desc["constraints"]["id"][1] =100; + Desc["results"]["list"][0] = "_distance"; + Desc["results"]["list"][1] = "id"; + Desc["set"] = "features_vectors_store1"; + Desc["k_neighbors"] = 5; + // Desc["blob"] =true; + FindDesc["FindDescriptor"] = Desc; + tuple.append(FindDesc); + FindDesc.clear(); + Desc.clear(); + return tuple; } -Json::Value Meta_Data::construct_find_descriptor() -{ - Json::Value FindDesc; - Json::Value Desc; - Json::Value tuple; - // Desc["results"]["count"] = ""; - // Desc["constraints"]["id"][0] =">="; - // Desc["constraints"]["id"][1] =100; - Desc["results"]["list"][0] = "_distance"; - Desc["results"]["list"][1] = "id"; - Desc["set"]= "features_vectors_store1"; - Desc["k_neighbors"]=5; - // Desc["blob"] =true; - FindDesc["FindDescriptor"] = Desc; - tuple.append(FindDesc); - FindDesc.clear(); - Desc.clear(); - return tuple; +Json::Value Meta_Data::construct_find_flinng_descriptor() { + Json::Value FindDesc; + Json::Value Desc; + Json::Value tuple; + Desc["results"]["list"][0] = "_distance"; + Desc["results"]["list"][1] = "id"; + Desc["set"] = "flinng_test_2060"; + Desc["k_neighbors"] = 5; + // Desc["blob"] =true; + FindDesc["FindDescriptor"] = Desc; + tuple.append(FindDesc); + FindDesc.clear(); + Desc.clear(); + return tuple; } -Json::Value Meta_Data::construct_find_flinng_descriptor() -{ - Json::Value FindDesc; - Json::Value Desc; - Json::Value tuple; - Desc["results"]["list"][0] = "_distance"; - Desc["results"]["list"][1] = "id"; - Desc["set"]= "flinng_test_2060"; - Desc["k_neighbors"]=5; - // Desc["blob"] =true; - FindDesc["FindDescriptor"] = Desc; - tuple.append(FindDesc); - FindDesc.clear(); - Desc.clear(); - return tuple; +Json::Value Meta_Data::constuct_image(bool add_operation, + Json::Value operations) { + + Json::Value image; + Json::Value add_image; + Json::Value tuple; + image["properties"]["Name"] = "sample-image"; + image["properties"]["ID"] = 1; + image["format"] = "png"; + image["_ref"] = 12; + if (add_operation) { + image["operations"] = operations; + } + add_image["AddImage"] = image; + tuple.append(add_image); + return tuple; } -Json::Value Meta_Data::constuct_image(bool add_operation, Json::Value operations){ - - Json::Value image; - Json::Value add_image; - Json::Value tuple; - image["properties"]["Name"]="sample-image"; - image["properties"]["ID"]=1; - image["format"]="png"; - image["_ref"]=12; - if( add_operation) - { - image["operations"]=operations; - } - add_image["AddImage"]=image; - tuple.append(add_image); - return tuple; - } - - Json::Value Meta_Data::constuct_video(bool add_operation){ - - Json::Value video; - Json::Value add_video; - Json::Value tuple; - video["properties"]["Name"]="sample-video"; - video["properties"]["ID"]=1; - video["container"]="avi"; - video["codec"]="xvid"; - // video["_ref"]=1209; - // if( add_operation) - // { - // video["operations"]=operations; - // } - add_video["AddVideo"]=video; - tuple.append(add_video); - return tuple; +Json::Value Meta_Data::constuct_video(bool add_operation) { + + Json::Value video; + Json::Value add_video; + Json::Value tuple; + video["properties"]["Name"] = "sample-video"; + video["properties"]["ID"] = 1; + video["container"] = "avi"; + video["codec"] = "xvid"; + // video["_ref"]=1209; + // if( add_operation) + // { + // video["operations"]=operations; + // } + add_video["AddVideo"] = video; + tuple.append(add_video); + return tuple; } -Json::Value Meta_Data::construct_find_image(){ - Json::Value tuple; +Json::Value Meta_Data::construct_find_image() { + Json::Value tuple; + + Json::Value cons; + cons["Name"][0] = "=="; + cons["Name"][1] = "sample-image"; - Json::Value cons; - cons["Name"][0] = "=="; - cons["Name"][1] = "sample-image"; + Json::Value results; + results["blob"] = false; + results["list"][0] = "Name"; + results["list"][1] = "ID"; - Json::Value results; - results["blob"] = false; - results["list"][0] = "Name"; - results["list"][1] = "ID"; + Json::Value image; + image["_ref"] = 1; + image["constraints"] = cons; + image["results"] = results; - Json::Value image; - image["_ref"]=1; - image["constraints"] = cons; - image["results"]=results; + Json::Value find_image; + find_image["FindImage"] = image; - Json::Value find_image; - find_image["FindImage"]=image; + tuple.append(find_image); + return tuple; +} - tuple.append(find_image); - return tuple; +Json::Value Meta_Data::construct_find_image_withop(Json::Value operations) { + Json::Value tuple; + Json::Value results; + results["blob"] = true; -} + Json::Value image; + image["results"] = results; + image["operations"] = operations; -std::string* Meta_Data::read_blob(std::string& fname){ - std::string video; - std::ifstream video_file(fname, - std::ios::in | std::ios::binary | std::ios::ate); + Json::Value find_image; + find_image["FindImage"] = image; - video.resize(video_file.tellg()); + tuple.append(find_image); + return tuple; +} - video_file.seekg(0, std::ios::beg); - if( !video_file.read(&video[ 0 ], video.size())) - std::cout << "error" << std::endl; - std::string* bytes_str =new std::string(video); - // std::cout << *bytes_str < +#include #include #include -#include #include #include -#include +#include +#include #include -#include #include +#include #include -#include -#include -#include "vcl/VCL.h" #include "VDMSClient.h" #include "helpers.h" +#include "vcl/VCL.h" #include "gtest/gtest.h" +class Meta_Data { +public: + std::shared_ptr _aclient; + std::string _server_name = "localhost"; + int _port = 55558; -class Meta_Data{ - public: - std::shared_ptr _aclient; - std::string _server_name="localhost"; - int _port =55558; - - Json::FastWriter _fastwriter; - Json::Reader _reader; - Json::Value _result; - - Meta_Data (); + Json::FastWriter _fastwriter; + Json::Reader _reader; + Json::Value _result; + Meta_Data(); - Json::Value construct_add_query(int ref, bool const_on, bool experiation); - Json::Value construct_add_area(int ref, bool const_on); - Json::Value construct_add_connection(int ref1, int ref2, bool const_on); - Json::Value construct_find_entity(bool ,bool ); - Json::Value constuct_BB(bool); - Json::Value construct_Blob(); - Json::Value construct_updateBlob(); - Json::Value construct_findBlob(); - std::string* read_blob(std::string&); - Json::Value constuct_image(bool =false, Json::Value operations={}); - Json::Value constuct_video(bool =false); - Json::Value construct_find_image(); - Json::Value construct_descriptor(); - Json::Value construct_find_descriptor(); - Json::Value construct_flinng_descriptor(); - Json::Value construct_find_flinng_descriptor(); - Json::Value construct_Flinng_Set(std::string&, int&); - std::string get_server(){return _server_name;} - int get_port() {return _port;} + Json::Value construct_add_query(int ref, bool const_on, bool experiation); + Json::Value construct_add_area(int ref, bool const_on); + Json::Value construct_add_connection(int ref1, int ref2, bool const_on); + Json::Value construct_find_entity(bool, bool); + Json::Value constuct_BB(bool); + Json::Value construct_Blob(); + Json::Value construct_updateBlob(); + Json::Value construct_findBlob(); + std::string *read_blob(std::string &); + Json::Value constuct_image(bool = false, Json::Value operations = {}); + Json::Value constuct_video(bool = false); + Json::Value construct_find_image(); + Json::Value construct_find_image_withop(Json::Value operations); + Json::Value construct_descriptor(); + Json::Value construct_find_descriptor(); + Json::Value construct_flinng_descriptor(); + Json::Value construct_find_flinng_descriptor(); + Json::Value construct_Flinng_Set(std::string &, int &); + std::string get_server() { return _server_name; } + int get_port() { return _port; } }; diff --git a/tests/unit_tests/pmgd_queries.cc b/tests/unit_tests/pmgd_queries.cc index bc42a283..7ef8b4ae 100644 --- a/tests/unit_tests/pmgd_queries.cc +++ b/tests/unit_tests/pmgd_queries.cc @@ -32,12 +32,12 @@ #include #include +#include "PMGDQueryHandler.h" #include "VDMSConfig.h" -#include "pmgdMessages.pb.h" // Protobuff implementation #include "pmgd.h" -#include "PMGDQueryHandler.h" +#include "pmgdMessages.pb.h" // Protobuff implementation -#include /* system, NULL, EXIT_FAILURE */ +#include /* system, NULL, EXIT_FAILURE */ using namespace PMGD; using namespace VDMS; @@ -47,2023 +47,2051 @@ using namespace std; #define FEMALE 1 void add_patient(protobufs::Command &cmdadd, int id, string name, int age, - string dob, string email, int sex) -{ - cmdadd.set_cmd_id(protobufs::Command::AddNode); - protobufs::AddNode *an = cmdadd.mutable_add_node(); - an->set_identifier(id); - protobufs::Node *n = an->mutable_node(); - n->set_tag("Patient"); - protobufs::Property *p = n->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Name"); - p->set_string_value(name); - p = n->add_properties(); - p->set_type(protobufs::Property::IntegerType); - p->set_key("Age"); - p->set_int_value(age); - p = n->add_properties(); + string dob, string email, int sex) { + cmdadd.set_cmd_id(protobufs::Command::AddNode); + protobufs::AddNode *an = cmdadd.mutable_add_node(); + an->set_identifier(id); + protobufs::Node *n = an->mutable_node(); + n->set_tag("Patient"); + protobufs::Property *p = n->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("Name"); + p->set_string_value(name); + p = n->add_properties(); + p->set_type(protobufs::Property::IntegerType); + p->set_key("Age"); + p->set_int_value(age); + p = n->add_properties(); + p->set_type(protobufs::Property::TimeType); + p->set_key("Birthday"); + p->set_time_value(dob); + p = n->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("Email"); + p->set_string_value(email); + p = n->add_properties(); + p->set_type(protobufs::Property::IntegerType); + p->set_key("Sex"); + p->set_int_value(sex); + p = n->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("RemoveViaUpdate"); + p->set_string_value("Random"); +} + +TEST(PMGDQueryHandler, addTest) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, patientid = 1, eid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdadd; + cmdadd.set_tx_id(txid); + add_patient(cmdadd, patientid++, "John Doe", 86, + "Sat Nov 1 18:59:24 PDT 1930", "john.doe@abc.com", MALE); + cmds.push_back(&cmdadd); + query_count++; + + protobufs::Command cmdadd1; + cmdadd1.set_tx_id(txid); + add_patient(cmdadd1, patientid++, "Jane Doe", 80, + "Sat Oct 1 17:59:24 PDT 1936", "jane.doe@abc.com", FEMALE); + cmds.push_back(&cmdadd1); + query_count++; + + protobufs::Command cmdedge1; + cmdedge1.set_tx_id(txid); + cmdedge1.set_cmd_id(protobufs::Command::AddEdge); + protobufs::AddEdge *ae = cmdedge1.mutable_add_edge(); + ae->set_identifier(eid++); + protobufs::Edge *e = ae->mutable_edge(); + e->set_src(1); + e->set_dst(2); + e->set_tag("Married"); + protobufs::Property *p = e->add_properties(); p->set_type(protobufs::Property::TimeType); - p->set_key("Birthday"); - p->set_time_value(dob); - p = n->add_properties(); + p->set_key("Since"); + p->set_time_value("Sat Sep 1 19:59:24 PDT 1956"); + p = e->add_properties(); p->set_type(protobufs::Property::StringType); - p->set_key("Email"); - p->set_string_value(email); - p = n->add_properties(); - p->set_type(protobufs::Property::IntegerType); - p->set_key("Sex"); - p->set_int_value(sex); - p = n->add_properties(); + p->set_key("Status"); + p->set_string_value("Old Adult"); + cmds.push_back(&cmdedge1); + query_count++; + + protobufs::Command cmdadd2; + cmdadd2.set_tx_id(txid); + add_patient(cmdadd2, patientid++, "Alice Crypto", 70, + "Sat Nov 1 17:59:24 PDT 1946", "alice.crypto@xyz.com", FEMALE); + cmds.push_back(&cmdadd2); + query_count++; + + protobufs::Command cmdadd3; + cmdadd3.set_tx_id(txid); + add_patient(cmdadd3, patientid++, "Bob Crypto", 70, + "Sat Nov 30 7:59:24 PDT 1946", "bob.crypto@xyz.com", MALE); + cmds.push_back(&cmdadd3); + query_count++; + + protobufs::Command cmdedge2; + cmdedge2.set_tx_id(txid); + cmdedge2.set_cmd_id(protobufs::Command::AddEdge); + ae = cmdedge2.mutable_add_edge(); + ae->set_identifier(eid++); + e = ae->mutable_edge(); + e->set_src(3); + e->set_dst(4); + e->set_tag("Married"); + p = e->add_properties(); + p->set_type(protobufs::Property::TimeType); + p->set_key("Since"); + p->set_time_value("Wed Dec 2 19:59:24 PDT 1970"); + p = e->add_properties(); p->set_type(protobufs::Property::StringType); - p->set_key("RemoveViaUpdate"); - p->set_string_value("Random"); -} - -TEST(PMGDQueryHandler, addTest) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, patientid = 1, eid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdadd; - cmdadd.set_tx_id(txid); - add_patient(cmdadd, patientid++, "John Doe", 86, "Sat Nov 1 18:59:24 PDT 1930", - "john.doe@abc.com", MALE); - cmds.push_back(&cmdadd); - query_count++; - - protobufs::Command cmdadd1; - cmdadd1.set_tx_id(txid); - add_patient(cmdadd1, patientid++, "Jane Doe", 80, "Sat Oct 1 17:59:24 PDT 1936", - "jane.doe@abc.com", FEMALE); - cmds.push_back(&cmdadd1); - query_count++; - - protobufs::Command cmdedge1; - cmdedge1.set_tx_id(txid); - cmdedge1.set_cmd_id(protobufs::Command::AddEdge); - protobufs::AddEdge *ae = cmdedge1.mutable_add_edge(); - ae->set_identifier(eid++); - protobufs::Edge *e = ae->mutable_edge(); - e->set_src(1); - e->set_dst(2); - e->set_tag("Married"); - protobufs::Property *p = e->add_properties(); - p->set_type(protobufs::Property::TimeType); - p->set_key("Since"); - p->set_time_value("Sat Sep 1 19:59:24 PDT 1956"); - p = e->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Status"); - p->set_string_value("Old Adult"); - cmds.push_back(&cmdedge1); - query_count++; - - protobufs::Command cmdadd2; - cmdadd2.set_tx_id(txid); - add_patient(cmdadd2, patientid++, "Alice Crypto", 70, "Sat Nov 1 17:59:24 PDT 1946", - "alice.crypto@xyz.com", FEMALE); - cmds.push_back(&cmdadd2); - query_count++; - - protobufs::Command cmdadd3; - cmdadd3.set_tx_id(txid); - add_patient(cmdadd3, patientid++, "Bob Crypto", 70, "Sat Nov 30 7:59:24 PDT 1946", - "bob.crypto@xyz.com", MALE); - cmds.push_back(&cmdadd3); - query_count++; - - protobufs::Command cmdedge2; - cmdedge2.set_tx_id(txid); - cmdedge2.set_cmd_id(protobufs::Command::AddEdge); - ae = cmdedge2.mutable_add_edge(); - ae->set_identifier(eid++); - e = ae->mutable_edge(); - e->set_src(3); - e->set_dst(4); - e->set_tag("Married"); - p = e->add_properties(); - p->set_type(protobufs::Property::TimeType); - p->set_key("Since"); - p->set_time_value("Wed Dec 2 19:59:24 PDT 1970"); - p = e->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Status"); - p->set_string_value("Old Adult"); - cmds.push_back(&cmdedge2); - query_count++; - - protobufs::Command cmdtxcommit; - cmdtxcommit.set_cmd_id(protobufs::Command::TxCommit); - cmdtxcommit.set_tx_id(txid); - cmds.push_back(&cmdtxcommit); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, false); - int nodeids = 1, edgeids = 1; - for (int i = 0; i < query_count; ++i) { - vector response = responses[i]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << "Unsuccessful TX"; - if (it->r_type() == protobufs::NodeID) { - long nodeid = it->op_int_value(); - EXPECT_EQ(nodeid, nodeids++) << "Unexpected node id"; - } - else if (it->r_type() == protobufs::EdgeID) { - long edgeid = it->op_int_value(); - EXPECT_EQ(edgeid, edgeids++) << "Unexpected edge id"; - } - } + p->set_key("Status"); + p->set_string_value("Old Adult"); + cmds.push_back(&cmdedge2); + query_count++; + + protobufs::Command cmdtxcommit; + cmdtxcommit.set_cmd_id(protobufs::Command::TxCommit); + cmdtxcommit.set_tx_id(txid); + cmds.push_back(&cmdtxcommit); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, false); + int nodeids = 1, edgeids = 1; + for (int i = 0; i < query_count; ++i) { + vector response = responses[i]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << "Unsuccessful TX"; + if (it->r_type() == protobufs::NodeID) { + long nodeid = it->op_int_value(); + EXPECT_EQ(nodeid, nodeids++) << "Unexpected node id"; + } else if (it->r_type() == protobufs::EdgeID) { + long edgeid = it->op_int_value(); + EXPECT_EQ(edgeid, edgeids++) << "Unexpected edge id"; } + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -void print_property(const string &key, const protobufs::Property &p) -{ +void print_property(const string &key, const protobufs::Property &p) { #ifdef PRINT_PROPERTY - switch(p.type()) { - case protobufs::Property::BooleanType: - printf("key: %s, value: %d\n", key.c_str(), p.bool_value()); - break; - case protobufs::Property::IntegerType: - printf("key: %s, value: %ld\n", key.c_str(), p.int_value()); - break; - case protobufs::Property::StringType: - case protobufs::Property::TimeType: - printf("key: %s, value: %s\n", key.c_str(), p.string_value().c_str()); - break; - case protobufs::Property::FloatType: - printf("key: %s, value: %lf\n", key.c_str(), p.float_value()); - break; - default: - printf("Unknown\n"); - } + switch (p.type()) { + case protobufs::Property::BooleanType: + printf("key: %s, value: %d\n", key.c_str(), p.bool_value()); + break; + case protobufs::Property::IntegerType: + printf("key: %s, value: %ld\n", key.c_str(), p.int_value()); + break; + case protobufs::Property::StringType: + case protobufs::Property::TimeType: + printf("key: %s, value: %s\n", key.c_str(), p.string_value().c_str()); + break; + case protobufs::Property::FloatType: + printf("key: %s, value: %lf\n", key.c_str(), p.float_value()); + break; + default: + printf("Unknown\n"); + } #endif } -TEST(PMGDQueryHandler, queryTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(-1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Email"); - pp->set_op(protobufs::PropertyPredicate::Gt); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Email"); - p->set_string_value("j"); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Email"; - key = qr->add_response_keys(); - *key = "Age"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int nodecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - nodecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - nodecount++; - } - propcount++; - } - } - //printf("\n"); +TEST(PMGDQueryHandler, queryTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(-1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Email"); + pp->set_op(protobufs::PropertyPredicate::Gt); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Email"); + p->set_string_value("j"); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Email"; + key = qr->add_response_keys(); + *key = "Age"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int nodecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + nodecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + nodecount++; } + propcount++; + } } - EXPECT_EQ(nodecount, 2) << "Not enough nodes found"; - EXPECT_EQ(propcount, 2) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(nodecount, 2) << "Not enough nodes found"; + EXPECT_EQ(propcount, 2) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryTestAverage) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(-1); - qc->set_tag("Patient"); - qr->set_r_type(protobufs::Average); - string *key = qr->add_response_keys(); - *key = "Age"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - for (int i = 0; i < query_count; ++i) { - vector response = responses[i]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::Average) { - EXPECT_EQ(it->op_float_value(), 76.5) << "Average didn't match expected for four patients' age"; - } - } +TEST(PMGDQueryHandler, queryTestAverage) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(-1); + qc->set_tag("Patient"); + qr->set_r_type(protobufs::Average); + string *key = qr->add_response_keys(); + *key = "Age"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + for (int i = 0; i < query_count; ++i) { + vector response = responses[i]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::Average) { + EXPECT_EQ(it->op_float_value(), 76.5) + << "Average didn't match expected for four patients' age"; } + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryTestUnique) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmdtx.set_cmd_grp_id(query_count); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - cmdquery.set_cmd_grp_id(query_count); - protobufs::QueryNode *qn = cmdquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(-1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - qc->set_unique(true); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Email"); - pp->set_op(protobufs::PropertyPredicate::Gt); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Email"); - p->set_string_value("j"); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Email"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmdtxend.set_cmd_grp_id(0); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - EXPECT_EQ(responses.size(), 1) << "Expecting an error return situation"; - for (int i = 0; i < responses.size(); ++i) { - vector response = responses[i]; - for (auto it : response) { - if (i == 0) // that's the unique query test - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::NotUnique) << "Was expecting the not unique msg"; - } - } +TEST(PMGDQueryHandler, queryTestUnique) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmdtx.set_cmd_grp_id(query_count); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + cmdquery.set_cmd_grp_id(query_count); + protobufs::QueryNode *qn = cmdquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(-1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + qc->set_unique(true); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Email"); + pp->set_op(protobufs::PropertyPredicate::Gt); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Email"); + p->set_string_value("j"); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Email"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmdtxend.set_cmd_grp_id(0); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + EXPECT_EQ(responses.size(), 1) << "Expecting an error return situation"; + for (int i = 0; i < responses.size(); ++i) { + vector response = responses[i]; + for (auto it : response) { + if (i == 0) // that's the unique query test + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::NotUnique) + << "Was expecting the not unique msg"; + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryNeighborTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Set parameters to find the starting node(s) - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Sex"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Sex"); - p->set_int_value(MALE); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - qn = cmdquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(-1); - protobufs::LinkInfo *qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(1); - qnb->set_e_tag("Married"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - - qc->set_p_op(protobufs::And); - qc->set_tagid(0); - qc->set_unique(false); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Name"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int nodecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - nodecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - nodecount++; - } - propcount++; - } - } - //printf("\n"); +TEST(PMGDQueryHandler, queryNeighborTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Set parameters to find the starting node(s) + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Sex"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Sex"); + p->set_int_value(MALE); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + qn = cmdquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(-1); + protobufs::LinkInfo *qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(1); + qnb->set_e_tag("Married"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + + qc->set_p_op(protobufs::And); + qc->set_tagid(0); + qc->set_unique(false); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Name"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int nodecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + nodecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + nodecount++; } + propcount++; + } } - EXPECT_EQ(nodecount, 2) << "Not enough nodes found"; - EXPECT_EQ(propcount, 1) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(nodecount, 2) << "Not enough nodes found"; + EXPECT_EQ(propcount, 1) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryConditionalNeighborTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Set parameters to find the starting node(s) - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Sex"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Sex"); - p->set_int_value(MALE); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - qn = cmdquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(-1); - protobufs::LinkInfo *qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(1); - qnb->set_e_tag("Married"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - pp = qc->add_predicates(); - pp->set_key("Age"); - pp->set_op(protobufs::PropertyPredicate::Lt); - p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Age"); - p->set_int_value(80); - - qc->set_unique(false); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Name"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int nodecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - nodecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - nodecount++; - } - propcount++; - } - } - //printf("\n"); +TEST(PMGDQueryHandler, queryConditionalNeighborTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Set parameters to find the starting node(s) + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Sex"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Sex"); + p->set_int_value(MALE); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + qn = cmdquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(-1); + protobufs::LinkInfo *qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(1); + qnb->set_e_tag("Married"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + pp = qc->add_predicates(); + pp->set_key("Age"); + pp->set_op(protobufs::PropertyPredicate::Lt); + p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Age"); + p->set_int_value(80); + + qc->set_unique(false); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Name"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int nodecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + nodecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + nodecount++; } + propcount++; + } } - EXPECT_EQ(nodecount, 1) << "Not enough nodes found"; - EXPECT_EQ(propcount, 1) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(nodecount, 1) << "Not enough nodes found"; + EXPECT_EQ(propcount, 1) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryNeighborTestSum) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Set parameters to find the starting node(s) - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - // Set parameters to find the starting node(s) - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - qc->set_unique(false); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Sex"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Sex"); - p->set_int_value(MALE); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - qn = cmdquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(-1); - protobufs::LinkInfo *qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(1); - qnb->set_e_tag("Married"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::Sum); - string *key = qr->add_response_keys(); - *key = "Age"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int nodecount = 0, propcount = 0; - for (int i = 0; i < query_count; ++i) { - vector response = responses[i]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::Sum) { - EXPECT_EQ(it->op_int_value(), 150) << "Sum didn't match expected for two patients' age"; - } - } +TEST(PMGDQueryHandler, queryNeighborTestSum) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Set parameters to find the starting node(s) + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + // Set parameters to find the starting node(s) + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + qc->set_unique(false); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Sex"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Sex"); + p->set_int_value(MALE); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + qn = cmdquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(-1); + protobufs::LinkInfo *qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(1); + qnb->set_e_tag("Married"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::Sum); + string *key = qr->add_response_keys(); + *key = "Age"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int nodecount = 0, propcount = 0; + for (int i = 0; i < query_count; ++i) { + vector response = responses[i]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::Sum) { + EXPECT_EQ(it->op_int_value(), 150) + << "Sum didn't match expected for two patients' age"; } + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, addConstrainedTest) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, patientid = 1, eid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmdtx.set_cmd_grp_id(query_count); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdadd; - cmdadd.set_tx_id(txid); - cmdadd.set_cmd_grp_id(query_count); - add_patient(cmdadd, patientid, "John Doe", 86, "Sat Nov 1 18:59:24 PDT 1930", - "john.doe@abc.com", MALE); - // Add a test to verify this node doesn't exist - protobufs::AddNode *an = cmdadd.mutable_add_node(); - protobufs::QueryNode *qn = an->mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(patientid++); // ref for caching in case found. - qc->set_tag("Patient"); - qc->set_unique(true); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::NodeID); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Email"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Email"); - p->set_string_value("john.doe@abc.com"); - cmds.push_back(&cmdadd); - query_count++; - - protobufs::Command cmdadd1; - cmdadd1.set_tx_id(txid); - cmdadd1.set_cmd_grp_id(query_count); - add_patient(cmdadd1, patientid++, "Janice Doe", 40, "Fri Oct 1 1:59:24 PDT 1976", - "janice.doe@abc.com", FEMALE); - cmds.push_back(&cmdadd1); - query_count++; - - protobufs::Command cmdedge1; - cmdedge1.set_tx_id(txid); - cmdedge1.set_cmd_id(protobufs::Command::AddEdge); - cmdedge1.set_cmd_grp_id(query_count); - protobufs::AddEdge *ae = cmdedge1.mutable_add_edge(); - ae->set_identifier(eid++); - protobufs::Edge *e = ae->mutable_edge(); - e->set_src(1); - e->set_dst(2); - e->set_tag("Daughter"); - p = e->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Status"); - p->set_string_value("Young Adult"); - cmds.push_back(&cmdedge1); - query_count++; - - protobufs::Command cmdtxcommit; - cmdtxcommit.set_cmd_id(protobufs::Command::TxCommit); - cmdtxcommit.set_tx_id(txid); - cmdtxcommit.set_cmd_grp_id(0); - cmds.push_back(&cmdtxcommit); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, false); - - // Since PMGD queries always generate one response per command, - // we can do the following: - protobufs::CommandResponse *resp = responses[0][0]; // TxBegin - EXPECT_EQ(resp->error_code(), protobufs::CommandResponse::Success) << "Unsuccessful TX"; - resp = responses[1][0]; // Conditional add - EXPECT_EQ(resp->error_code(), protobufs::CommandResponse::Exists) << resp->error_msg(); - EXPECT_EQ(resp->op_int_value(), 1) << "Unexpected node id for conditional add"; - resp = responses[2][0]; // Regular add - EXPECT_EQ(resp->error_code(), protobufs::CommandResponse::Success) << resp->error_msg(); - EXPECT_EQ(resp->op_int_value(), 5) << "Unexpected node id for add"; - resp = responses[3][0]; // Regular add edge - EXPECT_EQ(resp->error_code(), protobufs::CommandResponse::Success) << resp->error_msg(); - EXPECT_EQ(resp->op_int_value(), 3) << "Unexpected edge id for add"; - } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); +TEST(PMGDQueryHandler, addConstrainedTest) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, patientid = 1, eid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmdtx.set_cmd_grp_id(query_count); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdadd; + cmdadd.set_tx_id(txid); + cmdadd.set_cmd_grp_id(query_count); + add_patient(cmdadd, patientid, "John Doe", 86, + "Sat Nov 1 18:59:24 PDT 1930", "john.doe@abc.com", MALE); + // Add a test to verify this node doesn't exist + protobufs::AddNode *an = cmdadd.mutable_add_node(); + protobufs::QueryNode *qn = an->mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(patientid++); // ref for caching in case found. + qc->set_tag("Patient"); + qc->set_unique(true); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::NodeID); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Email"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Email"); + p->set_string_value("john.doe@abc.com"); + cmds.push_back(&cmdadd); + query_count++; + + protobufs::Command cmdadd1; + cmdadd1.set_tx_id(txid); + cmdadd1.set_cmd_grp_id(query_count); + add_patient(cmdadd1, patientid++, "Janice Doe", 40, + "Fri Oct 1 1:59:24 PDT 1976", "janice.doe@abc.com", FEMALE); + cmds.push_back(&cmdadd1); + query_count++; + + protobufs::Command cmdedge1; + cmdedge1.set_tx_id(txid); + cmdedge1.set_cmd_id(protobufs::Command::AddEdge); + cmdedge1.set_cmd_grp_id(query_count); + protobufs::AddEdge *ae = cmdedge1.mutable_add_edge(); + ae->set_identifier(eid++); + protobufs::Edge *e = ae->mutable_edge(); + e->set_src(1); + e->set_dst(2); + e->set_tag("Daughter"); + p = e->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("Status"); + p->set_string_value("Young Adult"); + cmds.push_back(&cmdedge1); + query_count++; + + protobufs::Command cmdtxcommit; + cmdtxcommit.set_cmd_id(protobufs::Command::TxCommit); + cmdtxcommit.set_tx_id(txid); + cmdtxcommit.set_cmd_grp_id(0); + cmds.push_back(&cmdtxcommit); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, false); + + // Since PMGD queries always generate one response per command, + // we can do the following: + protobufs::CommandResponse *resp = responses[0][0]; // TxBegin + EXPECT_EQ(resp->error_code(), protobufs::CommandResponse::Success) + << "Unsuccessful TX"; + resp = responses[1][0]; // Conditional add + EXPECT_EQ(resp->error_code(), protobufs::CommandResponse::Exists) + << resp->error_msg(); + EXPECT_EQ(resp->op_int_value(), 1) + << "Unexpected node id for conditional add"; + resp = responses[2][0]; // Regular add + EXPECT_EQ(resp->error_code(), protobufs::CommandResponse::Success) + << resp->error_msg(); + EXPECT_EQ(resp->op_int_value(), 5) << "Unexpected node id for add"; + resp = responses[3][0]; // Regular add edge + EXPECT_EQ(resp->error_code(), protobufs::CommandResponse::Success) + << resp->error_msg(); + EXPECT_EQ(resp->op_int_value(), 3) << "Unexpected edge id for add"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryNeighborLinksTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Set parameters to find the starting node(s) - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Sex"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Sex"); - p->set_int_value(FEMALE); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - qn = cmdquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(2); - protobufs::LinkInfo *qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(1); - qnb->set_e_tag("Married"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - qc->set_tagid(0); - qc->set_unique(false); - qc->set_p_op(protobufs::And); - cmds.push_back(&cmdquery); - query_count++; - - protobufs::Command cmdfollquery; - cmdfollquery.set_cmd_id(protobufs::Command::QueryNode); - cmdfollquery.set_tx_id(txid); - qn = cmdfollquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(-1); - qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(2); - qnb->set_e_tag("Daughter"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - qc->set_tagid(0); - qc->set_unique(false); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Name"; - cmds.push_back(&cmdfollquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int nodecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - nodecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - nodecount++; - } - propcount++; - } - } - //printf("\n"); +TEST(PMGDQueryHandler, queryNeighborLinksTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Set parameters to find the starting node(s) + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Sex"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Sex"); + p->set_int_value(FEMALE); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + qn = cmdquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(2); + protobufs::LinkInfo *qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(1); + qnb->set_e_tag("Married"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + qc->set_tagid(0); + qc->set_unique(false); + qc->set_p_op(protobufs::And); + cmds.push_back(&cmdquery); + query_count++; + + protobufs::Command cmdfollquery; + cmdfollquery.set_cmd_id(protobufs::Command::QueryNode); + cmdfollquery.set_tx_id(txid); + qn = cmdfollquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(-1); + qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(2); + qnb->set_e_tag("Daughter"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + qc->set_tagid(0); + qc->set_unique(false); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Name"; + cmds.push_back(&cmdfollquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int nodecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + nodecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + nodecount++; } + propcount++; + } } - EXPECT_EQ(nodecount, 1) << "Not enough nodes found"; - EXPECT_EQ(propcount, 1) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(nodecount, 1) << "Not enough nodes found"; + EXPECT_EQ(propcount, 1) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryNeighborLinksReuseTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Set parameters to find the starting node(s) - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Sex"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Sex"); - p->set_int_value(FEMALE); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Email"; - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - qn = cmdquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(2); - protobufs::LinkInfo *qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(1); - qnb->set_e_tag("Married"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - qc->set_tagid(0); - qc->set_unique(false); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::Count); - cmds.push_back(&cmdquery); - query_count++; - - protobufs::Command cmdfollquery; - cmdfollquery.set_cmd_id(protobufs::Command::QueryNode); - cmdfollquery.set_tx_id(txid); - qn = cmdfollquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(-1); - qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(2); - qnb->set_e_tag("Daughter"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - qc->set_tagid(0); - qc->set_unique(false); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::List); - key = qr->add_response_keys(); - *key = "Name"; - key = qr->add_response_keys(); - *key = "Email"; - cmds.push_back(&cmdfollquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int nodecount = 0, propcount = 0; - int totnodecount = 0, totpropcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - propcount = 0; - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - nodecount = 0; - propcount++; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - nodecount++; - } - } - totpropcount += propcount; - totnodecount += nodecount; - } - if (it->r_type() == protobufs::Count) { - EXPECT_EQ(it->op_int_value(), 2) << "Doesn't match expected count"; - } - // printf("\n"); +TEST(PMGDQueryHandler, queryNeighborLinksReuseTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Set parameters to find the starting node(s) + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Sex"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Sex"); + p->set_int_value(FEMALE); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Email"; + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + qn = cmdquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(2); + protobufs::LinkInfo *qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(1); + qnb->set_e_tag("Married"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + qc->set_tagid(0); + qc->set_unique(false); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::Count); + cmds.push_back(&cmdquery); + query_count++; + + protobufs::Command cmdfollquery; + cmdfollquery.set_cmd_id(protobufs::Command::QueryNode); + cmdfollquery.set_tx_id(txid); + qn = cmdfollquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(-1); + qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(2); + qnb->set_e_tag("Daughter"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + qc->set_tagid(0); + qc->set_unique(false); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::List); + key = qr->add_response_keys(); + *key = "Name"; + key = qr->add_response_keys(); + *key = "Email"; + cmds.push_back(&cmdfollquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int nodecount = 0, propcount = 0; + int totnodecount = 0, totpropcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + propcount = 0; + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + nodecount = 0; + propcount++; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + nodecount++; } + } + totpropcount += propcount; + totnodecount += nodecount; + } + if (it->r_type() == protobufs::Count) { + EXPECT_EQ(it->op_int_value(), 2) << "Doesn't match expected count"; } - EXPECT_EQ(nodecount, 1) << "Not enough nodes found"; - EXPECT_EQ(propcount, 2) << "Not enough properties read"; - EXPECT_EQ(totnodecount, 4) << "Not enough total nodes found"; - EXPECT_EQ(totpropcount, 3) << "Not enough total properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(nodecount, 1) << "Not enough nodes found"; + EXPECT_EQ(propcount, 2) << "Not enough properties read"; + EXPECT_EQ(totnodecount, 4) << "Not enough total nodes found"; + EXPECT_EQ(totpropcount, 3) << "Not enough total properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, querySortedNeighborLinksReuseTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Set parameters to find the starting node(s) - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Sex"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Sex"); - p->set_int_value(FEMALE); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Email"; - qr->set_sort(true); - qr->set_sort_key("Email"); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - qn = cmdquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(2); - protobufs::LinkInfo *qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(1); - qnb->set_e_tag("Married"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - qc->set_tagid(0); - qc->set_unique(false); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::Count); - cmds.push_back(&cmdquery); - query_count++; - - protobufs::Command cmdfollquery; - cmdfollquery.set_cmd_id(protobufs::Command::QueryNode); - cmdfollquery.set_tx_id(txid); - qn = cmdfollquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(-1); - qnb = qn->mutable_link(); - // Now set parameters for neighbor traversal - qnb->set_start_identifier(2); - qnb->set_e_tag("Daughter"); - qnb->set_dir(protobufs::LinkInfo::Any); - qnb->set_nb_unique(false); - qc->set_tagid(0); - qc->set_unique(false); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::List); - key = qr->add_response_keys(); - *key = "Name"; - key = qr->add_response_keys(); - *key = "Email"; - cmds.push_back(&cmdfollquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int nodecount = 0, propcount = 0; - int totnodecount = 0, totpropcount = 0; - bool firstquery = true; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - propcount = 0; - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - nodecount = 0; - propcount++; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - nodecount++; - } - if (firstquery) { - firstquery = false; - EXPECT_EQ(p.values(0).string_value(), "alice.crypto@xyz.com") << "Sorting didn't work"; - } - } - totpropcount += propcount; - totnodecount += nodecount; - } - if (it->r_type() == protobufs::Count) { - EXPECT_EQ(it->op_int_value(), 2) << "Doesn't match expected count"; - } - // printf("\n"); +TEST(PMGDQueryHandler, querySortedNeighborLinksReuseTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Set parameters to find the starting node(s) + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Sex"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Sex"); + p->set_int_value(FEMALE); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Email"; + qr->set_sort(true); + qr->set_sort_key("Email"); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + qn = cmdquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(2); + protobufs::LinkInfo *qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(1); + qnb->set_e_tag("Married"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + qc->set_tagid(0); + qc->set_unique(false); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::Count); + cmds.push_back(&cmdquery); + query_count++; + + protobufs::Command cmdfollquery; + cmdfollquery.set_cmd_id(protobufs::Command::QueryNode); + cmdfollquery.set_tx_id(txid); + qn = cmdfollquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(-1); + qnb = qn->mutable_link(); + // Now set parameters for neighbor traversal + qnb->set_start_identifier(2); + qnb->set_e_tag("Daughter"); + qnb->set_dir(protobufs::LinkInfo::Any); + qnb->set_nb_unique(false); + qc->set_tagid(0); + qc->set_unique(false); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::List); + key = qr->add_response_keys(); + *key = "Name"; + key = qr->add_response_keys(); + *key = "Email"; + cmds.push_back(&cmdfollquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int nodecount = 0, propcount = 0; + int totnodecount = 0, totpropcount = 0; + bool firstquery = true; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + propcount = 0; + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + nodecount = 0; + propcount++; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + nodecount++; + } + if (firstquery) { + firstquery = false; + EXPECT_EQ(p.values(0).string_value(), "alice.crypto@xyz.com") + << "Sorting didn't work"; } + } + totpropcount += propcount; + totnodecount += nodecount; } - EXPECT_EQ(nodecount, 1) << "Not enough nodes found"; - EXPECT_EQ(propcount, 2) << "Not enough properties read"; - EXPECT_EQ(totnodecount, 4) << "Not enough total nodes found"; - EXPECT_EQ(totpropcount, 3) << "Not enough total properties read"; + if (it->r_type() == protobufs::Count) { + EXPECT_EQ(it->op_int_value(), 2) << "Doesn't match expected count"; + } + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(nodecount, 1) << "Not enough nodes found"; + EXPECT_EQ(propcount, 2) << "Not enough properties read"; + EXPECT_EQ(totnodecount, 4) << "Not enough total nodes found"; + EXPECT_EQ(totpropcount, 3) << "Not enough total properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryTestListLimit) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(-1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Email"; - key = qr->add_response_keys(); - *key = "Age"; - qr->set_limit(4); - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int nodecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - nodecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - nodecount++; - } - propcount++; - } - } - //printf("\n"); +TEST(PMGDQueryHandler, queryTestListLimit) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(-1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Email"; + key = qr->add_response_keys(); + *key = "Age"; + qr->set_limit(4); + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int nodecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + nodecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + nodecount++; } + propcount++; + } } - EXPECT_EQ(nodecount, 4) << "Incorrect number of nodes found"; - EXPECT_EQ(propcount, 2) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(nodecount, 4) << "Incorrect number of nodes found"; + EXPECT_EQ(propcount, 2) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryTestSortedLimitedAverage) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryNode); - cmdquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(-1); - qc->set_tag("Patient"); - qr->set_r_type(protobufs::Average); - string *key = qr->add_response_keys(); - *key = "Age"; - qr->set_sort(true); - qr->set_sort_key("Email"); - // Average over 5 patients age is 69.2 - qr->set_limit(3); - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - for (int i = 0; i < query_count; ++i) { - vector response = responses[i]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::Average) { - EXPECT_EQ(static_cast(it->op_float_value()), 73) << "Average didn't match expected for three middle patients' age"; - } - } +TEST(PMGDQueryHandler, queryTestSortedLimitedAverage) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryNode); + cmdquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(-1); + qc->set_tag("Patient"); + qr->set_r_type(protobufs::Average); + string *key = qr->add_response_keys(); + *key = "Age"; + qr->set_sort(true); + qr->set_sort_key("Email"); + // Average over 5 patients age is 69.2 + qr->set_limit(3); + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + for (int i = 0; i < query_count; ++i) { + vector response = responses[i]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::Average) { + EXPECT_EQ(static_cast(it->op_float_value()), 73) + << "Average didn't match expected for three middle patients' age"; } + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryUpdateTest) -{ - //printf("Testing PMGD query protobuf handler for list return of neighbors with constraints\n"); - - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Set parameters to find the starting node(s) - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Sex"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Sex"); - p->set_int_value(MALE); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdupdate; - cmdupdate.set_cmd_id(protobufs::Command::UpdateNode); - cmdupdate.set_tx_id(txid); - protobufs::UpdateNode *un = cmdupdate.mutable_update_node(); - - // The identifier here will be the identifier used for search - // since we are going to update properties of the nodes found - // in the previous search - un->set_identifier(qn->identifier()); - p = un->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Hospital"); - p->set_string_value("Kaiser1"); - p = un->add_properties(); - p->set_type(protobufs::Property::BooleanType); - p->set_key("Treated"); - p->set_bool_value(true); - - // Remove the extra properties - un->add_remove_props("RemoveViaUpdate"); - - cmds.push_back(&cmdupdate); - query_count++; - - // Also make sure the removed property doesn't show up anymore - protobufs::Command cmdcheckquery; - cmdcheckquery.set_cmd_id(protobufs::Command::QueryNode); - cmdcheckquery.set_tx_id(txid); - qn = cmdcheckquery.mutable_query_node(); - qc = qn->mutable_constraints(); - qr = qn->mutable_results(); - qn->set_identifier(-1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - pp = qc->add_predicates(); - pp->set_key("RemoveViaUpdate"); - pp->set_op(protobufs::PropertyPredicate::Eq); - p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("RemoveViaUpdate"); - p->set_string_value("Random"); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Email"; - cmds.push_back(&cmdcheckquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, false); - for (int i = 0; i < query_count; ++i) { - vector response = responses[i]; - for (auto it : response) { - ASSERT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::Count) { - EXPECT_EQ(it->op_int_value(), 2) << "Doesn't match expected count"; - } - if (it->r_type() == protobufs::List) { - EXPECT_EQ(it->op_int_value(), 3) << "Doesn't match expected count for prop match"; - } - //printf("\n"); - } +TEST(PMGDQueryHandler, queryUpdateTest) { + // printf("Testing PMGD query protobuf handler for list return of neighbors + // with constraints\n"); + + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Set parameters to find the starting node(s) + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Sex"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Sex"); + p->set_int_value(MALE); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdupdate; + cmdupdate.set_cmd_id(protobufs::Command::UpdateNode); + cmdupdate.set_tx_id(txid); + protobufs::UpdateNode *un = cmdupdate.mutable_update_node(); + + // The identifier here will be the identifier used for search + // since we are going to update properties of the nodes found + // in the previous search + un->set_identifier(qn->identifier()); + p = un->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("Hospital"); + p->set_string_value("Kaiser1"); + p = un->add_properties(); + p->set_type(protobufs::Property::BooleanType); + p->set_key("Treated"); + p->set_bool_value(true); + + // Remove the extra properties + un->add_remove_props("RemoveViaUpdate"); + + cmds.push_back(&cmdupdate); + query_count++; + + // Also make sure the removed property doesn't show up anymore + protobufs::Command cmdcheckquery; + cmdcheckquery.set_cmd_id(protobufs::Command::QueryNode); + cmdcheckquery.set_tx_id(txid); + qn = cmdcheckquery.mutable_query_node(); + qc = qn->mutable_constraints(); + qr = qn->mutable_results(); + qn->set_identifier(-1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + pp = qc->add_predicates(); + pp->set_key("RemoveViaUpdate"); + pp->set_op(protobufs::PropertyPredicate::Eq); + p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("RemoveViaUpdate"); + p->set_string_value("Random"); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Email"; + cmds.push_back(&cmdcheckquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, false); + for (int i = 0; i < query_count; ++i) { + vector response = responses[i]; + for (auto it : response) { + ASSERT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::Count) { + EXPECT_EQ(it->op_int_value(), 2) << "Doesn't match expected count"; + } + if (it->r_type() == protobufs::List) { + EXPECT_EQ(it->op_int_value(), 3) + << "Doesn't match expected count for prop match"; } + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryUpdateConstraintTest) -{ - //printf("Testing PMGD query protobuf handler for list return of neighbors with constraints\n"); - - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Try with constraints inside the update command - protobufs::Command cmdupdate; - cmdupdate.set_cmd_id(protobufs::Command::UpdateNode); - cmdupdate.set_tx_id(txid); - protobufs::UpdateNode *un = cmdupdate.mutable_update_node(); - un->set_identifier(1); - - // Set parameters to find the starting node(s) - protobufs::QueryNode *qn = un->mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(un->identifier()); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Sex"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::IntegerType); - // I think the key is not required here. - p->set_key("Sex"); - p->set_int_value(FEMALE); - - // Set properties to be updated when nodes are found. - p = un->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Hospital"); - p->set_string_value("Kaiser2"); - p = un->add_properties(); - p->set_type(protobufs::Property::BooleanType); - p->set_key("Treated"); - p->set_bool_value(true); - - cmds.push_back(&cmdupdate); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, false); - for (int i = 0; i < query_count; ++i) { - vector response = responses[i]; - for (auto it : response) { - ASSERT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::Count) { - EXPECT_EQ(it->op_int_value(), 3) << "Doesn't match expected count"; - } - //printf("\n"); - } +TEST(PMGDQueryHandler, queryUpdateConstraintTest) { + // printf("Testing PMGD query protobuf handler for list return of neighbors + // with constraints\n"); + + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Try with constraints inside the update command + protobufs::Command cmdupdate; + cmdupdate.set_cmd_id(protobufs::Command::UpdateNode); + cmdupdate.set_tx_id(txid); + protobufs::UpdateNode *un = cmdupdate.mutable_update_node(); + un->set_identifier(1); + + // Set parameters to find the starting node(s) + protobufs::QueryNode *qn = un->mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(un->identifier()); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Sex"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::IntegerType); + // I think the key is not required here. + p->set_key("Sex"); + p->set_int_value(FEMALE); + + // Set properties to be updated when nodes are found. + p = un->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("Hospital"); + p->set_string_value("Kaiser2"); + p = un->add_properties(); + p->set_type(protobufs::Property::BooleanType); + p->set_key("Treated"); + p->set_bool_value(true); + + cmds.push_back(&cmdupdate); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, false); + for (int i = 0; i < query_count; ++i) { + vector response = responses[i]; + for (auto it : response) { + ASSERT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::Count) { + EXPECT_EQ(it->op_int_value(), 3) << "Doesn't match expected count"; } + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryEdgeTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryEdge); - cmdquery.set_tx_id(txid); - protobufs::QueryEdge *qn = cmdquery.mutable_query_edge(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(-1); - qc->set_tag(""); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Status"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Status"); - p->set_string_value("Young Adult"); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Status"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int edgecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - ASSERT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - edgecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - edgecount++; - } - propcount++; - } - } - //printf("\n"); +TEST(PMGDQueryHandler, queryEdgeTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryEdge); + cmdquery.set_tx_id(txid); + protobufs::QueryEdge *qn = cmdquery.mutable_query_edge(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(-1); + qc->set_tag(""); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Status"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Status"); + p->set_string_value("Young Adult"); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Status"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int edgecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + ASSERT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + edgecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + edgecount++; } + propcount++; + } } - EXPECT_EQ(edgecount, 1) << "Not enough edges found"; - EXPECT_EQ(propcount, 1) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(edgecount, 1) << "Not enough edges found"; + EXPECT_EQ(propcount, 1) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryEdgeTestSortList) -{ - // Way to test the reusable iterator - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryEdge); - cmdquery.set_tx_id(txid); - protobufs::QueryEdge *qn = cmdquery.mutable_query_edge(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(-1); - qc->set_tag(""); - qc->set_p_op(protobufs::And); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Status"; - key = qr->add_response_keys(); - *key = "Since"; - qr->set_sort(true); - qr->set_sort_key("Status"); - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int edgecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - edgecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - if (m_it.first == "Status") { - if (i <= 1) - EXPECT_EQ(p.values(i).string_value(), "Old Adult"); - else - EXPECT_EQ(p.values(i).string_value(), "Young Adult"); - } - print_property(m_it.first, p.values(i)); - edgecount++; - } - propcount++; - } - } - //printf("\n"); +TEST(PMGDQueryHandler, queryEdgeTestSortList) { + // Way to test the reusable iterator + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryEdge); + cmdquery.set_tx_id(txid); + protobufs::QueryEdge *qn = cmdquery.mutable_query_edge(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(-1); + qc->set_tag(""); + qc->set_p_op(protobufs::And); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Status"; + key = qr->add_response_keys(); + *key = "Since"; + qr->set_sort(true); + qr->set_sort_key("Status"); + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int edgecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + edgecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + if (m_it.first == "Status") { + if (i <= 1) + EXPECT_EQ(p.values(i).string_value(), "Old Adult"); + else + EXPECT_EQ(p.values(i).string_value(), "Young Adult"); + } + print_property(m_it.first, p.values(i)); + edgecount++; } + propcount++; + } } - EXPECT_EQ(edgecount, 3) << "Not enough edges found"; - EXPECT_EQ(propcount, 2) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(edgecount, 3) << "Not enough edges found"; + EXPECT_EQ(propcount, 2) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryNodeEdgeTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Constrain the starting nodes for the edge we want to access - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Email"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Email"); - p->set_string_value("john.doe@abc.com"); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryEdge); - cmdquery.set_tx_id(txid); - protobufs::QueryEdge *qe = cmdquery.mutable_query_edge(); - qc = qe->mutable_constraints(); - qr = qe->mutable_results(); - qe->set_identifier(-1); - qe->set_src_node_id(1); - qe->set_dest_node_id(-1); - qc->set_tag(""); - qc->set_p_op(protobufs::And); - pp = qc->add_predicates(); - pp->set_key("Status"); - pp->set_op(protobufs::PropertyPredicate::Eq); - p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Status"); - p->set_string_value("Old Adult"); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Status"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, true); - int edgecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - edgecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - edgecount++; - } - propcount++; - } - } - //printf("\n"); +TEST(PMGDQueryHandler, queryNodeEdgeTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Constrain the starting nodes for the edge we want to access + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Email"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Email"); + p->set_string_value("john.doe@abc.com"); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryEdge); + cmdquery.set_tx_id(txid); + protobufs::QueryEdge *qe = cmdquery.mutable_query_edge(); + qc = qe->mutable_constraints(); + qr = qe->mutable_results(); + qe->set_identifier(-1); + qe->set_src_node_id(1); + qe->set_dest_node_id(-1); + qc->set_tag(""); + qc->set_p_op(protobufs::And); + pp = qc->add_predicates(); + pp->set_key("Status"); + pp->set_op(protobufs::PropertyPredicate::Eq); + p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Status"); + p->set_string_value("Old Adult"); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Status"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, true); + int edgecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + edgecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + edgecount++; } + propcount++; + } } - EXPECT_EQ(edgecount, 1) << "Not enough edges found"; - EXPECT_EQ(propcount, 1) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(edgecount, 1) << "Not enough edges found"; + EXPECT_EQ(propcount, 1) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryNodeEdgeDestTestList) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Constrain the starting nodes for the edge we want to access - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Email"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Email"); - p->set_string_value("john.doe@abc.com"); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdadd; - cmdadd.set_tx_id(txid); - add_patient(cmdadd, 2, "Jane Foster", 70, "Tue Oct 1 13:59:24 PDT 1946", +TEST(PMGDQueryHandler, queryNodeEdgeDestTestList) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Constrain the starting nodes for the edge we want to access + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Email"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Email"); + p->set_string_value("john.doe@abc.com"); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdadd; + cmdadd.set_tx_id(txid); + add_patient(cmdadd, 2, "Jane Foster", 70, "Tue Oct 1 13:59:24 PDT 1946", "jane.foster@pqr.com", FEMALE); - cmds.push_back(&cmdadd); - query_count++; - - protobufs::Command cmdedge; - cmdedge.set_tx_id(txid); - cmdedge.set_cmd_id(protobufs::Command::AddEdge); - protobufs::AddEdge *ae = cmdedge.mutable_add_edge(); - ae->set_identifier(-1); - protobufs::Edge *e = ae->mutable_edge(); - e->set_src(1); - e->set_dst(2); - e->set_tag("Friend"); - p = e->add_properties(); - p->set_type(protobufs::Property::TimeType); - p->set_key("Since"); - p->set_time_value("Sat Sep 1 19:59:24 PDT 1956"); - p = e->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Status"); - p->set_string_value("Old Adult"); - cmds.push_back(&cmdedge); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryEdge); - cmdquery.set_tx_id(txid); - protobufs::QueryEdge *qe = cmdquery.mutable_query_edge(); - qc = qe->mutable_constraints(); - qr = qe->mutable_results(); - qe->set_identifier(-1); - qe->set_src_node_id(1); - qe->set_dest_node_id(2); - qc->set_tag(""); - qc->set_p_op(protobufs::And); - pp = qc->add_predicates(); - pp->set_key("Status"); - pp->set_op(protobufs::PropertyPredicate::Eq); - p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Status"); - p->set_string_value("Old Adult"); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Status"; - cmds.push_back(&cmdquery); - query_count++; - - // No need to commit in this case. So just end TX - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, false); - int edgecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - edgecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - edgecount++; - } - propcount++; - } - } - //printf("\n"); + cmds.push_back(&cmdadd); + query_count++; + + protobufs::Command cmdedge; + cmdedge.set_tx_id(txid); + cmdedge.set_cmd_id(protobufs::Command::AddEdge); + protobufs::AddEdge *ae = cmdedge.mutable_add_edge(); + ae->set_identifier(-1); + protobufs::Edge *e = ae->mutable_edge(); + e->set_src(1); + e->set_dst(2); + e->set_tag("Friend"); + p = e->add_properties(); + p->set_type(protobufs::Property::TimeType); + p->set_key("Since"); + p->set_time_value("Sat Sep 1 19:59:24 PDT 1956"); + p = e->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("Status"); + p->set_string_value("Old Adult"); + cmds.push_back(&cmdedge); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryEdge); + cmdquery.set_tx_id(txid); + protobufs::QueryEdge *qe = cmdquery.mutable_query_edge(); + qc = qe->mutable_constraints(); + qr = qe->mutable_results(); + qe->set_identifier(-1); + qe->set_src_node_id(1); + qe->set_dest_node_id(2); + qc->set_tag(""); + qc->set_p_op(protobufs::And); + pp = qc->add_predicates(); + pp->set_key("Status"); + pp->set_op(protobufs::PropertyPredicate::Eq); + p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Status"); + p->set_string_value("Old Adult"); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Status"; + cmds.push_back(&cmdquery); + query_count++; + + // No need to commit in this case. So just end TX + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, false); + int edgecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + edgecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + edgecount++; } + propcount++; + } } - EXPECT_EQ(edgecount, 1) << "Not enough edges found"; - EXPECT_EQ(propcount, 1) << "Not enough properties read"; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(edgecount, 1) << "Not enough edges found"; + EXPECT_EQ(propcount, 1) << "Not enough properties read"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } -TEST(PMGDQueryHandler, queryUpdateEdge) -{ - VDMSConfig::init("unit_tests/config-pmgd-tests.json"); - PMGDQueryHandler::init(); - PMGDQueryHandler qh; - - vector cmds; - - { - int txid = 1, query_count = 0; - protobufs::Command cmdtx; - cmdtx.set_cmd_id(protobufs::Command::TxBegin); - cmdtx.set_tx_id(txid); - cmds.push_back(&cmdtx); - query_count++; - - // Constrain the starting nodes for the edge we want to access - protobufs::Command cmdstartquery; - cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); - cmdstartquery.set_tx_id(txid); - protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); - protobufs::Constraints *qc = qn->mutable_constraints(); - protobufs::ResultInfo *qr = qn->mutable_results(); - qn->set_identifier(1); - qc->set_tag("Patient"); - qc->set_p_op(protobufs::And); - protobufs::PropertyPredicate *pp = qc->add_predicates(); - pp->set_key("Email"); - pp->set_op(protobufs::PropertyPredicate::Eq); - protobufs::Property *p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Email"); - p->set_string_value("john.doe@abc.com"); - cmds.push_back(&cmdstartquery); - query_count++; - - protobufs::Command cmdadd; - cmdadd.set_tx_id(txid); - add_patient(cmdadd, 2, "Jane Foster", 70, "Tue Oct 1 13:59:24 PDT 1946", +TEST(PMGDQueryHandler, queryUpdateEdge) { + VDMSConfig::init("unit_tests/config-pmgd-tests.json"); + PMGDQueryHandler::init(); + PMGDQueryHandler qh; + + vector cmds; + + { + int txid = 1, query_count = 0; + protobufs::Command cmdtx; + cmdtx.set_cmd_id(protobufs::Command::TxBegin); + cmdtx.set_tx_id(txid); + cmds.push_back(&cmdtx); + query_count++; + + // Constrain the starting nodes for the edge we want to access + protobufs::Command cmdstartquery; + cmdstartquery.set_cmd_id(protobufs::Command::QueryNode); + cmdstartquery.set_tx_id(txid); + protobufs::QueryNode *qn = cmdstartquery.mutable_query_node(); + protobufs::Constraints *qc = qn->mutable_constraints(); + protobufs::ResultInfo *qr = qn->mutable_results(); + qn->set_identifier(1); + qc->set_tag("Patient"); + qc->set_p_op(protobufs::And); + protobufs::PropertyPredicate *pp = qc->add_predicates(); + pp->set_key("Email"); + pp->set_op(protobufs::PropertyPredicate::Eq); + protobufs::Property *p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Email"); + p->set_string_value("john.doe@abc.com"); + cmds.push_back(&cmdstartquery); + query_count++; + + protobufs::Command cmdadd; + cmdadd.set_tx_id(txid); + add_patient(cmdadd, 2, "Jane Foster", 70, "Tue Oct 1 13:59:24 PDT 1946", "jane.foster@pqr.com", FEMALE); - cmds.push_back(&cmdadd); - query_count++; - - protobufs::Command cmdedge; - cmdedge.set_tx_id(txid); - cmdedge.set_cmd_id(protobufs::Command::AddEdge); - protobufs::AddEdge *ae = cmdedge.mutable_add_edge(); - ae->set_identifier(-1); - protobufs::Edge *e = ae->mutable_edge(); - e->set_src(1); - e->set_dst(2); - e->set_tag("Friend"); - p = e->add_properties(); - p->set_type(protobufs::Property::TimeType); - p->set_key("Since"); - p->set_time_value("Sat Sep 1 19:59:24 PDT 1956"); - p = e->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Status"); - p->set_string_value("Old Adult"); - cmds.push_back(&cmdedge); - query_count++; - - protobufs::Command cmdquery; - cmdquery.set_cmd_id(protobufs::Command::QueryEdge); - cmdquery.set_tx_id(txid); - protobufs::QueryEdge *qe = cmdquery.mutable_query_edge(); - qc = qe->mutable_constraints(); - qr = qe->mutable_results(); - qe->set_identifier(10); - qe->set_src_node_id(1); - qe->set_dest_node_id(2); - qc->set_tag(""); - qc->set_p_op(protobufs::And); - pp = qc->add_predicates(); - pp->set_key("Status"); - pp->set_op(protobufs::PropertyPredicate::Eq); - p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Status"); - p->set_string_value("Old Adult"); - qr->set_r_type(protobufs::List); - string *key = qr->add_response_keys(); - *key = "Status"; - cmds.push_back(&cmdquery); - query_count++; - - protobufs::Command cmdupdate; - cmdupdate.set_cmd_id(protobufs::Command::UpdateEdge); - cmdupdate.set_tx_id(txid); - protobufs::UpdateEdge *ue = cmdupdate.mutable_update_edge(); - - // The identifier here will be the identifier used for search - // since we are going to update properties of the edge found - // in the previous search - ue->set_identifier(10); - p = ue->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("StartHospital"); - p->set_string_value("Kaiser1"); - p = ue->add_properties(); - p->set_type(protobufs::Property::StringType); - p->set_key("Status"); - p->set_string_value("Medium Adult"); - - // Remove the extra properties - ue->add_remove_props("Since"); - cmds.push_back(&cmdupdate); - - // Re-query with different properties - protobufs::Command cmdqueryu; - cmdqueryu.set_cmd_id(protobufs::Command::QueryEdge); - cmdqueryu.set_tx_id(txid); - qe = cmdqueryu.mutable_query_edge(); - qc = qe->mutable_constraints(); - qr = qe->mutable_results(); - qe->set_identifier(-1); - qc->set_tag(""); - qc->set_p_op(protobufs::And); - pp = qc->add_predicates(); - pp->set_key("Status"); - pp->set_op(protobufs::PropertyPredicate::Eq); - p = pp->mutable_v1(); - p->set_type(protobufs::Property::StringType); - // I think the key is not required here. - p->set_key("Status"); - p->set_string_value("Medium Adult"); - qr->set_r_type(protobufs::List); - key = qr->add_response_keys(); - *key = "Since"; - key = qr->add_response_keys(); - *key = "StartHospital"; - cmds.push_back(&cmdqueryu); - query_count++; - - protobufs::Command cmdtxend; - // Commit here doesn't change anything. Just indicates end of TX - cmdtxend.set_cmd_id(protobufs::Command::TxCommit); - cmdtxend.set_tx_id(txid); - cmds.push_back(&cmdtxend); - query_count++; - - vector> responses = qh.process_queries(cmds, query_count, false); - int edgecount = 0, propcount = 0; - for (int q = 0; q < query_count; ++q) { - vector response = responses[q]; - int qcount = 0; - for (auto it : response) { - EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) << it->error_msg(); - if (it->r_type() == protobufs::List) { - if (qcount == 4) { // First query - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - edgecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - edgecount++; - } - propcount++; - } - EXPECT_EQ(propcount, 1) << "Not enough properties read"; - propcount = 0; - } - else if (q == 6) { - auto mymap = it->prop_values(); - for(auto m_it : mymap) { - // Assuming string for now - protobufs::PropertyList &p = m_it.second; - edgecount = 0; - for (int i = 0; i < p.values_size(); ++i) { - print_property(m_it.first, p.values(i)); - edgecount++; - } - propcount++; - } - EXPECT_EQ(propcount, 2) << "Not enough properties read"; - propcount = 0; - } - } - if (it->r_type() == protobufs::Count) { - EXPECT_EQ(it->op_int_value(), 1) << "Doesn't match expected update count"; - } - qcount++; - //printf("\n"); + cmds.push_back(&cmdadd); + query_count++; + + protobufs::Command cmdedge; + cmdedge.set_tx_id(txid); + cmdedge.set_cmd_id(protobufs::Command::AddEdge); + protobufs::AddEdge *ae = cmdedge.mutable_add_edge(); + ae->set_identifier(-1); + protobufs::Edge *e = ae->mutable_edge(); + e->set_src(1); + e->set_dst(2); + e->set_tag("Friend"); + p = e->add_properties(); + p->set_type(protobufs::Property::TimeType); + p->set_key("Since"); + p->set_time_value("Sat Sep 1 19:59:24 PDT 1956"); + p = e->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("Status"); + p->set_string_value("Old Adult"); + cmds.push_back(&cmdedge); + query_count++; + + protobufs::Command cmdquery; + cmdquery.set_cmd_id(protobufs::Command::QueryEdge); + cmdquery.set_tx_id(txid); + protobufs::QueryEdge *qe = cmdquery.mutable_query_edge(); + qc = qe->mutable_constraints(); + qr = qe->mutable_results(); + qe->set_identifier(10); + qe->set_src_node_id(1); + qe->set_dest_node_id(2); + qc->set_tag(""); + qc->set_p_op(protobufs::And); + pp = qc->add_predicates(); + pp->set_key("Status"); + pp->set_op(protobufs::PropertyPredicate::Eq); + p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Status"); + p->set_string_value("Old Adult"); + qr->set_r_type(protobufs::List); + string *key = qr->add_response_keys(); + *key = "Status"; + cmds.push_back(&cmdquery); + query_count++; + + protobufs::Command cmdupdate; + cmdupdate.set_cmd_id(protobufs::Command::UpdateEdge); + cmdupdate.set_tx_id(txid); + protobufs::UpdateEdge *ue = cmdupdate.mutable_update_edge(); + + // The identifier here will be the identifier used for search + // since we are going to update properties of the edge found + // in the previous search + ue->set_identifier(10); + p = ue->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("StartHospital"); + p->set_string_value("Kaiser1"); + p = ue->add_properties(); + p->set_type(protobufs::Property::StringType); + p->set_key("Status"); + p->set_string_value("Medium Adult"); + + // Remove the extra properties + ue->add_remove_props("Since"); + cmds.push_back(&cmdupdate); + + // Re-query with different properties + protobufs::Command cmdqueryu; + cmdqueryu.set_cmd_id(protobufs::Command::QueryEdge); + cmdqueryu.set_tx_id(txid); + qe = cmdqueryu.mutable_query_edge(); + qc = qe->mutable_constraints(); + qr = qe->mutable_results(); + qe->set_identifier(-1); + qc->set_tag(""); + qc->set_p_op(protobufs::And); + pp = qc->add_predicates(); + pp->set_key("Status"); + pp->set_op(protobufs::PropertyPredicate::Eq); + p = pp->mutable_v1(); + p->set_type(protobufs::Property::StringType); + // I think the key is not required here. + p->set_key("Status"); + p->set_string_value("Medium Adult"); + qr->set_r_type(protobufs::List); + key = qr->add_response_keys(); + *key = "Since"; + key = qr->add_response_keys(); + *key = "StartHospital"; + cmds.push_back(&cmdqueryu); + query_count++; + + protobufs::Command cmdtxend; + // Commit here doesn't change anything. Just indicates end of TX + cmdtxend.set_cmd_id(protobufs::Command::TxCommit); + cmdtxend.set_tx_id(txid); + cmds.push_back(&cmdtxend); + query_count++; + + vector> responses = + qh.process_queries(cmds, query_count, false); + int edgecount = 0, propcount = 0; + for (int q = 0; q < query_count; ++q) { + vector response = responses[q]; + int qcount = 0; + for (auto it : response) { + EXPECT_EQ(it->error_code(), protobufs::CommandResponse::Success) + << it->error_msg(); + if (it->r_type() == protobufs::List) { + if (qcount == 4) { // First query + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + edgecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + edgecount++; + } + propcount++; } + EXPECT_EQ(propcount, 1) << "Not enough properties read"; + propcount = 0; + } else if (q == 6) { + auto mymap = it->prop_values(); + for (auto m_it : mymap) { + // Assuming string for now + protobufs::PropertyList &p = m_it.second; + edgecount = 0; + for (int i = 0; i < p.values_size(); ++i) { + print_property(m_it.first, p.values(i)); + edgecount++; + } + propcount++; + } + EXPECT_EQ(propcount, 2) << "Not enough properties read"; + propcount = 0; + } + } + if (it->r_type() == protobufs::Count) { + EXPECT_EQ(it->op_int_value(), 1) + << "Doesn't match expected update count"; } - EXPECT_EQ(edgecount, 1) << "Not enough edges found"; + qcount++; + // printf("\n"); + } } - VDMSConfig::destroy(); - PMGDQueryHandler::destroy(); + EXPECT_EQ(edgecount, 1) << "Not enough edges found"; + } + VDMSConfig::destroy(); + PMGDQueryHandler::destroy(); } diff --git a/user_defined_operations/README.md b/user_defined_operations/README.md new file mode 100644 index 00000000..ec17527c --- /dev/null +++ b/user_defined_operations/README.md @@ -0,0 +1,185 @@ +# User Defined Operations in VDMS +This submodule is required to execute user defined operations (UDF) in VDMS using message queues (Support only available for images). Although shipped with VDMS, this submodule can be run independently and interacts with VDMS using message queues. + +## Requirements +- Python 3 or higher +- Following python libraries + - opencv-python + - zmq + +## UDF Definition +Any operation can be added to the module by creating a python file and adding it to the `functions` folder. All related files for the UDF should be stored in the folder `functions/files`. The operaion file should follow the following setup to define a `run` function that the interface file for VDMS will use; +``` +def run(settings, message, input_params): + + # message: The inputfile and other parameters sent from VDMS + # settings: System specific settings for the udf + # input_params: Any parameters required by the UDF to run + + # Create outputfile + # Read from inputfile + ''' + The UDF logic goes here + ''' + # Return outputfile +``` + +Update the `settings.json` file with the following parameters; + +``` +{ + "opfile": "/tmp/tmp_op_file", # Location where the outputfile temporary file will be stored + "port": 5555, # Port on which the message queue will be listening and writing + "functions" : { + "facedetect" : "facedetect", # Key value pair for the UDFs. 'key' is the UDF id and 'value' is the filename of the UDF. + "flip": "flip", + "carcount": "carcount", + "activityrecognition": "activityrecognition" + } +} +``` + +## Setup +1. Either run from the location where you have the VDMS repo or just copy the `user_defined_operations` directory to wherever you want to run the UDFs, but ensure that it is on the same system as VDMS. +2. Create your UDFs as python scripts and place them in the `user_defined_operations/functions` directory. +3. Update the `settings.json` file to include your UDF file and other necessary information. +4. Follow the following steps to run the `user_defined_operations` submodule on port . + +``` +cd user_defined_operations +python3 -m venv venv +source venv/bin/activate +python3 -m pip install pip --upgrade +python3 -m pip install wheel +python3 -m pip install -r requirements.txt +python3 udf_local.py +``` + +## Client Query + +The client query should contain the following two parameters: + +- `type`: Should always be `userOp` for remote operation +- `options`: Any parameter that is required by the operation. The following three parameters are important: + - `id`: A mandatory parameter. It specifies the operation to be executed and should be a key in the `functions` parameter of the `settings.json` file. For instance, if the key is `facedetect`, then the `id` should be `facedetect`. + - `format`: Optional, but specifies the format in which the image is required. Default is `jpg`. + - `port`: The port on which the message queue will be listening and writing. + +``` +"FindImage": { + "format": "png", + "constraints": { + "category": ["==", "cars"] + }, + "operations": [ + { + "type": "userOp", + "options": { + "id": "carcount", + "format": "png", + "port": 5555 + } + } + ] +} +``` + +## Detailed Instructions for new UDF +We now provide an example to add a new UDF `cardetect`. The `cardetect` operation detects cars in an image and creates a rectangle around all cars. This operation requires a pretrained model available in the form of `xml` file online. + +1. Copy `user_defined_operations` directory to anywhere you want but on the same server that is running VDMS. Say you copy the folder in the `home` directory. The folder structure you have now will look something like this; +``` +~/ +|__user_defined_operations + |__functions + | |__files + | | |__haarcascade_frontalface_default.xml + | |__facedetect.py + | |__flip.py + |__README.md + |__requirements.txt + |__settings.json + |__udf_local.py +``` +2. Download/Copy the `cars.xml` file to the `~/user_defined_operations/functions/files`. +3. Create the `cardetect.py` file in `~/user_defined_operations/functions`. +``` +import time +import cv2 +from PIL import Image +import numpy as np + +car_cascade_src = 'functions/files/cars.xml' + +def run(settings, message, input_params): + + global car_cascade_src + + t1 = time.time() + + ipfilename = message + format = message.strip().split('.')[-1] + + opfilename = settings["opfile"] + str(t1) + '.' + format + + img = cv2.imread(ipfilename) + + # These lines + # represent the + # code logic + + cv2.imwrite(opfilename, img) + + return (time.time() - t1), opfilename +``` +4. The final directory structure would be as follows; +``` +~/ +|__user_defined_operations + |__functions + | |__files + | | |__haarcascade_frontalface_default.xml + | | |__cars.xml + | |__facedetect.py + | |__flip.py + | |__cardetect.py + |__README.md + |__requirements.txt + |__settings.json + |__udf_local.py +``` +5. Update the settings file with the new UDF information. +``` +{ + "opfile": "/tmp/tmp_op_file", + "port": 5555, + "functions" : { + "facedetect" : "facedetect", + "flip": "flip", + "cardetect": "cardetect" + } +} +``` +6. Now start the `udf_local.py` file to initiate the message queue; +``` +python3 udf_local.py +``` +7. Say VDMS has a database of car images that have the property `category` set as `cars`. Then you can run the `cardetect` operation on these images using the following query; +``` +"FindImage": { + "format": "png", + "constraints": { + "category": ["==", "cars"] + }, + "operations": [ + { + "type": "userOp", + "options": { + "port": 5555, + "id": "cardetect", + "format": "png" + } + } + ] +} +``` \ No newline at end of file diff --git a/user_defined_operations/functions/facedetect.py b/user_defined_operations/functions/facedetect.py new file mode 100644 index 00000000..44529c6d --- /dev/null +++ b/user_defined_operations/functions/facedetect.py @@ -0,0 +1,32 @@ +import time +import cv2 + +face_cascade = cv2.CascadeClassifier( + # This file is available from OpenCV 'data' directory at + # https://github.com/opencv/opencv/blob/4.x/data/haarcascades/haarcascade_frontalface_default.xml + "functions/files/haarcascade_frontalface_default.xml" +) + + +def run(settings, message, input_params): + global face_cascade + ipfilename = message + format = message.strip().split(".")[-1] + + print(ipfilename) + t1 = time.time() + + opfilename = settings["opfile"] + str(t1) + "." + format + + img = cv2.imread(ipfilename) + + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + + faces = face_cascade.detectMultiScale(gray, 1.1, 4) + + for x, y, w, h in faces: + cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) + + cv2.imwrite(opfilename, img) + + return (time.time() - t1), opfilename diff --git a/user_defined_operations/functions/files/haarcascade_frontalface_default.xml b/user_defined_operations/functions/files/haarcascade_frontalface_default.xml new file mode 100644 index 00000000..cbd1aa89 --- /dev/null +++ b/user_defined_operations/functions/files/haarcascade_frontalface_default.xml @@ -0,0 +1,33314 @@ + + + +BOOST + HAAR + 24 + 24 + + 211 + + 0 + 25 + + <_> + 9 + -5.0425500869750977e+00 + + <_> + + 0 -1 0 -3.1511999666690826e-02 + + 2.0875380039215088e+00 -2.2172100543975830e+00 + <_> + + 0 -1 1 1.2396000325679779e-02 + + -1.8633940219879150e+00 1.3272049427032471e+00 + <_> + + 0 -1 2 2.1927999332547188e-02 + + -1.5105249881744385e+00 1.0625729560852051e+00 + <_> + + 0 -1 3 5.7529998011887074e-03 + + -8.7463897466659546e-01 1.1760339736938477e+00 + <_> + + 0 -1 4 1.5014000236988068e-02 + + -7.7945697307586670e-01 1.2608419656753540e+00 + <_> + + 0 -1 5 9.9371001124382019e-02 + + 5.5751299858093262e-01 -1.8743000030517578e+00 + <_> + + 0 -1 6 2.7340000960975885e-03 + + -1.6911929845809937e+00 4.4009700417518616e-01 + <_> + + 0 -1 7 -1.8859000876545906e-02 + + -1.4769539833068848e+00 4.4350099563598633e-01 + <_> + + 0 -1 8 5.9739998541772366e-03 + + -8.5909199714660645e-01 8.5255599021911621e-01 + <_> + 16 + -4.9842400550842285e+00 + + <_> + + 0 -1 9 -2.1110000088810921e-02 + + 1.2435649633407593e+00 -1.5713009834289551e+00 + <_> + + 0 -1 10 2.0355999469757080e-02 + + -1.6204780340194702e+00 1.1817760467529297e+00 + <_> + + 0 -1 11 2.1308999508619308e-02 + + -1.9415930509567261e+00 7.0069098472595215e-01 + <_> + + 0 -1 12 9.1660000383853912e-02 + + -5.5670100450515747e-01 1.7284419536590576e+00 + <_> + + 0 -1 13 3.6288000643253326e-02 + + 2.6763799786567688e-01 -2.1831810474395752e+00 + <_> + + 0 -1 14 -1.9109999760985374e-02 + + -2.6730210781097412e+00 4.5670801401138306e-01 + <_> + + 0 -1 15 8.2539999857544899e-03 + + -1.0852910280227661e+00 5.3564202785491943e-01 + <_> + + 0 -1 16 1.8355000764131546e-02 + + -3.5200199484825134e-01 9.3339198827743530e-01 + <_> + + 0 -1 17 -7.0569999516010284e-03 + + 9.2782098054885864e-01 -6.6349899768829346e-01 + <_> + + 0 -1 18 -9.8770000040531158e-03 + + 1.1577470302581787e+00 -2.9774799942970276e-01 + <_> + + 0 -1 19 1.5814000740647316e-02 + + -4.1960600018501282e-01 1.3576040267944336e+00 + <_> + + 0 -1 20 -2.0700000226497650e-02 + + 1.4590020179748535e+00 -1.9739399850368500e-01 + <_> + + 0 -1 21 -1.3760800659656525e-01 + + 1.1186759471893311e+00 -5.2915501594543457e-01 + <_> + + 0 -1 22 1.4318999834358692e-02 + + -3.5127198696136475e-01 1.1440860033035278e+00 + <_> + + 0 -1 23 1.0253000073134899e-02 + + -6.0850602388381958e-01 7.7098500728607178e-01 + <_> + + 0 -1 24 9.1508001089096069e-02 + + 3.8817799091339111e-01 -1.5122940540313721e+00 + <_> + 27 + -4.6551899909973145e+00 + + <_> + + 0 -1 25 6.9747000932693481e-02 + + -1.0130879878997803e+00 1.4687349796295166e+00 + <_> + + 0 -1 26 3.1502999365329742e-02 + + -1.6463639736175537e+00 1.0000629425048828e+00 + <_> + + 0 -1 27 1.4260999858379364e-02 + + 4.6480301022529602e-01 -1.5959889888763428e+00 + <_> + + 0 -1 28 1.4453000389039516e-02 + + -6.5511900186538696e-01 8.3021801710128784e-01 + <_> + + 0 -1 29 -3.0509999487549067e-03 + + -1.3982310295104980e+00 4.2550599575042725e-01 + <_> + + 0 -1 30 3.2722998410463333e-02 + + -5.0702601671218872e-01 1.0526109933853149e+00 + <_> + + 0 -1 31 -7.2960001416504383e-03 + + 3.6356899142265320e-01 -1.3464889526367188e+00 + <_> + + 0 -1 32 5.0425000488758087e-02 + + -3.0461400747299194e-01 1.4504129886627197e+00 + <_> + + 0 -1 33 4.6879000961780548e-02 + + -4.0286201238632202e-01 1.2145609855651855e+00 + <_> + + 0 -1 34 -6.9358997046947479e-02 + + 1.0539360046386719e+00 -4.5719701051712036e-01 + <_> + + 0 -1 35 -4.9033999443054199e-02 + + -1.6253089904785156e+00 1.5378999710083008e-01 + <_> + + 0 -1 36 8.4827996790409088e-02 + + 2.8402999043464661e-01 -1.5662059783935547e+00 + <_> + + 0 -1 37 -1.7229999648407102e-03 + + -1.0147459506988525e+00 2.3294800519943237e-01 + <_> + + 0 -1 38 1.1562199890613556e-01 + + -1.6732899844646454e-01 1.2804069519042969e+00 + <_> + + 0 -1 39 -5.1279999315738678e-02 + + 1.5162390470504761e+00 -3.0271100997924805e-01 + <_> + + 0 -1 40 -4.2706999927759171e-02 + + 1.7631920576095581e+00 -5.1832001656293869e-02 + <_> + + 0 -1 41 3.7178099155426025e-01 + + -3.1389200687408447e-01 1.5357979536056519e+00 + <_> + + 0 -1 42 1.9412999972701073e-02 + + -1.0017599910497665e-01 9.3655401468276978e-01 + <_> + + 0 -1 43 1.7439000308513641e-02 + + -4.0379899740219116e-01 9.6293002367019653e-01 + <_> + + 0 -1 44 3.9638999849557877e-02 + + 1.7039099335670471e-01 -2.9602990150451660e+00 + <_> + + 0 -1 45 -9.1469995677471161e-03 + + 8.8786798715591431e-01 -4.3818700313568115e-01 + <_> + + 0 -1 46 1.7219999572262168e-03 + + -3.7218600511550903e-01 4.0018901228904724e-01 + <_> + + 0 -1 47 3.0231000855565071e-02 + + 6.5924003720283508e-02 -2.6469180583953857e+00 + <_> + + 0 -1 48 -7.8795999288558960e-02 + + -1.7491459846496582e+00 2.8475299477577209e-01 + <_> + + 0 -1 49 2.1110000088810921e-03 + + -9.3908101320266724e-01 2.3205199837684631e-01 + <_> + + 0 -1 50 2.7091000229120255e-02 + + -5.2664000540971756e-02 1.0756820440292358e+00 + <_> + + 0 -1 51 -4.4964998960494995e-02 + + -1.8294479846954346e+00 9.9561996757984161e-02 + <_> + 32 + -4.4531588554382324e+00 + + <_> + + 0 -1 52 -6.5701000392436981e-02 + + 1.1558510065078735e+00 -1.0716359615325928e+00 + <_> + + 0 -1 53 1.5839999541640282e-02 + + -1.5634720325469971e+00 7.6877099275588989e-01 + <_> + + 0 -1 54 1.4570899307727814e-01 + + -5.7450097799301147e-01 1.3808720111846924e+00 + <_> + + 0 -1 55 6.1389999464154243e-03 + + -1.4570560455322266e+00 5.1610302925109863e-01 + <_> + + 0 -1 56 6.7179999314248562e-03 + + -8.3533602952957153e-01 5.8522200584411621e-01 + <_> + + 0 -1 57 1.8518000841140747e-02 + + -3.1312099099159241e-01 1.1696679592132568e+00 + <_> + + 0 -1 58 1.9958000630140305e-02 + + -4.3442600965499878e-01 9.5446902513504028e-01 + <_> + + 0 -1 59 -2.7755001187324524e-01 + + 1.4906179904937744e+00 -1.3815900683403015e-01 + <_> + + 0 -1 60 9.1859996318817139e-03 + + -9.6361500024795532e-01 2.7665498852729797e-01 + <_> + + 0 -1 61 -3.7737999111413956e-02 + + -2.4464108943939209e+00 2.3619599640369415e-01 + <_> + + 0 -1 62 1.8463000655174255e-02 + + 1.7539200186729431e-01 -1.3423130512237549e+00 + <_> + + 0 -1 63 -1.1114999651908875e-02 + + 4.8710799217224121e-01 -8.9851897954940796e-01 + <_> + + 0 -1 64 3.3927999436855316e-02 + + 1.7874200642108917e-01 -1.6342279911041260e+00 + <_> + + 0 -1 65 -3.5649001598358154e-02 + + -1.9607399702072144e+00 1.8102499842643738e-01 + <_> + + 0 -1 66 -1.1438000015914440e-02 + + 9.9010699987411499e-01 -3.8103199005126953e-01 + <_> + + 0 -1 67 -6.5236002206802368e-02 + + -2.5794160366058350e+00 2.4753600358963013e-01 + <_> + + 0 -1 68 -4.2272001504898071e-02 + + 1.4411840438842773e+00 -2.9508298635482788e-01 + <_> + + 0 -1 69 1.9219999667257071e-03 + + -4.9608600139617920e-01 6.3173598051071167e-01 + <_> + + 0 -1 70 -1.2921799719333649e-01 + + -2.3314270973205566e+00 5.4496999830007553e-02 + <_> + + 0 -1 71 2.2931000217795372e-02 + + -8.4447097778320312e-01 3.8738098740577698e-01 + <_> + + 0 -1 72 -3.4120000898838043e-02 + + -1.4431500434875488e+00 9.8422996699810028e-02 + <_> + + 0 -1 73 2.6223000138998032e-02 + + 1.8223099410533905e-01 -1.2586519718170166e+00 + <_> + + 0 -1 74 2.2236999124288559e-02 + + 6.9807998836040497e-02 -2.3820950984954834e+00 + <_> + + 0 -1 75 -5.8240001089870930e-03 + + 3.9332500100135803e-01 -2.7542799711227417e-01 + <_> + + 0 -1 76 4.3653000146150589e-02 + + 1.4832699298858643e-01 -1.1368780136108398e+00 + <_> + + 0 -1 77 5.7266999036073685e-02 + + 2.4628099799156189e-01 -1.2687400579452515e+00 + <_> + + 0 -1 78 2.3409998975694180e-03 + + -7.5448900461196899e-01 2.7163800597190857e-01 + <_> + + 0 -1 79 1.2996000237762928e-02 + + -3.6394900083541870e-01 7.0959198474884033e-01 + <_> + + 0 -1 80 -2.6517000049352646e-02 + + -2.3221859931945801e+00 3.5744000226259232e-02 + <_> + + 0 -1 81 -5.8400002308189869e-03 + + 4.2194300889968872e-01 -4.8184998333454132e-02 + <_> + + 0 -1 82 -1.6568999737501144e-02 + + 1.1099940538406372e+00 -3.4849700331687927e-01 + <_> + + 0 -1 83 -6.8157002329826355e-02 + + -3.3269989490509033e+00 2.1299000084400177e-01 + <_> + 52 + -4.3864588737487793e+00 + + <_> + + 0 -1 84 3.9974000304937363e-02 + + -1.2173449993133545e+00 1.0826710462570190e+00 + <_> + + 0 -1 85 1.8819500505924225e-01 + + -4.8289400339126587e-01 1.4045250415802002e+00 + <_> + + 0 -1 86 7.8027002513408661e-02 + + -1.0782150030136108e+00 7.4040299654006958e-01 + <_> + + 0 -1 87 1.1899999663000926e-04 + + -1.2019979953765869e+00 3.7749201059341431e-01 + <_> + + 0 -1 88 8.5056997835636139e-02 + + -4.3939098715782166e-01 1.2647340297698975e+00 + <_> + + 0 -1 89 8.9720003306865692e-03 + + -1.8440499901771545e-01 4.5726400613784790e-01 + <_> + + 0 -1 90 8.8120000436902046e-03 + + 3.0396699905395508e-01 -9.5991098880767822e-01 + <_> + + 0 -1 91 -2.3507999256253242e-02 + + 1.2487529516220093e+00 4.6227999031543732e-02 + <_> + + 0 -1 92 7.0039997808635235e-03 + + -5.9442102909088135e-01 5.3963297605514526e-01 + <_> + + 0 -1 93 3.3851999789476395e-02 + + 2.8496098518371582e-01 -1.4895249605178833e+00 + <_> + + 0 -1 94 -3.2530000898987055e-03 + + 4.8120799660682678e-01 -5.2712398767471313e-01 + <_> + + 0 -1 95 2.9097000136971474e-02 + + 2.6743900775909424e-01 -1.6007850170135498e+00 + <_> + + 0 -1 96 -8.4790000692009926e-03 + + -1.3107639551162720e+00 1.5243099629878998e-01 + <_> + + 0 -1 97 -1.0795000009238720e-02 + + 4.5613598823547363e-01 -7.2050899267196655e-01 + <_> + + 0 -1 98 -2.4620000272989273e-02 + + -1.7320619821548462e+00 6.8363003432750702e-02 + <_> + + 0 -1 99 3.7380000576376915e-03 + + -1.9303299486637115e-01 6.8243497610092163e-01 + <_> + + 0 -1 100 -1.2264000251889229e-02 + + -1.6095290184020996e+00 7.5268000364303589e-02 + <_> + + 0 -1 101 -4.8670000396668911e-03 + + 7.4286502599716187e-01 -2.1510200202465057e-01 + <_> + + 0 -1 102 7.6725997030735016e-02 + + -2.6835098862648010e-01 1.3094140291213989e+00 + <_> + + 0 -1 103 2.8578000143170357e-02 + + -5.8793000876903534e-02 1.2196329832077026e+00 + <_> + + 0 -1 104 1.9694000482559204e-02 + + -3.5142898559570312e-01 8.4926998615264893e-01 + <_> + + 0 -1 105 -2.9093999415636063e-02 + + -1.0507299900054932e+00 2.9806300997734070e-01 + <_> + + 0 -1 106 -2.9144000262022018e-02 + + 8.2547801733016968e-01 -3.2687199115753174e-01 + <_> + + 0 -1 107 1.9741000607609749e-02 + + 2.0452600717544556e-01 -8.3760201930999756e-01 + <_> + + 0 -1 108 4.3299999088048935e-03 + + 2.0577900111675262e-01 -6.6829800605773926e-01 + <_> + + 0 -1 109 -3.5500999540090561e-02 + + -1.2969900369644165e+00 1.3897499442100525e-01 + <_> + + 0 -1 110 -1.6172999516129494e-02 + + -1.3110569715499878e+00 7.5751997530460358e-02 + <_> + + 0 -1 111 -2.2151000797748566e-02 + + -1.0524389743804932e+00 1.9241100549697876e-01 + <_> + + 0 -1 112 -2.2707000374794006e-02 + + -1.3735309839248657e+00 6.6780999302864075e-02 + <_> + + 0 -1 113 1.6607999801635742e-02 + + -3.7135999649763107e-02 7.7846401929855347e-01 + <_> + + 0 -1 114 -1.3309000059962273e-02 + + -9.9850702285766602e-01 1.2248100340366364e-01 + <_> + + 0 -1 115 -3.3732000738382339e-02 + + 1.4461359977722168e+00 1.3151999562978745e-02 + <_> + + 0 -1 116 1.6935000196099281e-02 + + -3.7121298909187317e-01 5.2842199802398682e-01 + <_> + + 0 -1 117 3.3259999472647905e-03 + + -5.7568502426147461e-01 3.9261901378631592e-01 + <_> + + 0 -1 118 8.3644002676010132e-02 + + 1.6116000711917877e-02 -2.1173279285430908e+00 + <_> + + 0 -1 119 2.5785198807716370e-01 + + -8.1609003245830536e-02 9.8782497644424438e-01 + <_> + + 0 -1 120 -3.6566998809576035e-02 + + -1.1512110233306885e+00 9.6459001302719116e-02 + <_> + + 0 -1 121 -1.6445999965071678e-02 + + 3.7315499782562256e-01 -1.4585399627685547e-01 + <_> + + 0 -1 122 -3.7519999314099550e-03 + + 2.6179298758506775e-01 -5.8156698942184448e-01 + <_> + + 0 -1 123 -6.3660000450909138e-03 + + 7.5477397441864014e-01 -1.7055200040340424e-01 + <_> + + 0 -1 124 -3.8499999791383743e-03 + + 2.2653999924659729e-01 -6.3876402378082275e-01 + <_> + + 0 -1 125 -4.5494001358747482e-02 + + -1.2640299797058105e+00 2.5260698795318604e-01 + <_> + + 0 -1 126 -2.3941000923514366e-02 + + 8.7068402767181396e-01 -2.7104699611663818e-01 + <_> + + 0 -1 127 -7.7558003365993500e-02 + + -1.3901610374450684e+00 2.3612299561500549e-01 + <_> + + 0 -1 128 2.3614000529050827e-02 + + 6.6140003502368927e-02 -1.2645419836044312e+00 + <_> + + 0 -1 129 -2.5750000495463610e-03 + + -5.3841698169708252e-01 3.0379098653793335e-01 + <_> + + 0 -1 130 1.2010800093412399e-01 + + -3.5343000292778015e-01 5.2866202592849731e-01 + <_> + + 0 -1 131 2.2899999748915434e-03 + + -5.8701997995376587e-01 2.4061000347137451e-01 + <_> + + 0 -1 132 6.9716997444629669e-02 + + -3.3348900079727173e-01 5.1916301250457764e-01 + <_> + + 0 -1 133 -4.6670001000165939e-02 + + 6.9795399904251099e-01 -1.4895999804139137e-02 + <_> + + 0 -1 134 -5.0129000097513199e-02 + + 8.6146199703216553e-01 -2.5986000895500183e-01 + <_> + + 0 -1 135 3.0147999525070190e-02 + + 1.9332799315452576e-01 -5.9131097793579102e-01 + <_> + 53 + -4.1299300193786621e+00 + + <_> + + 0 -1 136 9.1085001826286316e-02 + + -8.9233100414276123e-01 1.0434230566024780e+00 + <_> + + 0 -1 137 1.2818999588489532e-02 + + -1.2597670555114746e+00 5.5317097902297974e-01 + <_> + + 0 -1 138 1.5931999310851097e-02 + + -8.6254400014877319e-01 6.3731801509857178e-01 + <_> + + 0 -1 139 2.2780001163482666e-03 + + -7.4639201164245605e-01 5.3155601024627686e-01 + <_> + + 0 -1 140 3.1840998679399490e-02 + + -1.2650489807128906e+00 3.6153900623321533e-01 + <_> + + 0 -1 141 2.6960000395774841e-03 + + -9.8290401697158813e-01 3.6013001203536987e-01 + <_> + + 0 -1 142 -1.2055000290274620e-02 + + 6.4068400859832764e-01 -5.0125002861022949e-01 + <_> + + 0 -1 143 2.1324999630451202e-02 + + -2.4034999310970306e-01 8.5448002815246582e-01 + <_> + + 0 -1 144 3.0486000701785088e-02 + + -3.4273600578308105e-01 1.1428849697113037e+00 + <_> + + 0 -1 145 -4.5079998672008514e-02 + + 1.0976949930191040e+00 -1.7974600195884705e-01 + <_> + + 0 -1 146 -7.1700997650623322e-02 + + 1.5735000371932983e+00 -3.1433498859405518e-01 + <_> + + 0 -1 147 5.9218000620603561e-02 + + -2.7582401037216187e-01 1.0448570251464844e+00 + <_> + + 0 -1 148 6.7010000348091125e-03 + + -1.0974019765853882e+00 1.9801199436187744e-01 + <_> + + 0 -1 149 4.1046999394893646e-02 + + 3.0547699332237244e-01 -1.3287999629974365e+00 + <_> + + 0 -1 150 -8.5499999113380909e-04 + + 2.5807100534439087e-01 -7.0052897930145264e-01 + <_> + + 0 -1 151 -3.0360000208020210e-02 + + -1.2306419610977173e+00 2.2609399259090424e-01 + <_> + + 0 -1 152 -1.2930000200867653e-02 + + 4.0758600831031799e-01 -5.1234501600265503e-01 + <_> + + 0 -1 153 3.7367999553680420e-02 + + -9.4755001366138458e-02 6.1765098571777344e-01 + <_> + + 0 -1 154 2.4434000253677368e-02 + + -4.1100600361824036e-01 4.7630500793457031e-01 + <_> + + 0 -1 155 5.7007998228073120e-02 + + 2.5249299407005310e-01 -6.8669801950454712e-01 + <_> + + 0 -1 156 -1.6313999891281128e-02 + + -9.3928402662277222e-01 1.1448100209236145e-01 + <_> + + 0 -1 157 -1.7648899555206299e-01 + + 1.2451089620590210e+00 -5.6519001722335815e-02 + <_> + + 0 -1 158 1.7614600062370300e-01 + + -3.2528200745582581e-01 8.2791501283645630e-01 + <_> + + 0 -1 159 -7.3910001665353775e-03 + + 3.4783700108528137e-01 -1.7929099500179291e-01 + <_> + + 0 -1 160 6.0890998691320419e-02 + + 5.5098000913858414e-02 -1.5480779409408569e+00 + <_> + + 0 -1 161 -2.9123000800609589e-02 + + -1.0255639553070068e+00 2.4106900393962860e-01 + <_> + + 0 -1 162 -4.5648999512195587e-02 + + 1.0301599502563477e+00 -3.1672099232673645e-01 + <_> + + 0 -1 163 3.7333000451326370e-02 + + 2.1620599925518036e-01 -8.2589900493621826e-01 + <_> + + 0 -1 164 -2.4411000311374664e-02 + + -1.5957959890365601e+00 5.1139000803232193e-02 + <_> + + 0 -1 165 -5.9806998819112778e-02 + + -1.0312290191650391e+00 1.3092300295829773e-01 + <_> + + 0 -1 166 -3.0106000602245331e-02 + + -1.4781630039215088e+00 3.7211999297142029e-02 + <_> + + 0 -1 167 7.4209999293088913e-03 + + -2.4024100601673126e-01 4.9333998560905457e-01 + <_> + + 0 -1 168 -2.1909999195486307e-03 + + 2.8941500186920166e-01 -5.7259601354598999e-01 + <_> + + 0 -1 169 2.0860999822616577e-02 + + -2.3148399591445923e-01 6.3765901327133179e-01 + <_> + + 0 -1 170 -6.6990000195801258e-03 + + -1.2107750177383423e+00 6.4018003642559052e-02 + <_> + + 0 -1 171 1.8758000805974007e-02 + + 2.4461300671100616e-01 -9.9786698818206787e-01 + <_> + + 0 -1 172 -4.4323001056909561e-02 + + -1.3699189424514771e+00 3.6051999777555466e-02 + <_> + + 0 -1 173 2.2859999909996986e-02 + + 2.1288399398326874e-01 -1.0397620201110840e+00 + <_> + + 0 -1 174 -9.8600005730986595e-04 + + 3.2443600893020630e-01 -5.4291802644729614e-01 + <_> + + 0 -1 175 1.7239000648260117e-02 + + -2.8323900699615479e-01 4.4468200206756592e-01 + <_> + + 0 -1 176 -3.4531001001596451e-02 + + -2.3107020854949951e+00 -3.1399999279528856e-03 + <_> + + 0 -1 177 6.7006997764110565e-02 + + 2.8715699911117554e-01 -6.4481002092361450e-01 + <_> + + 0 -1 178 2.3776899278163910e-01 + + -2.7174800634384155e-01 8.0219101905822754e-01 + <_> + + 0 -1 179 -1.2903000228106976e-02 + + -1.5317620038986206e+00 2.1423600614070892e-01 + <_> + + 0 -1 180 1.0514999739825726e-02 + + 7.7037997543811798e-02 -1.0581140518188477e+00 + <_> + + 0 -1 181 1.6969000920653343e-02 + + 1.4306700229644775e-01 -8.5828399658203125e-01 + <_> + + 0 -1 182 -7.2460002265870571e-03 + + -1.1020129919052124e+00 6.4906999468803406e-02 + <_> + + 0 -1 183 1.0556999593973160e-02 + + 1.3964000158011913e-02 6.3601499795913696e-01 + <_> + + 0 -1 184 6.1380001716315746e-03 + + -3.4545901417732239e-01 5.6296801567077637e-01 + <_> + + 0 -1 185 1.3158000074326992e-02 + + 1.9927300512790680e-01 -1.5040320158004761e+00 + <_> + + 0 -1 186 3.1310000922530890e-03 + + -4.0903699398040771e-01 3.7796398997306824e-01 + <_> + + 0 -1 187 -1.0920699685811996e-01 + + -2.2227079868316650e+00 1.2178199738264084e-01 + <_> + + 0 -1 188 8.1820003688335419e-03 + + -2.8652000427246094e-01 6.7890799045562744e-01 + <_> + 62 + -4.0218091011047363e+00 + + <_> + + 0 -1 189 3.1346999108791351e-02 + + -8.8884598016738892e-01 9.4936800003051758e-01 + <_> + + 0 -1 190 3.1918000429868698e-02 + + -1.1146880388259888e+00 4.8888999223709106e-01 + <_> + + 0 -1 191 6.5939999185502529e-03 + + -1.0097689628601074e+00 4.9723801016807556e-01 + <_> + + 0 -1 192 2.6148000732064247e-02 + + 2.5991299748420715e-01 -1.2537480592727661e+00 + <_> + + 0 -1 193 1.2845000252127647e-02 + + -5.7138597965240479e-01 5.9659498929977417e-01 + <_> + + 0 -1 194 2.6344999670982361e-02 + + -5.5203199386596680e-01 3.0217400193214417e-01 + <_> + + 0 -1 195 -1.5083000063896179e-02 + + -1.2871240377426147e+00 2.2354200482368469e-01 + <_> + + 0 -1 196 -3.8887001574039459e-02 + + 1.7425049543380737e+00 -9.9747002124786377e-02 + <_> + + 0 -1 197 -5.7029998861253262e-03 + + -1.0523240566253662e+00 1.8362599611282349e-01 + <_> + + 0 -1 198 -1.4860000228509307e-03 + + 5.6784200668334961e-01 -4.6742001175880432e-01 + <_> + + 0 -1 199 -2.8486000373959541e-02 + + 1.3082909584045410e+00 -2.6460900902748108e-01 + <_> + + 0 -1 200 6.6224999725818634e-02 + + -4.6210700273513794e-01 4.1749599575996399e-01 + <_> + + 0 -1 201 8.8569996878504753e-03 + + -4.1474899649620056e-01 5.9204798936843872e-01 + <_> + + 0 -1 202 1.1355999857187271e-02 + + 3.6103099584579468e-01 -4.5781201124191284e-01 + <_> + + 0 -1 203 -2.7679998893290758e-03 + + -8.9238899946212769e-01 1.4199000597000122e-01 + <_> + + 0 -1 204 1.1246999725699425e-02 + + 2.9353401064872742e-01 -9.7330600023269653e-01 + <_> + + 0 -1 205 7.1970000863075256e-03 + + -7.9334902763366699e-01 1.8313400447368622e-01 + <_> + + 0 -1 206 3.1768999993801117e-02 + + 1.5523099899291992e-01 -1.3245639801025391e+00 + <_> + + 0 -1 207 2.5173999369144440e-02 + + 3.4214999526739120e-02 -2.0948131084442139e+00 + <_> + + 0 -1 208 7.5360001064836979e-03 + + -3.9450600743293762e-01 5.1333999633789062e-01 + <_> + + 0 -1 209 3.2873000949621201e-02 + + 8.8372997939586639e-02 -1.2814120054244995e+00 + <_> + + 0 -1 210 -2.7379998937249184e-03 + + 5.5286502838134766e-01 -4.6384999155998230e-01 + <_> + + 0 -1 211 -3.8075000047683716e-02 + + -1.8497270345687866e+00 4.5944001525640488e-02 + <_> + + 0 -1 212 -3.8984000682830811e-02 + + -4.8223701119422913e-01 3.4760600328445435e-01 + <_> + + 0 -1 213 2.8029999230057001e-03 + + -4.5154699683189392e-01 4.2806300520896912e-01 + <_> + + 0 -1 214 -5.4145999252796173e-02 + + -8.4520798921585083e-01 1.6674900054931641e-01 + <_> + + 0 -1 215 -8.3280000835657120e-03 + + 3.5348299145698547e-01 -4.7163200378417969e-01 + <_> + + 0 -1 216 3.3778000622987747e-02 + + 1.8463100492954254e-01 -1.6686669588088989e+00 + <_> + + 0 -1 217 -1.1238099634647369e-01 + + -1.2521569728851318e+00 3.5992000252008438e-02 + <_> + + 0 -1 218 -1.0408000089228153e-02 + + -8.1620401144027710e-01 2.3428599536418915e-01 + <_> + + 0 -1 219 -4.9439999274909496e-03 + + -9.2584699392318726e-01 1.0034800320863724e-01 + <_> + + 0 -1 220 -9.3029998242855072e-03 + + 5.6499302387237549e-01 -1.8881900608539581e-01 + <_> + + 0 -1 221 -1.1749999597668648e-02 + + 8.0302399396896362e-01 -3.8277000188827515e-01 + <_> + + 0 -1 222 -2.3217000067234039e-02 + + -8.4926998615264893e-01 1.9671200215816498e-01 + <_> + + 0 -1 223 1.6866000369191170e-02 + + -4.0591898560523987e-01 5.0695300102233887e-01 + <_> + + 0 -1 224 -2.4031000211834908e-02 + + -1.5297520160675049e+00 2.3344999551773071e-01 + <_> + + 0 -1 225 -3.6945998668670654e-02 + + 6.3007700443267822e-01 -3.1780400872230530e-01 + <_> + + 0 -1 226 -6.1563998460769653e-02 + + 5.8627897500991821e-01 -1.2107999995350838e-02 + <_> + + 0 -1 227 2.1661000326275826e-02 + + -2.5623700022697449e-01 1.0409849882125854e+00 + <_> + + 0 -1 228 -3.6710000131279230e-03 + + 2.9171100258827209e-01 -8.3287298679351807e-01 + <_> + + 0 -1 229 4.4849000871181488e-02 + + -3.9633199572563171e-01 4.5662000775337219e-01 + <_> + + 0 -1 230 5.7195000350475311e-02 + + 2.1023899316787720e-01 -1.5004800558090210e+00 + <_> + + 0 -1 231 -1.1342000216245651e-02 + + 4.4071298837661743e-01 -3.8653799891471863e-01 + <_> + + 0 -1 232 -1.2004000134766102e-02 + + 9.3954598903656006e-01 -1.0589499771595001e-01 + <_> + + 0 -1 233 2.2515999153256416e-02 + + 9.4480002298951149e-03 -1.6799509525299072e+00 + <_> + + 0 -1 234 -1.9809000194072723e-02 + + -1.0133639574050903e+00 2.4146600067615509e-01 + <_> + + 0 -1 235 1.5891000628471375e-02 + + -3.7507599592208862e-01 4.6614098548889160e-01 + <_> + + 0 -1 236 -9.1420002281665802e-03 + + -8.0484098196029663e-01 1.7816999554634094e-01 + <_> + + 0 -1 237 -4.4740000739693642e-03 + + -1.0562069416046143e+00 7.3305003345012665e-02 + <_> + + 0 -1 238 1.2742500007152557e-01 + + 2.0165599882602692e-01 -1.5467929840087891e+00 + <_> + + 0 -1 239 4.7703001648187637e-02 + + -3.7937799096107483e-01 3.7885999679565430e-01 + <_> + + 0 -1 240 5.3608000278472900e-02 + + 2.1220499277114868e-01 -1.2399710416793823e+00 + <_> + + 0 -1 241 -3.9680998772382736e-02 + + -1.0257550477981567e+00 5.1282998174428940e-02 + <_> + + 0 -1 242 -6.7327000200748444e-02 + + -1.0304750204086304e+00 2.3005299270153046e-01 + <_> + + 0 -1 243 1.3337600231170654e-01 + + -2.0869000256061554e-01 1.2272510528564453e+00 + <_> + + 0 -1 244 -2.0919300615787506e-01 + + 8.7929898500442505e-01 -4.4254999607801437e-02 + <_> + + 0 -1 245 -6.5589003264904022e-02 + + 1.0443429946899414e+00 -2.1682099997997284e-01 + <_> + + 0 -1 246 6.1882998794317245e-02 + + 1.3798199594020844e-01 -1.9009059667587280e+00 + <_> + + 0 -1 247 -2.5578999891877174e-02 + + -1.6607600450515747e+00 5.8439997956156731e-03 + <_> + + 0 -1 248 -3.4827001392841339e-02 + + 7.9940402507781982e-01 -8.2406997680664062e-02 + <_> + + 0 -1 249 -1.8209999427199364e-02 + + -9.6073997020721436e-01 6.6320002079010010e-02 + <_> + + 0 -1 250 1.5070999972522259e-02 + + 1.9899399578571320e-01 -7.6433002948760986e-01 + <_> + 72 + -3.8832089900970459e+00 + + <_> + + 0 -1 251 4.6324998140335083e-02 + + -1.0362670421600342e+00 8.2201498746871948e-01 + <_> + + 0 -1 252 1.5406999737024307e-02 + + -1.2327589988708496e+00 2.9647698998451233e-01 + <_> + + 0 -1 253 1.2808999978005886e-02 + + -7.5852298736572266e-01 5.7985502481460571e-01 + <_> + + 0 -1 254 4.9150999635457993e-02 + + -3.8983899354934692e-01 8.9680302143096924e-01 + <_> + + 0 -1 255 1.2621000409126282e-02 + + -7.1799302101135254e-01 5.0440901517868042e-01 + <_> + + 0 -1 256 -1.8768999725580215e-02 + + 5.5147600173950195e-01 -7.0555400848388672e-01 + <_> + + 0 -1 257 4.1965000331401825e-02 + + -4.4782099127769470e-01 7.0985502004623413e-01 + <_> + + 0 -1 258 -5.1401998847723007e-02 + + -1.0932120084762573e+00 2.6701900362968445e-01 + <_> + + 0 -1 259 -7.0960998535156250e-02 + + 8.3618402481079102e-01 -3.8318100571632385e-01 + <_> + + 0 -1 260 1.6745999455451965e-02 + + -2.5733101367950439e-01 2.5966501235961914e-01 + <_> + + 0 -1 261 -6.2400000169873238e-03 + + 3.1631499528884888e-01 -5.8796900510787964e-01 + <_> + + 0 -1 262 -3.9397999644279480e-02 + + -1.0491210222244263e+00 1.6822400689125061e-01 + <_> + + 0 -1 263 0. + + 1.6144199669361115e-01 -8.7876898050308228e-01 + <_> + + 0 -1 264 -2.2307999432086945e-02 + + -6.9053500890731812e-01 2.3607000708580017e-01 + <_> + + 0 -1 265 1.8919999711215496e-03 + + 2.4989199638366699e-01 -5.6583297252655029e-01 + <_> + + 0 -1 266 1.0730000212788582e-03 + + -5.0415802001953125e-01 3.8374501466751099e-01 + <_> + + 0 -1 267 3.9230998605489731e-02 + + 4.2619001120328903e-02 -1.3875889778137207e+00 + <_> + + 0 -1 268 6.2238000333309174e-02 + + 1.4119400084018707e-01 -1.0688860416412354e+00 + <_> + + 0 -1 269 2.1399999968707561e-03 + + -8.9622402191162109e-01 1.9796399772167206e-01 + <_> + + 0 -1 270 9.1800000518560410e-04 + + -4.5337298512458801e-01 4.3532699346542358e-01 + <_> + + 0 -1 271 -6.9169998168945312e-03 + + 3.3822798728942871e-01 -4.4793000817298889e-01 + <_> + + 0 -1 272 -2.3866999894380569e-02 + + -7.8908598423004150e-01 2.2511799633502960e-01 + <_> + + 0 -1 273 -1.0262800008058548e-01 + + -2.2831439971923828e+00 -5.3960001096129417e-03 + <_> + + 0 -1 274 -9.5239998772740364e-03 + + 3.9346700906753540e-01 -5.2242201566696167e-01 + <_> + + 0 -1 275 3.9877001196146011e-02 + + 3.2799001783132553e-02 -1.5079489946365356e+00 + <_> + + 0 -1 276 -1.3144999742507935e-02 + + -1.0839990377426147e+00 1.8482400476932526e-01 + <_> + + 0 -1 277 -5.0590999424457550e-02 + + -1.8822289705276489e+00 -2.2199999075382948e-03 + <_> + + 0 -1 278 2.4917000904679298e-02 + + 1.4593400061130524e-01 -2.2196519374847412e+00 + <_> + + 0 -1 279 -7.6370001770555973e-03 + + -1.0164569616317749e+00 5.8797001838684082e-02 + <_> + + 0 -1 280 4.2911998927593231e-02 + + 1.5443000197410583e-01 -1.1843889951705933e+00 + <_> + + 0 -1 281 2.3000000510364771e-04 + + -7.7305799722671509e-01 1.2189900130033493e-01 + <_> + + 0 -1 282 9.0929996222257614e-03 + + -1.1450099945068359e-01 7.1091300249099731e-01 + <_> + + 0 -1 283 1.1145000346004963e-02 + + 7.0000998675823212e-02 -1.0534820556640625e+00 + <_> + + 0 -1 284 -5.2453000098466873e-02 + + -1.7594360113143921e+00 1.9523799419403076e-01 + <_> + + 0 -1 285 -2.3020699620246887e-01 + + 9.5840299129486084e-01 -2.5045698881149292e-01 + <_> + + 0 -1 286 -1.6365999355912209e-02 + + 4.6731901168823242e-01 -2.1108399331569672e-01 + <_> + + 0 -1 287 -1.7208000645041466e-02 + + 7.0835697650909424e-01 -2.8018298745155334e-01 + <_> + + 0 -1 288 -3.6648001521825790e-02 + + -1.1013339757919312e+00 2.4341100454330444e-01 + <_> + + 0 -1 289 -1.0304999537765980e-02 + + -1.0933129787445068e+00 5.6258998811244965e-02 + <_> + + 0 -1 290 -1.3713000342249870e-02 + + -2.6438099145889282e-01 1.9821000099182129e-01 + <_> + + 0 -1 291 2.9308000579476357e-02 + + -2.2142399847507477e-01 1.0525950193405151e+00 + <_> + + 0 -1 292 2.4077000096440315e-02 + + 1.8485699594020844e-01 -1.7203969955444336e+00 + <_> + + 0 -1 293 6.1280000954866409e-03 + + -9.2721498012542725e-01 5.8752998709678650e-02 + <_> + + 0 -1 294 -2.2377999499440193e-02 + + 1.9646559953689575e+00 2.7785999700427055e-02 + <_> + + 0 -1 295 -7.0440000854432583e-03 + + 2.1427600085735321e-01 -4.8407599329948425e-01 + <_> + + 0 -1 296 -4.0603000670671463e-02 + + -1.1754349470138550e+00 1.6061200201511383e-01 + <_> + + 0 -1 297 -2.4466000497341156e-02 + + -1.1239900588989258e+00 4.1110001504421234e-02 + <_> + + 0 -1 298 2.5309999473392963e-03 + + -1.7169700562953949e-01 3.2178801298141479e-01 + <_> + + 0 -1 299 -1.9588999450206757e-02 + + 8.2720202207565308e-01 -2.6376700401306152e-01 + <_> + + 0 -1 300 -2.9635999351739883e-02 + + -1.1524770259857178e+00 1.4999300241470337e-01 + <_> + + 0 -1 301 -1.5030000358819962e-02 + + -1.0491830110549927e+00 4.0160998702049255e-02 + <_> + + 0 -1 302 -6.0715001076459885e-02 + + -1.0903840065002441e+00 1.5330800414085388e-01 + <_> + + 0 -1 303 -1.2790000066161156e-02 + + 4.2248600721359253e-01 -4.2399200797080994e-01 + <_> + + 0 -1 304 -2.0247999578714371e-02 + + -9.1866999864578247e-01 1.8485699594020844e-01 + <_> + + 0 -1 305 -3.0683999881148338e-02 + + -1.5958670377731323e+00 2.5760000571608543e-03 + <_> + + 0 -1 306 -2.0718000829219818e-02 + + -6.6299998760223389e-01 3.1037199497222900e-01 + <_> + + 0 -1 307 -1.7290000105276704e-03 + + 1.9183400273323059e-01 -6.5084999799728394e-01 + <_> + + 0 -1 308 -3.1394001096487045e-02 + + -6.3643002510070801e-01 1.5408399701118469e-01 + <_> + + 0 -1 309 1.9003000110387802e-02 + + -1.8919399380683899e-01 1.5294510126113892e+00 + <_> + + 0 -1 310 6.1769997701048851e-03 + + -1.0597900301218033e-01 6.4859598875045776e-01 + <_> + + 0 -1 311 -1.0165999643504620e-02 + + -1.0802700519561768e+00 3.7176001816987991e-02 + <_> + + 0 -1 312 -1.4169999631121755e-03 + + 3.4157499670982361e-01 -9.7737997770309448e-02 + <_> + + 0 -1 313 -4.0799998678267002e-03 + + 4.7624599933624268e-01 -3.4366300702095032e-01 + <_> + + 0 -1 314 -4.4096998870372772e-02 + + 9.7634297609329224e-01 -1.9173000007867813e-02 + <_> + + 0 -1 315 -6.0669999569654465e-02 + + -2.1752851009368896e+00 -2.8925999999046326e-02 + <_> + + 0 -1 316 -3.2931998372077942e-02 + + -6.4383101463317871e-01 1.6494099795818329e-01 + <_> + + 0 -1 317 -1.4722800254821777e-01 + + -1.4745830297470093e+00 2.5839998852461576e-03 + <_> + + 0 -1 318 -1.1930000036954880e-02 + + 4.2441400885581970e-01 -1.7712600529193878e-01 + <_> + + 0 -1 319 1.4517900347709656e-01 + + 2.5444999337196350e-02 -1.2779400348663330e+00 + <_> + + 0 -1 320 5.1447998732328415e-02 + + 1.5678399801254272e-01 -1.5188430547714233e+00 + <_> + + 0 -1 321 3.1479999888688326e-03 + + -4.0424400568008423e-01 3.2429701089859009e-01 + <_> + + 0 -1 322 -4.3600000441074371e-02 + + -1.9932260513305664e+00 1.5018600225448608e-01 + <_> + 83 + -3.8424909114837646e+00 + + <_> + + 0 -1 323 1.2899599969387054e-01 + + -6.2161999940872192e-01 1.1116520166397095e+00 + <_> + + 0 -1 324 -9.1261997818946838e-02 + + 1.0143059492111206e+00 -6.1335200071334839e-01 + <_> + + 0 -1 325 1.4271999709308147e-02 + + -1.0261659622192383e+00 3.9779999852180481e-01 + <_> + + 0 -1 326 3.2889999449253082e-02 + + -1.1386079788208008e+00 2.8690800070762634e-01 + <_> + + 0 -1 327 1.2590000405907631e-02 + + -5.6645601987838745e-01 4.5172399282455444e-01 + <_> + + 0 -1 328 1.4661000110208988e-02 + + 3.0505999922752380e-01 -6.8129599094390869e-01 + <_> + + 0 -1 329 -3.3555999398231506e-02 + + -1.7208939790725708e+00 6.1439000070095062e-02 + <_> + + 0 -1 330 1.4252699911594391e-01 + + 2.3192200064659119e-01 -1.7297149896621704e+00 + <_> + + 0 -1 331 -6.2079997733235359e-03 + + -1.2163300514221191e+00 1.2160199880599976e-01 + <_> + + 0 -1 332 1.8178999423980713e-02 + + 3.2553699612617493e-01 -8.1003999710083008e-01 + <_> + + 0 -1 333 2.5036999955773354e-02 + + -3.1698799133300781e-01 6.7361402511596680e-01 + <_> + + 0 -1 334 4.6560999006032944e-02 + + -1.1089800298213959e-01 8.4082502126693726e-01 + <_> + + 0 -1 335 -8.9999996125698090e-03 + + 3.9574500918388367e-01 -4.7624599933624268e-01 + <_> + + 0 -1 336 4.0805999189615250e-02 + + -1.8000000272877514e-04 9.4570702314376831e-01 + <_> + + 0 -1 337 -3.4221999347209930e-02 + + 7.5206297636032104e-01 -3.1531500816345215e-01 + <_> + + 0 -1 338 -3.9716001600027084e-02 + + -8.3139598369598389e-01 1.7744399607181549e-01 + <_> + + 0 -1 339 2.5170000735670328e-03 + + -5.9377998113632202e-01 2.4657000601291656e-01 + <_> + + 0 -1 340 2.7428999543190002e-02 + + 1.5998399257659912e-01 -4.2781999707221985e-01 + <_> + + 0 -1 341 3.4986000508069992e-02 + + 3.5055998712778091e-02 -1.5988600254058838e+00 + <_> + + 0 -1 342 4.4970000162720680e-03 + + -5.2034300565719604e-01 3.7828299403190613e-01 + <_> + + 0 -1 343 2.7699999045580626e-03 + + -5.3182601928710938e-01 2.4951000511646271e-01 + <_> + + 0 -1 344 3.5174001008272171e-02 + + 1.9983400404453278e-01 -1.4446129798889160e+00 + <_> + + 0 -1 345 2.5970999151468277e-02 + + 4.4426999986171722e-02 -1.3622980117797852e+00 + <_> + + 0 -1 346 -1.5783999115228653e-02 + + -9.1020399332046509e-01 2.7190300822257996e-01 + <_> + + 0 -1 347 -7.5880000367760658e-03 + + 9.2064999043941498e-02 -8.1628900766372681e-01 + <_> + + 0 -1 348 2.0754000172019005e-02 + + 2.1185700595378876e-01 -7.4729001522064209e-01 + <_> + + 0 -1 349 5.9829000383615494e-02 + + -2.7301099896430969e-01 8.0923300981521606e-01 + <_> + + 0 -1 350 3.9039000868797302e-02 + + -1.0432299971580505e-01 8.6226201057434082e-01 + <_> + + 0 -1 351 2.1665999665856361e-02 + + 6.2709003686904907e-02 -9.8894298076629639e-01 + <_> + + 0 -1 352 -2.7496999129652977e-02 + + -9.2690998315811157e-01 1.5586300194263458e-01 + <_> + + 0 -1 353 1.0462000034749508e-02 + + 1.3418099284172058e-01 -7.0386397838592529e-01 + <_> + + 0 -1 354 2.4870999157428741e-02 + + 1.9706700742244720e-01 -4.0263301134109497e-01 + <_> + + 0 -1 355 -1.6036000102758408e-02 + + -1.1409829854965210e+00 7.3997996747493744e-02 + <_> + + 0 -1 356 4.8627000302076340e-02 + + 1.6990399360656738e-01 -7.2152197360992432e-01 + <_> + + 0 -1 357 1.2619999470189214e-03 + + -4.7389799356460571e-01 2.6254999637603760e-01 + <_> + + 0 -1 358 -8.8035002350807190e-02 + + -2.1606519222259521e+00 1.4554800093173981e-01 + <_> + + 0 -1 359 1.8356999382376671e-02 + + 4.4750999659299850e-02 -1.0766370296478271e+00 + <_> + + 0 -1 360 3.5275001078844070e-02 + + -3.2919000834226608e-02 1.2153890132904053e+00 + <_> + + 0 -1 361 -2.0392900705337524e-01 + + -1.3187999725341797e+00 1.5503999777138233e-02 + <_> + + 0 -1 362 -1.6619000583887100e-02 + + 3.6850199103355408e-01 -1.5283699333667755e-01 + <_> + + 0 -1 363 3.7739001214504242e-02 + + -2.5727799534797668e-01 7.0655298233032227e-01 + <_> + + 0 -1 364 2.2720000706613064e-03 + + -7.7602997422218323e-02 3.3367800712585449e-01 + <_> + + 0 -1 365 -1.4802999794483185e-02 + + -7.8524798154830933e-01 7.6934002339839935e-02 + <_> + + 0 -1 366 -4.8319000750780106e-02 + + 1.7022320032119751e+00 4.9722000956535339e-02 + <_> + + 0 -1 367 -2.9539000242948532e-02 + + 7.7670699357986450e-01 -2.4534299969673157e-01 + <_> + + 0 -1 368 -4.6169001609086990e-02 + + -1.4922779798507690e+00 1.2340000271797180e-01 + <_> + + 0 -1 369 -2.8064999729394913e-02 + + -2.1345369815826416e+00 -2.5797000154852867e-02 + <_> + + 0 -1 370 -5.7339998893439770e-03 + + 5.6982600688934326e-01 -1.2056600302457809e-01 + <_> + + 0 -1 371 -1.0111000388860703e-02 + + 6.7911398410797119e-01 -2.6638001203536987e-01 + <_> + + 0 -1 372 1.1359999887645245e-02 + + 2.4789799749851227e-01 -6.4493000507354736e-01 + <_> + + 0 -1 373 5.1809001713991165e-02 + + 1.4716000296175480e-02 -1.2395579814910889e+00 + <_> + + 0 -1 374 3.3291999250650406e-02 + + -8.2559995353221893e-03 1.0168470144271851e+00 + <_> + + 0 -1 375 -1.4494000002741814e-02 + + 4.5066800713539124e-01 -3.6250999569892883e-01 + <_> + + 0 -1 376 -3.4221999347209930e-02 + + -9.5292502641677856e-01 2.0684599876403809e-01 + <_> + + 0 -1 377 -8.0654002726078033e-02 + + -2.0139501094818115e+00 -2.3084999993443489e-02 + <_> + + 0 -1 378 -8.9399999706074595e-04 + + 3.9572000503540039e-01 -2.9351300001144409e-01 + <_> + + 0 -1 379 9.7162000834941864e-02 + + -2.4980300664901733e-01 1.0859220027923584e+00 + <_> + + 0 -1 380 3.6614000797271729e-02 + + -5.7844001799821854e-02 1.2162159681320190e+00 + <_> + + 0 -1 381 5.1693998277187347e-02 + + 4.3062999844551086e-02 -1.0636160373687744e+00 + <_> + + 0 -1 382 -2.4557000026106834e-02 + + -4.8946800827980042e-01 1.7182900011539459e-01 + <_> + + 0 -1 383 3.2736799120903015e-01 + + -2.9688599705696106e-01 5.1798301935195923e-01 + <_> + + 0 -1 384 7.6959999278187752e-03 + + -5.9805899858474731e-01 2.4803200364112854e-01 + <_> + + 0 -1 385 1.6172200441360474e-01 + + -2.9613999649882317e-02 -2.3162529468536377e+00 + <_> + + 0 -1 386 -4.7889999113976955e-03 + + 3.7457901239395142e-01 -3.2779198884963989e-01 + <_> + + 0 -1 387 -1.8402999266982079e-02 + + -9.9692702293395996e-01 7.2948001325130463e-02 + <_> + + 0 -1 388 7.7665001153945923e-02 + + 1.4175699651241302e-01 -1.7238730192184448e+00 + <_> + + 0 -1 389 1.8921000882983208e-02 + + -2.1273100376129150e-01 1.0165189504623413e+00 + <_> + + 0 -1 390 -7.9397998750209808e-02 + + -1.3164349794387817e+00 1.4981999993324280e-01 + <_> + + 0 -1 391 -6.8037003278732300e-02 + + 4.9421998858451843e-01 -2.9091000556945801e-01 + <_> + + 0 -1 392 -6.1010001227259636e-03 + + 4.2430499196052551e-01 -3.3899301290512085e-01 + <_> + + 0 -1 393 3.1927000731229782e-02 + + -3.1046999618411064e-02 -2.3459999561309814e+00 + <_> + + 0 -1 394 -2.9843999072909355e-02 + + -7.8989601135253906e-01 1.5417699515819550e-01 + <_> + + 0 -1 395 -8.0541998147964478e-02 + + -2.2509229183197021e+00 -3.0906999483704567e-02 + <_> + + 0 -1 396 3.8109999150037766e-03 + + -2.5577300786972046e-01 2.3785500228404999e-01 + <_> + + 0 -1 397 3.3647000789642334e-02 + + -2.2541399300098419e-01 9.2307400703430176e-01 + <_> + + 0 -1 398 8.2809999585151672e-03 + + -2.8896200656890869e-01 3.1046199798583984e-01 + <_> + + 0 -1 399 1.0104399919509888e-01 + + -3.4864000976085663e-02 -2.7102620601654053e+00 + <_> + + 0 -1 400 -1.0009000077843666e-02 + + 5.9715402126312256e-01 -3.3831000328063965e-02 + <_> + + 0 -1 401 7.1919998154044151e-03 + + -4.7738000750541687e-01 2.2686000168323517e-01 + <_> + + 0 -1 402 2.4969000369310379e-02 + + 2.2877700626850128e-01 -1.0435529947280884e+00 + <_> + + 0 -1 403 2.7908000349998474e-01 + + -2.5818100571632385e-01 7.6780498027801514e-01 + <_> + + 0 -1 404 -4.4213000684976578e-02 + + -5.9798002243041992e-01 2.8039899468421936e-01 + <_> + + 0 -1 405 -1.4136999845504761e-02 + + 7.0987302064895630e-01 -2.5645199418067932e-01 + <_> + 91 + -3.6478610038757324e+00 + + <_> + + 0 -1 406 1.3771200180053711e-01 + + -5.5870598554611206e-01 1.0953769683837891e+00 + <_> + + 0 -1 407 3.4460999071598053e-02 + + -7.1171897649765015e-01 5.2899599075317383e-01 + <_> + + 0 -1 408 1.8580000847578049e-02 + + -1.1157519817352295e+00 4.0593999624252319e-01 + <_> + + 0 -1 409 2.5041999295353889e-02 + + -4.0892499685287476e-01 7.4129998683929443e-01 + <_> + + 0 -1 410 5.7179000228643417e-02 + + -3.8054299354553223e-01 7.3647701740264893e-01 + <_> + + 0 -1 411 1.4932000078260899e-02 + + -6.9945502281188965e-01 3.7950998544692993e-01 + <_> + + 0 -1 412 8.8900001719594002e-03 + + -5.4558598995208740e-01 3.6332499980926514e-01 + <_> + + 0 -1 413 3.0435999855399132e-02 + + -1.0124599933624268e-01 7.9585897922515869e-01 + <_> + + 0 -1 414 -4.4160000979900360e-02 + + 8.4410899877548218e-01 -3.2976400852203369e-01 + <_> + + 0 -1 415 1.8461000174283981e-02 + + 2.6326599717140198e-01 -9.6736502647399902e-01 + <_> + + 0 -1 416 1.0614999569952488e-02 + + 1.5251900255680084e-01 -1.0589870214462280e+00 + <_> + + 0 -1 417 -4.5974001288414001e-02 + + -1.9918340444564819e+00 1.3629099726676941e-01 + <_> + + 0 -1 418 8.2900002598762512e-02 + + -3.2037198543548584e-01 6.0304200649261475e-01 + <_> + + 0 -1 419 -8.9130001142621040e-03 + + 5.9586602449417114e-01 -2.1139599382877350e-01 + <_> + + 0 -1 420 4.2814001441001892e-02 + + 2.2925000637769699e-02 -1.4679330587387085e+00 + <_> + + 0 -1 421 -8.7139997631311417e-03 + + -4.3989500403404236e-01 2.0439699292182922e-01 + <_> + + 0 -1 422 -4.3390002101659775e-03 + + -8.9066797494888306e-01 1.0469999909400940e-01 + <_> + + 0 -1 423 8.0749997869133949e-03 + + 2.1164199709892273e-01 -4.0231600403785706e-01 + <_> + + 0 -1 424 9.6739001572132111e-02 + + 1.3319999910891056e-02 -1.6085360050201416e+00 + <_> + + 0 -1 425 -3.0536999925971031e-02 + + 1.0063740015029907e+00 -1.3413299620151520e-01 + <_> + + 0 -1 426 -6.0855999588966370e-02 + + -1.4689979553222656e+00 9.4240000471472740e-03 + <_> + + 0 -1 427 -3.8162000477313995e-02 + + -8.1636399030685425e-01 2.6171201467514038e-01 + <_> + + 0 -1 428 -9.6960002556443214e-03 + + 1.1561699956655502e-01 -7.1693199872970581e-01 + <_> + + 0 -1 429 4.8902999609708786e-02 + + 1.3050499558448792e-01 -1.6448370218276978e+00 + <_> + + 0 -1 430 -4.1611999273300171e-02 + + -1.1795840263366699e+00 2.5017000734806061e-02 + <_> + + 0 -1 431 -2.0188000053167343e-02 + + 6.3188201189041138e-01 -1.0490400344133377e-01 + <_> + + 0 -1 432 -9.7900000400841236e-04 + + 1.8507799506187439e-01 -5.3565901517868042e-01 + <_> + + 0 -1 433 -3.3622000366449356e-02 + + -9.3127602338790894e-01 2.0071500539779663e-01 + <_> + + 0 -1 434 1.9455999135971069e-02 + + 3.8029000163078308e-02 -1.0112210512161255e+00 + <_> + + 0 -1 435 -3.1800000579096377e-04 + + 3.6457699537277222e-01 -2.7610900998115540e-01 + <_> + + 0 -1 436 -3.8899999344721437e-04 + + 1.9665899872779846e-01 -5.3410500288009644e-01 + <_> + + 0 -1 437 -9.3496002256870270e-02 + + -1.6772350072860718e+00 2.0727099478244781e-01 + <_> + + 0 -1 438 -7.7877998352050781e-02 + + -3.0760629177093506e+00 -3.5803999751806259e-02 + <_> + + 0 -1 439 1.6947999596595764e-02 + + 2.1447399258613586e-01 -7.1376299858093262e-01 + <_> + + 0 -1 440 -2.1459000185132027e-02 + + -1.1468060016632080e+00 1.5855999663472176e-02 + <_> + + 0 -1 441 -1.2865999713540077e-02 + + 8.3812397718429565e-01 -6.5944001078605652e-02 + <_> + + 0 -1 442 7.8220004215836525e-03 + + -2.8026801347732544e-01 7.9376900196075439e-01 + <_> + + 0 -1 443 1.0294400155544281e-01 + + 1.7832300066947937e-01 -6.8412202596664429e-01 + <_> + + 0 -1 444 -3.7487998604774475e-02 + + 9.6189999580383301e-01 -2.1735599637031555e-01 + <_> + + 0 -1 445 2.5505999103188515e-02 + + 1.0103999637067318e-02 1.2461110353469849e+00 + <_> + + 0 -1 446 6.6700001480057836e-04 + + -5.3488200902938843e-01 1.4746299386024475e-01 + <_> + + 0 -1 447 -2.8867900371551514e-01 + + 8.2172799110412598e-01 -1.4948000200092793e-02 + <_> + + 0 -1 448 9.1294996440410614e-02 + + -1.9605399668216705e-01 1.0803170204162598e+00 + <_> + + 0 -1 449 1.2056600302457809e-01 + + -2.3848999291658401e-02 1.1392610073089600e+00 + <_> + + 0 -1 450 -7.3775000870227814e-02 + + -1.3583840131759644e+00 -4.2039998807013035e-03 + <_> + + 0 -1 451 -3.3128000795841217e-02 + + -6.4483201503753662e-01 2.4142199754714966e-01 + <_> + + 0 -1 452 -4.3937001377344131e-02 + + 8.4285402297973633e-01 -2.0624800026416779e-01 + <_> + + 0 -1 453 1.8110199272632599e-01 + + 1.9212099909782410e-01 -1.2222139835357666e+00 + <_> + + 0 -1 454 -1.1850999668240547e-02 + + -7.2677397727966309e-01 5.2687998861074448e-02 + <_> + + 0 -1 455 4.5920000411570072e-03 + + -3.6305201053619385e-01 2.9223799705505371e-01 + <_> + + 0 -1 456 7.0620002225041389e-03 + + 5.8116000145673752e-02 -6.7161601781845093e-01 + <_> + + 0 -1 457 -2.3715000599622726e-02 + + 4.7142100334167480e-01 1.8580000847578049e-02 + <_> + + 0 -1 458 -6.7171998322010040e-02 + + -1.1331889629364014e+00 2.3780999705195427e-02 + <_> + + 0 -1 459 -6.5310001373291016e-02 + + 9.8253500461578369e-01 2.8362000361084938e-02 + <_> + + 0 -1 460 2.2791000083088875e-02 + + -2.8213700652122498e-01 5.8993399143218994e-01 + <_> + + 0 -1 461 -1.9037999212741852e-02 + + -6.3711500167846680e-01 2.6514598727226257e-01 + <_> + + 0 -1 462 -6.8689999170601368e-03 + + 3.7487301230430603e-01 -3.3232098817825317e-01 + <_> + + 0 -1 463 -4.0146000683307648e-02 + + -1.3048729896545410e+00 1.5724299848079681e-01 + <_> + + 0 -1 464 -4.0530998259782791e-02 + + -2.0458049774169922e+00 -2.6925999671220779e-02 + <_> + + 0 -1 465 -1.2253999710083008e-02 + + 7.7649402618408203e-01 -4.2971000075340271e-02 + <_> + + 0 -1 466 -2.7219999581575394e-02 + + 1.7424400150775909e-01 -4.4600901007652283e-01 + <_> + + 0 -1 467 -8.8366001844406128e-02 + + -1.5036419630050659e+00 1.4289900660514832e-01 + <_> + + 0 -1 468 -7.9159997403621674e-03 + + 2.8666698932647705e-01 -3.7923699617385864e-01 + <_> + + 0 -1 469 -4.1960000991821289e-02 + + 1.3846950531005859e+00 6.5026998519897461e-02 + <_> + + 0 -1 470 4.5662999153137207e-02 + + -2.2452299296855927e-01 7.9521000385284424e-01 + <_> + + 0 -1 471 -1.4090600609779358e-01 + + -1.5879319906234741e+00 1.1359000205993652e-01 + <_> + + 0 -1 472 -5.9216000139713287e-02 + + -1.1945960521697998e+00 -7.1640000678598881e-03 + <_> + + 0 -1 473 4.3390002101659775e-03 + + -1.5528699755668640e-01 4.0664499998092651e-01 + <_> + + 0 -1 474 -2.0369999110698700e-03 + + 2.5927901268005371e-01 -3.8368299603462219e-01 + <_> + + 0 -1 475 2.7516499161720276e-01 + + -8.8497996330261230e-02 7.6787501573562622e-01 + <_> + + 0 -1 476 -2.6601999998092651e-02 + + 7.5024497509002686e-01 -2.2621999680995941e-01 + <_> + + 0 -1 477 4.0906000882387161e-02 + + 1.2158600240945816e-01 -1.4566910266876221e+00 + <_> + + 0 -1 478 5.5320002138614655e-03 + + -3.6611500382423401e-01 2.5968599319458008e-01 + <_> + + 0 -1 479 3.1879000365734100e-02 + + -7.5019001960754395e-02 4.8484799265861511e-01 + <_> + + 0 -1 480 -4.1482001543045044e-02 + + 7.8220397233963013e-01 -2.1992200613021851e-01 + <_> + + 0 -1 481 -9.6130996942520142e-02 + + -8.9456301927566528e-01 1.4680700004100800e-01 + <_> + + 0 -1 482 -1.1568999849259853e-02 + + 8.2714098691940308e-01 -2.0275600254535675e-01 + <_> + + 0 -1 483 1.8312999978661537e-02 + + 1.6367999836802483e-02 2.7306801080703735e-01 + <_> + + 0 -1 484 -3.4166000783443451e-02 + + 1.1307320594787598e+00 -1.8810899555683136e-01 + <_> + + 0 -1 485 -2.4476999416947365e-02 + + -5.7791298627853394e-01 1.5812499821186066e-01 + <_> + + 0 -1 486 4.8957001417875290e-02 + + -2.2564999759197235e-02 -1.6373280286788940e+00 + <_> + + 0 -1 487 -2.0702999085187912e-02 + + -5.4512101411819458e-01 2.4086999893188477e-01 + <_> + + 0 -1 488 -2.3002000525593758e-02 + + -1.2236540317535400e+00 -7.3440000414848328e-03 + <_> + + 0 -1 489 6.4585000276565552e-02 + + 1.4695599675178528e-01 -4.4967499375343323e-01 + <_> + + 0 -1 490 1.2666000053286552e-02 + + -2.7873900532722473e-01 4.3876600265502930e-01 + <_> + + 0 -1 491 -1.2002999894320965e-02 + + -2.4289099872112274e-01 2.5350099802017212e-01 + <_> + + 0 -1 492 -2.6443999260663986e-02 + + -8.5864800214767456e-01 2.6025999337434769e-02 + <_> + + 0 -1 493 -2.5547999888658524e-02 + + 6.9287902116775513e-01 -2.1160000469535589e-03 + <_> + + 0 -1 494 3.9115000516176224e-02 + + -1.6589100658893585e-01 1.5209139585494995e+00 + <_> + + 0 -1 495 -6.0330000706017017e-03 + + 4.3856900930404663e-01 -2.1613700687885284e-01 + <_> + + 0 -1 496 -3.3936999738216400e-02 + + -9.7998398542404175e-01 2.2133000195026398e-02 + <_> + 99 + -3.8700489997863770e+00 + + <_> + + 0 -1 497 4.0672998875379562e-02 + + -9.0474700927734375e-01 6.4410597085952759e-01 + <_> + + 0 -1 498 2.5609999895095825e-02 + + -7.9216998815536499e-01 5.7489997148513794e-01 + <_> + + 0 -1 499 1.9959500432014465e-01 + + -3.0099600553512573e-01 1.3143850564956665e+00 + <_> + + 0 -1 500 1.2404999695718288e-02 + + -8.9882999658584595e-01 2.9205799102783203e-01 + <_> + + 0 -1 501 3.9207998663187027e-02 + + -4.1955199837684631e-01 5.3463298082351685e-01 + <_> + + 0 -1 502 -3.0843999236822128e-02 + + 4.5793399214744568e-01 -4.4629099965095520e-01 + <_> + + 0 -1 503 -3.5523001104593277e-02 + + 9.1310501098632812e-01 -2.7373200654983521e-01 + <_> + + 0 -1 504 -6.1650000512599945e-02 + + -1.4697799682617188e+00 2.0364099740982056e-01 + <_> + + 0 -1 505 -1.1739999987185001e-02 + + -1.0482879877090454e+00 6.7801997065544128e-02 + <_> + + 0 -1 506 6.6933996975421906e-02 + + 2.9274499416351318e-01 -5.2282899618148804e-01 + <_> + + 0 -1 507 -2.0631000399589539e-02 + + -1.2855139970779419e+00 4.4550999999046326e-02 + <_> + + 0 -1 508 -2.2357000038027763e-02 + + -8.5753798484802246e-01 1.8434000015258789e-01 + <_> + + 0 -1 509 1.1500000255182385e-03 + + 1.6405500471591949e-01 -6.9125002622604370e-01 + <_> + + 0 -1 510 3.5872999578714371e-02 + + 1.5756499767303467e-01 -8.4262597560882568e-01 + <_> + + 0 -1 511 3.0659999698400497e-02 + + 2.1637000143527985e-02 -1.3634690046310425e+00 + <_> + + 0 -1 512 5.5559999309480190e-03 + + -1.6737000644207001e-01 2.5888401269912720e-01 + <_> + + 0 -1 513 -6.1160000041127205e-03 + + -9.7271800041198730e-01 6.6100001335144043e-02 + <_> + + 0 -1 514 -3.0316999182105064e-02 + + 9.8474198579788208e-01 -1.6448000445961952e-02 + <_> + + 0 -1 515 -9.7200004383921623e-03 + + 4.7604700922966003e-01 -3.2516700029373169e-01 + <_> + + 0 -1 516 -5.7126998901367188e-02 + + -9.5920699834823608e-01 1.9938200712203979e-01 + <_> + + 0 -1 517 4.0059997700154781e-03 + + -5.2612501382827759e-01 2.2428700327873230e-01 + <_> + + 0 -1 518 3.3734001219272614e-02 + + 1.7070099711418152e-01 -1.0737580060958862e+00 + <_> + + 0 -1 519 -3.4641999751329422e-02 + + -1.1343129873275757e+00 3.6540001630783081e-02 + <_> + + 0 -1 520 4.6923000365495682e-02 + + 2.5832301378250122e-01 -7.1535801887512207e-01 + <_> + + 0 -1 521 -8.7660001590847969e-03 + + 1.9640900194644928e-01 -5.3355097770690918e-01 + <_> + + 0 -1 522 6.5627999603748322e-02 + + -5.1194999366998672e-02 9.7610700130462646e-01 + <_> + + 0 -1 523 -4.4165000319480896e-02 + + 1.0631920099258423e+00 -2.3462599515914917e-01 + <_> + + 0 -1 524 1.7304999753832817e-02 + + -1.8582899868488312e-01 4.5889899134635925e-01 + <_> + + 0 -1 525 3.3135998994112015e-02 + + -2.9381999745965004e-02 -2.6651329994201660e+00 + <_> + + 0 -1 526 -2.1029999479651451e-02 + + 9.9979901313781738e-01 2.4937000125646591e-02 + <_> + + 0 -1 527 2.9783999547362328e-02 + + -2.9605999588966370e-02 -2.1695868968963623e+00 + <_> + + 0 -1 528 5.5291999131441116e-02 + + -7.5599999399855733e-04 7.4651998281478882e-01 + <_> + + 0 -1 529 -3.3597998321056366e-02 + + -1.5274159908294678e+00 1.1060000397264957e-02 + <_> + + 0 -1 530 1.9602999091148376e-02 + + 3.3574998378753662e-02 9.9526202678680420e-01 + <_> + + 0 -1 531 -2.0787000656127930e-02 + + 7.6612901687622070e-01 -2.4670800566673279e-01 + <_> + + 0 -1 532 3.2536000013351440e-02 + + 1.6263400018215179e-01 -6.1134302616119385e-01 + <_> + + 0 -1 533 -1.0788000188767910e-02 + + -9.7839701175689697e-01 2.8969999402761459e-02 + <_> + + 0 -1 534 -9.9560003727674484e-03 + + 4.6145799756050110e-01 -1.3510499894618988e-01 + <_> + + 0 -1 535 -3.7489999085664749e-03 + + 2.5458198785781860e-01 -5.1955598592758179e-01 + <_> + + 0 -1 536 -4.1779998689889908e-02 + + -8.0565100908279419e-01 1.5208500623703003e-01 + <_> + + 0 -1 537 -3.4221000969409943e-02 + + -1.3137799501419067e+00 -3.5800000187009573e-03 + <_> + + 0 -1 538 1.0130000300705433e-02 + + 2.0175799727439880e-01 -6.1339598894119263e-01 + <_> + + 0 -1 539 -8.9849002659320831e-02 + + 9.7632801532745361e-01 -2.0884799957275391e-01 + <_> + + 0 -1 540 2.6097999885678291e-02 + + -1.8807999789714813e-01 4.7705799341201782e-01 + <_> + + 0 -1 541 -3.7539999466389418e-03 + + -6.7980402708053589e-01 1.1288800090551376e-01 + <_> + + 0 -1 542 3.1973000615835190e-02 + + 1.8951700627803802e-01 -1.4967479705810547e+00 + <_> + + 0 -1 543 1.9332999363541603e-02 + + -2.3609900474548340e-01 8.1320500373840332e-01 + <_> + + 0 -1 544 1.9490000559017062e-03 + + 2.4830399453639984e-01 -6.9211997091770172e-02 + <_> + + 0 -1 545 -4.4146999716758728e-02 + + -1.0418920516967773e+00 4.8053000122308731e-02 + <_> + + 0 -1 546 -4.4681999832391739e-02 + + 5.1346302032470703e-01 -7.3799998499453068e-03 + <_> + + 0 -1 547 -1.0757499933242798e-01 + + 1.6202019453048706e+00 -1.8667599558830261e-01 + <_> + + 0 -1 548 -1.2846800684928894e-01 + + 2.9869480133056641e+00 9.5427997410297394e-02 + <_> + + 0 -1 549 -4.4757999479770660e-02 + + 6.0405302047729492e-01 -2.7058699727058411e-01 + <_> + + 0 -1 550 -4.3990999460220337e-02 + + -6.1790502071380615e-01 1.5997199714183807e-01 + <_> + + 0 -1 551 -1.2268999963998795e-01 + + 6.6327202320098877e-01 -2.3636999726295471e-01 + <_> + + 0 -1 552 -1.9982999190688133e-02 + + -1.1228660345077515e+00 1.9616700708866119e-01 + <_> + + 0 -1 553 -1.5527999959886074e-02 + + -1.0770269632339478e+00 2.0693000406026840e-02 + <_> + + 0 -1 554 -4.8971001058816910e-02 + + 8.1168299913406372e-01 -1.7252000048756599e-02 + <_> + + 0 -1 555 5.5975999683141708e-02 + + -2.2529000416398048e-02 -1.7356760501861572e+00 + <_> + + 0 -1 556 -9.8580000922083855e-03 + + 6.7881399393081665e-01 -5.8180000633001328e-02 + <_> + + 0 -1 557 1.3481000438332558e-02 + + 5.7847999036312103e-02 -7.7255302667617798e-01 + <_> + + 0 -1 558 6.5609999001026154e-03 + + -1.3146899640560150e-01 6.7055797576904297e-01 + <_> + + 0 -1 559 7.1149999275803566e-03 + + -3.7880599498748779e-01 3.0978998541831970e-01 + <_> + + 0 -1 560 4.8159998841583729e-03 + + -5.8470398187637329e-01 2.5602099299430847e-01 + <_> + + 0 -1 561 9.5319999381899834e-03 + + -3.0217000842094421e-01 4.1253298521041870e-01 + <_> + + 0 -1 562 -2.7474999427795410e-02 + + 5.9154701232910156e-01 1.7963999882340431e-02 + <_> + + 0 -1 563 -3.9519999176263809e-02 + + 9.6913498640060425e-01 -2.1020300686359406e-01 + <_> + + 0 -1 564 -3.0658999457955360e-02 + + 9.1155898571014404e-01 4.0550000965595245e-02 + <_> + + 0 -1 565 -1.4680000022053719e-03 + + -6.0489797592163086e-01 1.6960899531841278e-01 + <_> + + 0 -1 566 1.9077600538730621e-01 + + 4.3515000492334366e-02 8.1892901659011841e-01 + <_> + + 0 -1 567 5.1790000870823860e-03 + + -9.3617302179336548e-01 2.4937000125646591e-02 + <_> + + 0 -1 568 2.4126000702381134e-02 + + 1.8175500631332397e-01 -3.4185901284217834e-01 + <_> + + 0 -1 569 -2.6383999735116959e-02 + + -1.2912579774856567e+00 -3.4280000254511833e-03 + <_> + + 0 -1 570 5.4139997810125351e-03 + + -4.6291999518871307e-02 2.5269600749015808e-01 + <_> + + 0 -1 571 5.4216001182794571e-02 + + -1.2848000042140484e-02 -1.4304540157318115e+00 + <_> + + 0 -1 572 2.3799999326001853e-04 + + -2.6676699519157410e-01 3.3588299155235291e-01 + <_> + + 0 -1 573 1.5216999687254429e-02 + + -5.1367300748825073e-01 1.3005100190639496e-01 + <_> + + 0 -1 574 1.7007999122142792e-02 + + 4.1575899720191956e-01 -3.1241199374198914e-01 + <_> + + 0 -1 575 3.0496999621391296e-02 + + -2.4820999801158905e-01 7.0828497409820557e-01 + <_> + + 0 -1 576 6.5430002287030220e-03 + + -2.2637000679969788e-01 1.9184599816799164e-01 + <_> + + 0 -1 577 1.4163999259471893e-01 + + 6.5227001905441284e-02 -8.8809502124786377e-01 + <_> + + 0 -1 578 1.9338000565767288e-02 + + 1.8891200423240662e-01 -2.7397701144218445e-01 + <_> + + 0 -1 579 -1.7324000597000122e-02 + + -9.4866698980331421e-01 2.4196999147534370e-02 + <_> + + 0 -1 580 -6.2069999985396862e-03 + + 3.6938399076461792e-01 -1.7494900524616241e-01 + <_> + + 0 -1 581 -1.6109000891447067e-02 + + 9.6159499883651733e-01 -2.0005300641059875e-01 + <_> + + 0 -1 582 -1.0122500360012054e-01 + + -3.0699110031127930e+00 1.1363799870014191e-01 + <_> + + 0 -1 583 -7.5509999878704548e-03 + + 2.2921000421047211e-01 -4.5645099878311157e-01 + <_> + + 0 -1 584 4.4247999787330627e-02 + + -3.1599999056197703e-04 3.9225301146507263e-01 + <_> + + 0 -1 585 -1.1636000126600266e-01 + + 9.5233702659606934e-01 -2.0201599597930908e-01 + <_> + + 0 -1 586 4.7360002063214779e-03 + + -9.9177002906799316e-02 2.0370499789714813e-01 + <_> + + 0 -1 587 2.2459000349044800e-02 + + 8.7280003353953362e-03 -1.0217070579528809e+00 + <_> + + 0 -1 588 -1.2109000235795975e-02 + + 6.4812600612640381e-01 -9.0149000287055969e-02 + <_> + + 0 -1 589 5.6120000779628754e-02 + + -3.6759998649358749e-02 -1.9275590181350708e+00 + <_> + + 0 -1 590 -8.7379999458789825e-03 + + 6.9261300563812256e-01 -6.8374998867511749e-02 + <_> + + 0 -1 591 6.6399998031556606e-03 + + -4.0569800138473511e-01 1.8625700473785400e-01 + <_> + + 0 -1 592 -1.8131999298930168e-02 + + -6.4518201351165771e-01 2.1976399421691895e-01 + <_> + + 0 -1 593 -2.2718999534845352e-02 + + 9.7776198387145996e-01 -1.8654300272464752e-01 + <_> + + 0 -1 594 1.2705000117421150e-02 + + -1.0546600073575974e-01 3.7404099106788635e-01 + <_> + + 0 -1 595 -1.3682999648153782e-02 + + 6.1064100265502930e-01 -2.6881098747253418e-01 + <_> + 115 + -3.7160909175872803e+00 + + <_> + + 0 -1 596 3.1357999891042709e-02 + + -1.0183910131454468e+00 5.7528597116470337e-01 + <_> + + 0 -1 597 9.3050003051757812e-02 + + -4.1297501325607300e-01 1.0091199874877930e+00 + <_> + + 0 -1 598 2.5949999690055847e-02 + + -5.8587902784347534e-01 5.6606197357177734e-01 + <_> + + 0 -1 599 1.6472000628709793e-02 + + -9.2857497930526733e-01 3.0924499034881592e-01 + <_> + + 0 -1 600 -1.8779999809339643e-03 + + 1.1951000243425369e-01 -1.1180130243301392e+00 + <_> + + 0 -1 601 -9.0129999443888664e-03 + + -5.7849502563476562e-01 3.3154401183128357e-01 + <_> + + 0 -1 602 2.2547999396920204e-02 + + -3.8325101137161255e-01 5.2462202310562134e-01 + <_> + + 0 -1 603 -3.7780001759529114e-02 + + 1.1790670156478882e+00 -3.4166999161243439e-02 + <_> + + 0 -1 604 -5.3799999877810478e-03 + + -8.6265897750854492e-01 1.1867900192737579e-01 + <_> + + 0 -1 605 -2.3893000558018684e-02 + + -7.4950599670410156e-01 2.1011400222778320e-01 + <_> + + 0 -1 606 -2.6521999388933182e-02 + + 9.2128598690032959e-01 -2.8252801299095154e-01 + <_> + + 0 -1 607 1.2280000373721123e-02 + + 2.6662799715995789e-01 -7.0013600587844849e-01 + <_> + + 0 -1 608 9.6594996750354767e-02 + + -2.8453999757766724e-01 7.3168998956680298e-01 + <_> + + 0 -1 609 -2.7414999902248383e-02 + + -6.1492699384689331e-01 1.5576200187206268e-01 + <_> + + 0 -1 610 -1.5767000615596771e-02 + + 5.7551199197769165e-01 -3.4362199902534485e-01 + <_> + + 0 -1 611 -2.1100000012665987e-03 + + 3.2599699497222900e-01 -1.3008299469947815e-01 + <_> + + 0 -1 612 1.2006999924778938e-02 + + 8.9322999119758606e-02 -9.6025598049163818e-01 + <_> + + 0 -1 613 -1.5421999618411064e-02 + + 3.4449499845504761e-01 -4.6711999177932739e-01 + <_> + + 0 -1 614 -4.1579999960958958e-03 + + 2.3696300387382507e-01 -5.2563297748565674e-01 + <_> + + 0 -1 615 -2.1185999736189842e-02 + + -7.4267697334289551e-01 2.1702000498771667e-01 + <_> + + 0 -1 616 -1.7077000811696053e-02 + + -9.0471798181533813e-01 6.6012002527713776e-02 + <_> + + 0 -1 617 -4.0849998593330383e-02 + + -3.4446600079536438e-01 2.1503700315952301e-01 + <_> + + 0 -1 618 -8.1930002197623253e-03 + + -9.3388599157333374e-01 5.0471000373363495e-02 + <_> + + 0 -1 619 -1.9238000735640526e-02 + + -5.3203701972961426e-01 1.7240600287914276e-01 + <_> + + 0 -1 620 -4.4192001223564148e-02 + + 9.2075002193450928e-01 -2.2148500382900238e-01 + <_> + + 0 -1 621 -6.2392000108957291e-02 + + -7.1053802967071533e-01 1.8323899805545807e-01 + <_> + + 0 -1 622 -1.0079999919980764e-03 + + -8.7063097953796387e-01 5.5330000817775726e-02 + <_> + + 0 -1 623 2.3870000615715981e-02 + + -2.2854200005531311e-01 5.2415597438812256e-01 + <_> + + 0 -1 624 2.1391000598669052e-02 + + -3.0325898528099060e-01 5.5860602855682373e-01 + <_> + + 0 -1 625 2.0254999399185181e-02 + + 2.6901501417160034e-01 -7.0261800289154053e-01 + <_> + + 0 -1 626 -2.8772000223398209e-02 + + -1.1835030317306519e+00 4.6512000262737274e-02 + <_> + + 0 -1 627 3.4199999645352364e-03 + + -5.4652100801467896e-01 2.5962498784065247e-01 + <_> + + 0 -1 628 5.6983001530170441e-02 + + -2.6982900500297546e-01 5.8170700073242188e-01 + <_> + + 0 -1 629 -9.3892000615596771e-02 + + -9.1046398878097534e-01 1.9677700102329254e-01 + <_> + + 0 -1 630 1.7699999734759331e-02 + + -4.4003298878669739e-01 2.1349500119686127e-01 + <_> + + 0 -1 631 2.2844199836254120e-01 + + 2.3605000227689743e-02 7.7171599864959717e-01 + <_> + + 0 -1 632 -1.8287500739097595e-01 + + 7.9228597879409790e-01 -2.4644799530506134e-01 + <_> + + 0 -1 633 -6.9891996681690216e-02 + + 8.0267798900604248e-01 -3.6072000861167908e-02 + <_> + + 0 -1 634 1.5297000296413898e-02 + + -2.0072300732135773e-01 1.1030600070953369e+00 + <_> + + 0 -1 635 6.7500001750886440e-03 + + -4.5967999845743179e-02 7.2094500064849854e-01 + <_> + + 0 -1 636 -1.5983000397682190e-02 + + -9.0357202291488647e-01 4.4987998902797699e-02 + <_> + + 0 -1 637 1.3088000006973743e-02 + + 3.5297098755836487e-01 -3.7710601091384888e-01 + <_> + + 0 -1 638 1.3061000034213066e-02 + + -1.9583599269390106e-01 1.1198940277099609e+00 + <_> + + 0 -1 639 -3.9907000958919525e-02 + + -1.3998429775238037e+00 1.9145099818706512e-01 + <_> + + 0 -1 640 1.5026999637484550e-02 + + 2.3600000422447920e-03 -1.1611249446868896e+00 + <_> + + 0 -1 641 -2.0517999306321144e-02 + + -4.8908099532127380e-01 1.6743400692939758e-01 + <_> + + 0 -1 642 -2.2359000518918037e-02 + + -1.2202980518341064e+00 -1.1975999921560287e-02 + <_> + + 0 -1 643 -7.9150004312396049e-03 + + 3.7228098511695862e-01 -8.5063003003597260e-02 + <_> + + 0 -1 644 1.5258000232279301e-02 + + -2.9412600398063660e-01 5.9406399726867676e-01 + <_> + + 0 -1 645 -3.1665999442338943e-02 + + -1.4395569562911987e+00 1.3578799366950989e-01 + <_> + + 0 -1 646 -3.0773999169468880e-02 + + -2.2545371055603027e+00 -3.3971000462770462e-02 + <_> + + 0 -1 647 -1.5483000315725803e-02 + + 3.7700700759887695e-01 1.5847999602556229e-02 + <_> + + 0 -1 648 3.5167001187801361e-02 + + -2.9446101188659668e-01 5.3159099817276001e-01 + <_> + + 0 -1 649 -1.7906000837683678e-02 + + -9.9788200855255127e-01 1.6235999763011932e-01 + <_> + + 0 -1 650 -3.1799999997019768e-03 + + 4.7657001763582230e-02 -7.5249898433685303e-01 + <_> + + 0 -1 651 1.5720000490546227e-02 + + 1.4873799681663513e-01 -6.5375399589538574e-01 + <_> + + 0 -1 652 2.9864000156521797e-02 + + -1.4952000230550766e-02 -1.2275190353393555e+00 + <_> + + 0 -1 653 2.9899999499320984e-03 + + -1.4263699948787689e-01 4.3272799253463745e-01 + <_> + + 0 -1 654 8.4749996662139893e-02 + + -1.9280999898910522e-02 -1.1946409940719604e+00 + <_> + + 0 -1 655 -5.8724999427795410e-02 + + -1.7328219413757324e+00 1.4374700188636780e-01 + <_> + + 0 -1 656 4.4755998998880386e-02 + + -2.4140599370002747e-01 5.4019999504089355e-01 + <_> + + 0 -1 657 4.0369000285863876e-02 + + 5.7680001482367516e-03 5.6578099727630615e-01 + <_> + + 0 -1 658 3.7735998630523682e-02 + + 3.8180999457836151e-02 -7.9370397329330444e-01 + <_> + + 0 -1 659 6.0752999037504196e-02 + + 7.6453000307083130e-02 1.4813209772109985e+00 + <_> + + 0 -1 660 -1.9832000136375427e-02 + + -1.6971720457077026e+00 -2.7370000258088112e-02 + <_> + + 0 -1 661 -1.6592699289321899e-01 + + 6.2976002693176270e-01 3.1762998551130295e-02 + <_> + + 0 -1 662 6.9014996290206909e-02 + + -3.3463200926780701e-01 3.0076700448989868e-01 + <_> + + 0 -1 663 1.1358000338077545e-02 + + 2.2741499543190002e-01 -3.8224700093269348e-01 + <_> + + 0 -1 664 1.7000000225380063e-03 + + 1.9223800301551819e-01 -5.2735102176666260e-01 + <_> + + 0 -1 665 7.9769000411033630e-02 + + 9.1491997241973877e-02 2.1049048900604248e+00 + <_> + + 0 -1 666 -5.7144001126289368e-02 + + -1.7452130317687988e+00 -4.0910001844167709e-02 + <_> + + 0 -1 667 7.3830001056194305e-03 + + -2.4214799702167511e-01 3.5577800869941711e-01 + <_> + + 0 -1 668 -1.8040999770164490e-02 + + 1.1779999732971191e+00 -1.7676700651645660e-01 + <_> + + 0 -1 669 9.4503000378608704e-02 + + 1.3936099410057068e-01 -1.2993700504302979e+00 + <_> + + 0 -1 670 5.4210000671446323e-03 + + -5.4608601331710815e-01 1.3916400074958801e-01 + <_> + + 0 -1 671 7.0290002040565014e-03 + + -2.1597200632095337e-01 3.9258098602294922e-01 + <_> + + 0 -1 672 3.4515999257564545e-02 + + 6.3188999891281128e-02 -7.2108101844787598e-01 + <_> + + 0 -1 673 -5.1924999803304672e-02 + + 6.8667602539062500e-01 6.3272997736930847e-02 + <_> + + 0 -1 674 -6.9162003695964813e-02 + + 1.7411810159683228e+00 -1.6619299352169037e-01 + <_> + + 0 -1 675 -5.5229999125003815e-03 + + 3.0694699287414551e-01 -1.6662900149822235e-01 + <_> + + 0 -1 676 6.8599998950958252e-02 + + -2.1405400335788727e-01 7.3185002803802490e-01 + <_> + + 0 -1 677 -6.7038998007774353e-02 + + -7.9360598325729370e-01 2.0525799691677094e-01 + <_> + + 0 -1 678 -2.1005000919103622e-02 + + 3.7344399094581604e-01 -2.9618600010871887e-01 + <_> + + 0 -1 679 2.0278999581933022e-02 + + -1.5200000256299973e-02 4.0555301308631897e-01 + <_> + + 0 -1 680 -4.7107998281717300e-02 + + 1.2116849422454834e+00 -1.7464299499988556e-01 + <_> + + 0 -1 681 1.8768499791622162e-01 + + -2.2909000515937805e-02 6.9645798206329346e-01 + <_> + + 0 -1 682 -4.3228998780250549e-02 + + -1.0602480173110962e+00 -5.5599998449906707e-04 + <_> + + 0 -1 683 2.0004000514745712e-02 + + -3.2751001417636871e-02 5.3805100917816162e-01 + <_> + + 0 -1 684 8.0880001187324524e-03 + + 3.7548001855611801e-02 -7.4768900871276855e-01 + <_> + + 0 -1 685 2.7101000770926476e-02 + + -8.1790000200271606e-02 3.3387100696563721e-01 + <_> + + 0 -1 686 -9.1746002435684204e-02 + + -1.9213509559631348e+00 -3.8952998816967010e-02 + <_> + + 0 -1 687 -1.2454999610781670e-02 + + 4.8360601067543030e-01 1.8168000504374504e-02 + <_> + + 0 -1 688 1.4649000018835068e-02 + + -1.9906699657440186e-01 7.2815400362014771e-01 + <_> + + 0 -1 689 2.9101999476552010e-02 + + 1.9871099293231964e-01 -4.9216800928115845e-01 + <_> + + 0 -1 690 8.7799998000264168e-03 + + -1.9499599933624268e-01 7.7317398786544800e-01 + <_> + + 0 -1 691 -5.4740000516176224e-02 + + 1.8087190389633179e+00 6.8323001265525818e-02 + <_> + + 0 -1 692 -1.4798000454902649e-02 + + 7.8064900636672974e-01 -1.8709599971771240e-01 + <_> + + 0 -1 693 2.5012999773025513e-02 + + 1.5285299718379974e-01 -1.6021020412445068e+00 + <_> + + 0 -1 694 4.6548001468181610e-02 + + -1.6738200187683105e-01 1.1902060508728027e+00 + <_> + + 0 -1 695 1.7624000087380409e-02 + + -1.0285499691963196e-01 3.9175900816917419e-01 + <_> + + 0 -1 696 1.6319599747657776e-01 + + -3.5624001175165176e-02 -1.6098170280456543e+00 + <_> + + 0 -1 697 1.3137999922037125e-02 + + -5.6359000504016876e-02 5.4158902168273926e-01 + <_> + + 0 -1 698 -1.5665000304579735e-02 + + 2.8063100576400757e-01 -3.1708601117134094e-01 + <_> + + 0 -1 699 8.0554001033306122e-02 + + 1.2640400230884552e-01 -1.0297529697418213e+00 + <_> + + 0 -1 700 3.5363998264074326e-02 + + 2.0752999931573868e-02 -7.9105597734451294e-01 + <_> + + 0 -1 701 3.2986998558044434e-02 + + 1.9057099521160126e-01 -8.3839899301528931e-01 + <_> + + 0 -1 702 1.2195000424981117e-02 + + 7.3729000985622406e-02 -6.2780702114105225e-01 + <_> + + 0 -1 703 4.3065998703241348e-02 + + 4.7384999692440033e-02 1.5712939500808716e+00 + <_> + + 0 -1 704 3.0326999723911285e-02 + + -2.7314600348472595e-01 3.8572001457214355e-01 + <_> + + 0 -1 705 3.5493001341819763e-02 + + 5.4593998938798904e-02 5.2583402395248413e-01 + <_> + + 0 -1 706 -1.4596999622881413e-02 + + 3.8152599334716797e-01 -2.8332400321960449e-01 + <_> + + 0 -1 707 1.2606999836862087e-02 + + 1.5455099940299988e-01 -3.0501499772071838e-01 + <_> + + 0 -1 708 1.0172000154852867e-02 + + 2.3637000471353531e-02 -8.7217897176742554e-01 + <_> + + 0 -1 709 2.8843000531196594e-02 + + 1.6090999543666840e-01 -2.0277599990367889e-01 + <_> + + 0 -1 710 5.5100000463426113e-04 + + -6.1545401811599731e-01 8.0935999751091003e-02 + <_> + 127 + -3.5645289421081543e+00 + + <_> + + 0 -1 711 4.8344001173973083e-02 + + -8.4904599189758301e-01 5.6974399089813232e-01 + <_> + + 0 -1 712 3.2460000365972519e-02 + + -8.1417298316955566e-01 4.4781699776649475e-01 + <_> + + 0 -1 713 3.3339999616146088e-02 + + -3.6423799395561218e-01 6.7937397956848145e-01 + <_> + + 0 -1 714 6.4019998535513878e-03 + + -1.1885459423065186e+00 1.9238699972629547e-01 + <_> + + 0 -1 715 -5.6889997795224190e-03 + + 3.3085298538208008e-01 -7.1334099769592285e-01 + <_> + + 0 -1 716 1.2698000296950340e-02 + + -5.0990802049636841e-01 1.1376299709081650e-01 + <_> + + 0 -1 717 6.0549997724592686e-03 + + -1.0470550060272217e+00 2.0222599804401398e-01 + <_> + + 0 -1 718 2.6420000940561295e-03 + + -5.0559401512145996e-01 3.6441200971603394e-01 + <_> + + 0 -1 719 -1.6925999894738197e-02 + + -9.9541902542114258e-01 1.2602199614048004e-01 + <_> + + 0 -1 720 2.8235999867320061e-02 + + -9.4137996435165405e-02 5.7780402898788452e-01 + <_> + + 0 -1 721 1.0428999550640583e-02 + + 2.3272900283336639e-01 -5.2569699287414551e-01 + <_> + + 0 -1 722 9.8860003054141998e-03 + + -1.0316299647092819e-01 4.7657600045204163e-01 + <_> + + 0 -1 723 2.6015000417828560e-02 + + -1.0920000495389104e-03 -1.5581729412078857e+00 + <_> + + 0 -1 724 -2.5537999346852303e-02 + + -6.5451401472091675e-01 1.8843199312686920e-01 + <_> + + 0 -1 725 -3.5310001112520695e-03 + + 2.8140598535537720e-01 -4.4575300812721252e-01 + <_> + + 0 -1 726 9.2449998483061790e-03 + + 1.5612000226974487e-01 -2.1370999515056610e-01 + <_> + + 0 -1 727 2.1030999720096588e-02 + + -2.9170298576354980e-01 5.2234101295471191e-01 + <_> + + 0 -1 728 -5.1063001155853271e-02 + + 1.3661290407180786e+00 3.0465999618172646e-02 + <_> + + 0 -1 729 -6.2330000102519989e-02 + + 1.2207020521163940e+00 -2.2434400022029877e-01 + <_> + + 0 -1 730 -3.2963000237941742e-02 + + -8.2016801834106445e-01 1.4531899988651276e-01 + <_> + + 0 -1 731 -3.7418000400066376e-02 + + -1.2218099832534790e+00 1.9448999315500259e-02 + <_> + + 0 -1 732 1.2402799725532532e-01 + + 1.2082300335168839e-01 -9.8729300498962402e-01 + <_> + + 0 -1 733 -8.9229997247457504e-03 + + -1.1688489913940430e+00 2.1105000749230385e-02 + <_> + + 0 -1 734 -5.9879999607801437e-02 + + -1.0689330101013184e+00 1.9860200583934784e-01 + <_> + + 0 -1 735 6.2620001845061779e-03 + + -3.6229598522186279e-01 3.8000801205635071e-01 + <_> + + 0 -1 736 -1.7673000693321228e-02 + + 4.9094098806381226e-01 -1.4606699347496033e-01 + <_> + + 0 -1 737 1.7579000443220139e-02 + + 5.8728098869323730e-01 -2.7774399518966675e-01 + <_> + + 0 -1 738 5.1560001447796822e-03 + + -7.5194999575614929e-02 6.0193097591400146e-01 + <_> + + 0 -1 739 -1.0599999688565731e-02 + + 2.7637401223182678e-01 -3.7794300913810730e-01 + <_> + + 0 -1 740 2.0884099602699280e-01 + + -5.3599998354911804e-03 1.0317809581756592e+00 + <_> + + 0 -1 741 -2.6412999257445335e-02 + + 8.2336401939392090e-01 -2.2480599582195282e-01 + <_> + + 0 -1 742 5.8892000466585159e-02 + + 1.3098299503326416e-01 -1.1853699684143066e+00 + <_> + + 0 -1 743 -1.1579000391066074e-02 + + -9.0667802095413208e-01 4.4126998633146286e-02 + <_> + + 0 -1 744 4.5988000929355621e-02 + + 1.0143999941647053e-02 1.0740900039672852e+00 + <_> + + 0 -1 745 -2.2838000208139420e-02 + + 1.7791990041732788e+00 -1.7315499484539032e-01 + <_> + + 0 -1 746 -8.1709995865821838e-03 + + 5.7386302947998047e-01 -7.4106000363826752e-02 + <_> + + 0 -1 747 3.5359999164938927e-03 + + -3.2072898745536804e-01 4.0182501077651978e-01 + <_> + + 0 -1 748 4.9444999545812607e-02 + + 1.9288000464439392e-01 -1.2166700363159180e+00 + <_> + + 0 -1 749 3.5139999818056822e-03 + + 6.9568000733852386e-02 -7.1323698759078979e-01 + <_> + + 0 -1 750 -3.0996000394225121e-02 + + -3.8862198591232300e-01 1.8098799884319305e-01 + <_> + + 0 -1 751 8.6452998220920563e-02 + + -2.5792999193072319e-02 -1.5453219413757324e+00 + <_> + + 0 -1 752 -1.3652600347995758e-01 + + -1.9199420213699341e+00 1.6613300144672394e-01 + <_> + + 0 -1 753 -5.7689999230206013e-03 + + -1.2822589874267578e+00 -1.5907999128103256e-02 + <_> + + 0 -1 754 -1.7899999395012856e-02 + + -4.0409898757934570e-01 2.3591600358486176e-01 + <_> + + 0 -1 755 -1.9969999790191650e-02 + + -7.2891902923583984e-01 5.6235000491142273e-02 + <_> + + 0 -1 756 -5.7493001222610474e-02 + + 5.7830798625946045e-01 -1.5796000137925148e-02 + <_> + + 0 -1 757 -8.3056002855300903e-02 + + 9.1511601209640503e-01 -2.1121400594711304e-01 + <_> + + 0 -1 758 -5.3771000355482101e-02 + + -5.1931297779083252e-01 1.8576000630855560e-01 + <_> + + 0 -1 759 -8.3670001477003098e-03 + + 2.4109700322151184e-01 -3.9648601412773132e-01 + <_> + + 0 -1 760 5.5406998842954636e-02 + + 1.6771200299263000e-01 -2.5664970874786377e+00 + <_> + + 0 -1 761 -6.7180998623371124e-02 + + -1.3658570051193237e+00 -1.4232000336050987e-02 + <_> + + 0 -1 762 -2.3900000378489494e-02 + + -1.7084569931030273e+00 1.6507799923419952e-01 + <_> + + 0 -1 763 5.5949999950826168e-03 + + -3.1373998522758484e-01 3.2837900519371033e-01 + <_> + + 0 -1 764 2.1294999867677689e-02 + + 1.4953400194644928e-01 -4.8579800128936768e-01 + <_> + + 0 -1 765 -2.4613000452518463e-02 + + 7.4346399307250977e-01 -2.2305199503898621e-01 + <_> + + 0 -1 766 -1.9626000896096230e-02 + + -4.0918299555778503e-01 1.8893200159072876e-01 + <_> + + 0 -1 767 -5.3266000002622604e-02 + + 8.1381601095199585e-01 -2.0853699743747711e-01 + <_> + + 0 -1 768 7.1290000341832638e-03 + + 3.2996100187301636e-01 -5.9937399625778198e-01 + <_> + + 0 -1 769 -2.2486999630928040e-02 + + -1.2551610469818115e+00 -2.0413000136613846e-02 + <_> + + 0 -1 770 -8.2310996949672699e-02 + + 1.3821430206298828e+00 5.9308998286724091e-02 + <_> + + 0 -1 771 1.3097000122070312e-01 + + -3.5843998193740845e-02 -1.5396369695663452e+00 + <_> + + 0 -1 772 1.4293000102043152e-02 + + -1.8475200235843658e-01 3.7455001473426819e-01 + <_> + + 0 -1 773 6.3479999080300331e-03 + + -4.4901099801063538e-01 1.3876999914646149e-01 + <_> + + 0 -1 774 -4.6055000275373459e-02 + + 6.7832601070404053e-01 -1.7071999609470367e-02 + <_> + + 0 -1 775 5.7693999260663986e-02 + + -1.1955999769270420e-02 -1.2261159420013428e+00 + <_> + + 0 -1 776 -6.0609998181462288e-03 + + 3.3958598971366882e-01 6.2800000887364149e-04 + <_> + + 0 -1 777 -5.2163001149892807e-02 + + -1.0621069669723511e+00 -1.3779999688267708e-02 + <_> + + 0 -1 778 4.6572998166084290e-02 + + 1.4538800716400146e-01 -1.2384550571441650e+00 + <_> + + 0 -1 779 7.5309998355805874e-03 + + -2.4467700719833374e-01 5.1377099752426147e-01 + <_> + + 0 -1 780 2.1615000441670418e-02 + + 1.3072599470615387e-01 -7.0996797084808350e-01 + <_> + + 0 -1 781 -1.7864000052213669e-02 + + -1.0474660396575928e+00 4.9599999329075217e-04 + <_> + + 0 -1 782 -3.7195000797510147e-02 + + -1.5126730203628540e+00 1.4801399409770966e-01 + <_> + + 0 -1 783 -3.1100001069717109e-04 + + 1.3971500098705292e-01 -4.6867498755455017e-01 + <_> + + 0 -1 784 2.5042999535799026e-02 + + 2.8632000088691711e-01 -4.1794699430465698e-01 + <_> + + 0 -1 785 9.3449996784329414e-03 + + -2.7336201071739197e-01 4.3444699048995972e-01 + <_> + + 0 -1 786 3.2363999634981155e-02 + + 1.8438899517059326e-01 -9.5019298791885376e-01 + <_> + + 0 -1 787 -6.2299999408423901e-03 + + 3.2581999897956848e-01 -3.0815601348876953e-01 + <_> + + 0 -1 788 5.1488999277353287e-02 + + 1.1416000127792358e-01 -1.9795479774475098e+00 + <_> + + 0 -1 789 -2.6449000462889671e-02 + + -1.1067299842834473e+00 -8.5519999265670776e-03 + <_> + + 0 -1 790 -1.5420000068843365e-02 + + 8.0138701200485229e-01 -3.2035000622272491e-02 + <_> + + 0 -1 791 1.9456999376416206e-02 + + -2.6449498534202576e-01 3.8753899931907654e-01 + <_> + + 0 -1 792 3.3620998263359070e-02 + + 1.6052000224590302e-02 5.8840900659561157e-01 + <_> + + 0 -1 793 2.8906000778079033e-02 + + 1.5216000378131866e-02 -9.4723600149154663e-01 + <_> + + 0 -1 794 2.0300000323913991e-04 + + -3.0766001343727112e-01 2.1235899627208710e-01 + <_> + + 0 -1 795 -4.9141999334096909e-02 + + -1.6058609485626221e+00 -3.1094999983906746e-02 + <_> + + 0 -1 796 7.6425999402999878e-02 + + 7.4758999049663544e-02 1.1639410257339478e+00 + <_> + + 0 -1 797 2.3897999897599220e-02 + + -6.4320000819861889e-03 -1.1150749921798706e+00 + <_> + + 0 -1 798 3.8970001041889191e-03 + + -2.4105699360370636e-01 2.0858900249004364e-01 + <_> + + 0 -1 799 -8.9445002377033234e-02 + + 1.9157789945602417e+00 -1.5721100568771362e-01 + <_> + + 0 -1 800 -1.5008999966084957e-02 + + -2.5174099206924438e-01 1.8179899454116821e-01 + <_> + + 0 -1 801 -1.1145999655127525e-02 + + -6.9349497556686401e-01 4.4927999377250671e-02 + <_> + + 0 -1 802 9.4578996300697327e-02 + + 1.8102100491523743e-01 -7.4978601932525635e-01 + <_> + + 0 -1 803 5.5038899183273315e-01 + + -3.0974000692367554e-02 -1.6746139526367188e+00 + <_> + + 0 -1 804 4.1381001472473145e-02 + + 6.3910000026226044e-02 7.6561200618743896e-01 + <_> + + 0 -1 805 2.4771999567747116e-02 + + 1.1380000039935112e-02 -8.8559401035308838e-01 + <_> + + 0 -1 806 5.0999000668525696e-02 + + 1.4890299737453461e-01 -2.4634211063385010e+00 + <_> + + 0 -1 807 -1.6893999651074409e-02 + + 3.8870999217033386e-01 -2.9880300164222717e-01 + <_> + + 0 -1 808 -1.2162300199270248e-01 + + -1.5542800426483154e+00 1.6300800442695618e-01 + <_> + + 0 -1 809 -3.6049999762326479e-03 + + 2.1842800080776215e-01 -3.7312099337577820e-01 + <_> + + 0 -1 810 1.1575400084257126e-01 + + -4.7061000019311905e-02 5.9403699636459351e-01 + <_> + + 0 -1 811 3.6903999745845795e-02 + + -2.5508600473403931e-01 5.5397301912307739e-01 + <_> + + 0 -1 812 1.1483999900519848e-02 + + -1.8129499256610870e-01 4.0682798624038696e-01 + <_> + + 0 -1 813 -2.0233999937772751e-02 + + 5.4311197996139526e-01 -2.3822399973869324e-01 + <_> + + 0 -1 814 -2.8765000402927399e-02 + + -6.9172298908233643e-01 1.5943300724029541e-01 + <_> + + 0 -1 815 -5.8320001699030399e-03 + + 2.9447799921035767e-01 -3.4005999565124512e-01 + <_> + + 0 -1 816 -5.5468998849391937e-02 + + 9.2200797796249390e-01 9.4093002378940582e-02 + <_> + + 0 -1 817 -1.4801000244915485e-02 + + -7.9539698362350464e-01 3.1521998345851898e-02 + <_> + + 0 -1 818 -7.0940000005066395e-03 + + 3.3096000552177429e-01 -5.0886999815702438e-02 + <_> + + 0 -1 819 -4.5124001801013947e-02 + + -1.3719749450683594e+00 -2.1408999338746071e-02 + <_> + + 0 -1 820 6.4377002418041229e-02 + + 6.3901998102664948e-02 9.1478300094604492e-01 + <_> + + 0 -1 821 -1.4727000147104263e-02 + + 3.6050599813461304e-01 -2.8614500164985657e-01 + <_> + + 0 -1 822 4.5007001608610153e-02 + + -1.5619699656963348e-01 5.3160297870635986e-01 + <_> + + 0 -1 823 -1.1330000124871731e-03 + + 1.3422900438308716e-01 -4.4358900189399719e-01 + <_> + + 0 -1 824 4.9451000988483429e-02 + + 1.0571800172328949e-01 -2.5589139461517334e+00 + <_> + + 0 -1 825 2.9102999716997147e-02 + + -1.0088000446557999e-02 -1.1073939800262451e+00 + <_> + + 0 -1 826 3.4786000847816467e-02 + + -2.7719999197870493e-03 5.6700998544692993e-01 + <_> + + 0 -1 827 -6.1309998854994774e-03 + + -4.6889400482177734e-01 1.2636399269104004e-01 + <_> + + 0 -1 828 1.5525000169873238e-02 + + -8.4279999136924744e-03 8.7469202280044556e-01 + <_> + + 0 -1 829 2.9249999206513166e-03 + + -3.4434300661087036e-01 2.0851600170135498e-01 + <_> + + 0 -1 830 -5.3571000695228577e-02 + + 1.4982949495315552e+00 5.7328000664710999e-02 + <_> + + 0 -1 831 -1.9217999652028084e-02 + + -9.9234098196029663e-01 -9.3919998034834862e-03 + <_> + + 0 -1 832 -5.5282998830080032e-02 + + -5.7682299613952637e-01 1.6860599815845490e-01 + <_> + + 0 -1 833 5.6336000561714172e-02 + + -3.3775001764297485e-02 -1.3889650106430054e+00 + <_> + + 0 -1 834 -2.3824000731110573e-02 + + 4.0182098746299744e-01 1.8360000103712082e-03 + <_> + + 0 -1 835 1.7810000572353601e-03 + + 1.8145999312400818e-01 -4.1743400692939758e-01 + <_> + + 0 -1 836 -3.7689000368118286e-02 + + 5.4683101177215576e-01 1.8219999969005585e-02 + <_> + + 0 -1 837 -2.4144999682903290e-02 + + 6.8352097272872925e-01 -1.9650200009346008e-01 + <_> + 135 + -3.7025990486145020e+00 + + <_> + + 0 -1 838 2.7444999665021896e-02 + + -8.9984202384948730e-01 5.1876497268676758e-01 + <_> + + 0 -1 839 1.1554100364446640e-01 + + -5.6524401903152466e-01 7.0551300048828125e-01 + <_> + + 0 -1 840 -2.2297000512480736e-02 + + 3.6079999804496765e-01 -6.6864597797393799e-01 + <_> + + 0 -1 841 1.3325000181794167e-02 + + -5.5573397874832153e-01 3.5789999365806580e-01 + <_> + + 0 -1 842 -3.8060001097619534e-03 + + -1.0713000297546387e+00 1.8850000202655792e-01 + <_> + + 0 -1 843 -2.6819999329745770e-03 + + -7.1584302186965942e-01 2.6344498991966248e-01 + <_> + + 0 -1 844 3.3819999080151320e-03 + + -4.6930798888206482e-01 2.6658400893211365e-01 + <_> + + 0 -1 845 3.7643000483512878e-02 + + 2.1098700165748596e-01 -1.0804339647293091e+00 + <_> + + 0 -1 846 -1.3861999846994877e-02 + + 6.6912001371383667e-01 -2.7942800521850586e-01 + <_> + + 0 -1 847 -2.7350001037120819e-03 + + -9.5332300662994385e-01 2.4051299691200256e-01 + <_> + + 0 -1 848 -3.8336999714374542e-02 + + 8.1432801485061646e-01 -2.4919399619102478e-01 + <_> + + 0 -1 849 -3.4697998315095901e-02 + + 1.2330100536346436e+00 6.8600000813603401e-03 + <_> + + 0 -1 850 2.3360999301075935e-02 + + -3.0794700980186462e-01 7.0714497566223145e-01 + <_> + + 0 -1 851 3.5057999193668365e-02 + + 2.1205900609493256e-01 -1.4399830102920532e+00 + <_> + + 0 -1 852 -1.3256999664008617e-02 + + -9.0260702371597290e-01 4.8610001802444458e-02 + <_> + + 0 -1 853 1.2740000151097775e-02 + + 2.2655199468135834e-01 -4.4643801450729370e-01 + <_> + + 0 -1 854 3.6400000099092722e-03 + + -3.9817899465560913e-01 3.4665399789810181e-01 + <_> + + 0 -1 855 1.0064700245857239e-01 + + 1.8383599817752838e-01 -1.3410769701004028e+00 + <_> + + 0 -1 856 0. + + 1.5536400675773621e-01 -5.1582497358322144e-01 + <_> + + 0 -1 857 1.1708999983966351e-02 + + 2.1651400625705719e-01 -7.2705197334289551e-01 + <_> + + 0 -1 858 -3.5964999347925186e-02 + + -1.4789500236511230e+00 -2.4317000061273575e-02 + <_> + + 0 -1 859 -2.1236000582575798e-02 + + -1.6844099760055542e-01 1.9526599347591400e-01 + <_> + + 0 -1 860 1.4874000102281570e-02 + + 3.7335999310016632e-02 -8.7557297945022583e-01 + <_> + + 0 -1 861 -5.1409997977316380e-03 + + 3.3466500043869019e-01 -2.4109700322151184e-01 + <_> + + 0 -1 862 2.3450000211596489e-02 + + 5.5320002138614655e-03 -1.2509720325469971e+00 + <_> + + 0 -1 863 -2.5062000378966331e-02 + + 4.5212399959564209e-01 -8.4469996392726898e-02 + <_> + + 0 -1 864 -7.7400001464411616e-04 + + 1.5249900519847870e-01 -4.8486500978469849e-01 + <_> + + 0 -1 865 -4.0483999997377396e-02 + + -1.3024920225143433e+00 1.7983500659465790e-01 + <_> + + 0 -1 866 2.8170999139547348e-02 + + -2.4410900473594666e-01 6.2271100282669067e-01 + <_> + + 0 -1 867 4.5692998915910721e-02 + + 2.8122000396251678e-02 9.2394399642944336e-01 + <_> + + 0 -1 868 3.9707001298666000e-02 + + -2.2332799434661865e-01 7.7674001455307007e-01 + <_> + + 0 -1 869 5.0517000257968903e-02 + + 2.0319999754428864e-01 -1.0895930528640747e+00 + <_> + + 0 -1 870 -1.7266999930143356e-02 + + 6.8598401546478271e-01 -2.3304499685764313e-01 + <_> + + 0 -1 871 8.0186001956462860e-02 + + -1.0292000137269497e-02 6.1881101131439209e-01 + <_> + + 0 -1 872 9.7676001489162445e-02 + + -2.0070299506187439e-01 1.0088349580764771e+00 + <_> + + 0 -1 873 -1.5572000294923782e-02 + + 4.7615298628807068e-01 4.5623999089002609e-02 + <_> + + 0 -1 874 -1.5305000357329845e-02 + + -1.1077369451522827e+00 4.5239999890327454e-03 + <_> + + 0 -1 875 -1.6485000029206276e-02 + + 1.0152939558029175e+00 1.6327999532222748e-02 + <_> + + 0 -1 876 -2.6141999289393425e-02 + + 4.1723299026489258e-01 -2.8645500540733337e-01 + <_> + + 0 -1 877 8.8679995387792587e-03 + + 2.1404999494552612e-01 -1.6772800683975220e-01 + <_> + + 0 -1 878 -2.6886999607086182e-02 + + -1.1564220190048218e+00 -1.0324000380933285e-02 + <_> + + 0 -1 879 7.7789998613297939e-03 + + 3.5359498858451843e-01 -2.9611301422119141e-01 + <_> + + 0 -1 880 -1.5974000096321106e-02 + + -1.5374109745025635e+00 -2.9958000406622887e-02 + <_> + + 0 -1 881 2.0866999402642250e-02 + + 2.0244100689888000e-01 -7.1270197629928589e-01 + <_> + + 0 -1 882 8.5482001304626465e-02 + + -2.5932999327778816e-02 -1.5156569480895996e+00 + <_> + + 0 -1 883 2.3872999474406242e-02 + + 1.6803400218486786e-01 -3.8806200027465820e-01 + <_> + + 0 -1 884 -3.9105001837015152e-02 + + -1.1958349943161011e+00 -2.0361000671982765e-02 + <_> + + 0 -1 885 -7.7946998178958893e-02 + + -1.0898950099945068e+00 1.4530299603939056e-01 + <_> + + 0 -1 886 -1.6876000910997391e-02 + + 2.8049701452255249e-01 -4.1336300969123840e-01 + <_> + + 0 -1 887 1.1875600367784500e-01 + + -4.3490998446941376e-02 4.1263699531555176e-01 + <_> + + 0 -1 888 1.5624199807643890e-01 + + -2.6429599523544312e-01 5.5127799510955811e-01 + <_> + + 0 -1 889 -4.5908000320196152e-02 + + 6.0189199447631836e-01 1.8921000882983208e-02 + <_> + + 0 -1 890 -1.0309999808669090e-02 + + 3.8152998685836792e-01 -2.9507899284362793e-01 + <_> + + 0 -1 891 9.5769003033638000e-02 + + 1.3246500492095947e-01 -4.6266800165176392e-01 + <_> + + 0 -1 892 1.3686999678611755e-02 + + 1.1738699674606323e-01 -5.1664102077484131e-01 + <_> + + 0 -1 893 2.3990001063793898e-03 + + -3.4007599949836731e-01 2.0953500270843506e-01 + <_> + + 0 -1 894 3.3264998346567154e-02 + + -1.7052799463272095e-01 1.4366799592971802e+00 + <_> + + 0 -1 895 -3.3206000924110413e-02 + + 6.1295700073242188e-01 -4.1549999266862869e-02 + <_> + + 0 -1 896 2.7979998849332333e-03 + + -4.8554301261901855e-01 1.3372699916362762e-01 + <_> + + 0 -1 897 -6.5792001783847809e-02 + + -4.0257668495178223e+00 1.0876700282096863e-01 + <_> + + 0 -1 898 2.1430000197142363e-03 + + -3.9179998636245728e-01 2.2427099943161011e-01 + <_> + + 0 -1 899 2.2363999858498573e-02 + + -8.6429998278617859e-02 3.7785199284553528e-01 + <_> + + 0 -1 900 -5.7410001754760742e-02 + + 1.1454069614410400e+00 -1.9736599922180176e-01 + <_> + + 0 -1 901 6.6550001502037048e-03 + + -2.1105000749230385e-02 5.8453398942947388e-01 + <_> + + 0 -1 902 1.2326999567449093e-02 + + 3.7817001342773438e-02 -6.6987001895904541e-01 + <_> + + 0 -1 903 -8.1869997084140778e-03 + + 5.6366002559661865e-01 -7.6877996325492859e-02 + <_> + + 0 -1 904 3.6681000143289566e-02 + + -1.7343300580978394e-01 1.1670149564743042e+00 + <_> + + 0 -1 905 -4.0220400691032410e-01 + + 1.2640819549560547e+00 4.3398998677730560e-02 + <_> + + 0 -1 906 -2.2126000374555588e-02 + + 6.6978102922439575e-01 -2.1605299413204193e-01 + <_> + + 0 -1 907 -1.3156999833881855e-02 + + -4.1198599338531494e-01 2.0215000212192535e-01 + <_> + + 0 -1 908 -1.2860000133514404e-02 + + -9.1582697629928589e-01 3.9232999086380005e-02 + <_> + + 0 -1 909 2.1627999842166901e-02 + + 3.8719999138265848e-03 3.5668200254440308e-01 + <_> + + 0 -1 910 1.1896000243723392e-02 + + -3.7303900718688965e-01 1.9235099852085114e-01 + <_> + + 0 -1 911 -1.9548999145627022e-02 + + -4.2374899983406067e-01 2.4429599940776825e-01 + <_> + + 0 -1 912 6.4444996416568756e-02 + + -1.6558900475502014e-01 1.2697030305862427e+00 + <_> + + 0 -1 913 1.0898499935865402e-01 + + 1.4894300699234009e-01 -2.1534640789031982e+00 + <_> + + 0 -1 914 -3.4077998250722885e-02 + + 1.3779460191726685e+00 -1.6198499500751495e-01 + <_> + + 0 -1 915 -3.7489999085664749e-03 + + -3.3828601241111755e-01 2.1152900159358978e-01 + <_> + + 0 -1 916 -1.0971999727189541e-02 + + 7.6517897844314575e-01 -1.9692599773406982e-01 + <_> + + 0 -1 917 -1.1485000140964985e-02 + + -6.9271200895309448e-01 2.1657100319862366e-01 + <_> + + 0 -1 918 2.5984000414609909e-02 + + -1.1983999982476234e-02 -9.9697297811508179e-01 + <_> + + 0 -1 919 4.2159999720752239e-03 + + -1.0205700248479843e-01 4.8884400725364685e-01 + <_> + + 0 -1 920 -4.7697000205516815e-02 + + 1.0666010379791260e+00 -1.7576299607753754e-01 + <_> + + 0 -1 921 4.0300001273863018e-04 + + 1.8524800240993500e-01 -7.4790000915527344e-01 + <_> + + 0 -1 922 1.1539600044488907e-01 + + -2.2019700706005096e-01 5.4509997367858887e-01 + <_> + + 0 -1 923 1.6021000221371651e-02 + + 2.5487500429153442e-01 -5.0740098953247070e-01 + <_> + + 0 -1 924 5.6632000952959061e-02 + + -1.1256000027060509e-02 -9.5968097448348999e-01 + <_> + + 0 -1 925 -1.0726000182330608e-02 + + -2.8544700145721436e-01 1.6994799673557281e-01 + <_> + + 0 -1 926 1.2420000135898590e-01 + + -3.6139998584985733e-02 -1.3132710456848145e+00 + <_> + + 0 -1 927 -5.3799999877810478e-03 + + 3.3092701435089111e-01 1.3307999819517136e-02 + <_> + + 0 -1 928 1.1908000335097313e-02 + + -3.4830299019813538e-01 2.4041900038719177e-01 + <_> + + 0 -1 929 -4.3007999658584595e-02 + + -1.4390469789505005e+00 1.5599599480628967e-01 + <_> + + 0 -1 930 -3.3149998635053635e-02 + + -1.1805850267410278e+00 -1.2347999960184097e-02 + <_> + + 0 -1 931 -2.1341999992728233e-02 + + 2.2119441032409668e+00 6.2737002968788147e-02 + <_> + + 0 -1 932 -1.2218999676406384e-02 + + -1.8709750175476074e+00 -4.5499999076128006e-02 + <_> + + 0 -1 933 -1.6860999166965485e-02 + + -7.6912701129913330e-01 1.5330000221729279e-01 + <_> + + 0 -1 934 -2.4999999441206455e-03 + + -6.2987399101257324e-01 5.1600001752376556e-02 + <_> + + 0 -1 935 -4.5037999749183655e-02 + + 8.5428899526596069e-01 6.2600001692771912e-03 + <_> + + 0 -1 936 3.9057999849319458e-02 + + -3.2458998262882233e-02 -1.3325669765472412e+00 + <_> + + 0 -1 937 6.6720000468194485e-03 + + -1.9423599541187286e-01 3.7328699231147766e-01 + <_> + + 0 -1 938 -1.6361000016331673e-02 + + 2.0605869293212891e+00 -1.5042699873447418e-01 + <_> + + 0 -1 939 6.1719999648630619e-03 + + -1.1610999703407288e-01 2.5455400347709656e-01 + <_> + + 0 -1 940 4.5722000300884247e-02 + + -1.6340000554919243e-02 -1.0449140071868896e+00 + <_> + + 0 -1 941 4.1209999471902847e-03 + + -4.1997998952865601e-02 3.9680999517440796e-01 + <_> + + 0 -1 942 -1.7800000205170363e-04 + + -6.6422599554061890e-01 3.3443000167608261e-02 + <_> + + 0 -1 943 7.1109998971223831e-03 + + -5.8231998234987259e-02 3.7857300043106079e-01 + <_> + + 0 -1 944 -4.9864001572132111e-02 + + 6.1019402742385864e-01 -2.1005700528621674e-01 + <_> + + 0 -1 945 -2.5011999532580376e-02 + + -5.7100099325180054e-01 1.7848399281501770e-01 + <_> + + 0 -1 946 3.0939999967813492e-02 + + 5.6363001465797424e-02 -6.4731001853942871e-01 + <_> + + 0 -1 947 4.6271000057458878e-02 + + 1.7482399940490723e-01 -9.8909401893615723e-01 + <_> + + 0 -1 948 -3.1870000530034304e-03 + + -6.6804802417755127e-01 3.2267000526189804e-02 + <_> + + 0 -1 949 -2.4351999163627625e-02 + + 2.9444900155067444e-01 -1.3599999947473407e-03 + <_> + + 0 -1 950 1.1974000371992588e-02 + + -2.8345099091529846e-01 4.7171199321746826e-01 + <_> + + 0 -1 951 1.3070000335574150e-02 + + -1.0834600031375885e-01 5.7193297147750854e-01 + <_> + + 0 -1 952 5.9163000434637070e-02 + + -5.0939001142978668e-02 -1.9059720039367676e+00 + <_> + + 0 -1 953 -4.1094999760389328e-02 + + 4.5104598999023438e-01 -9.7599998116493225e-03 + <_> + + 0 -1 954 -8.3989001810550690e-02 + + -2.0349199771881104e+00 -5.1019001752138138e-02 + <_> + + 0 -1 955 4.4619001448154449e-02 + + 1.7041100561618805e-01 -1.2278720140457153e+00 + <_> + + 0 -1 956 2.4419000372290611e-02 + + -2.1796999499201775e-02 -1.0822949409484863e+00 + <_> + + 0 -1 957 -4.3870001100003719e-03 + + 3.0466699600219727e-01 -3.7066599726676941e-01 + <_> + + 0 -1 958 2.4607999250292778e-02 + + -3.1169500946998596e-01 2.3657299578189850e-01 + <_> + + 0 -1 959 -8.5182003676891327e-02 + + -1.7982350587844849e+00 1.5254299342632294e-01 + <_> + + 0 -1 960 2.1844999864697456e-02 + + -5.1888000220060349e-02 -1.9017189741134644e+00 + <_> + + 0 -1 961 -1.6829000785946846e-02 + + 2.1025900542736053e-01 2.1656999364495277e-02 + <_> + + 0 -1 962 3.2547999173402786e-02 + + -2.0292599499225616e-01 6.0944002866744995e-01 + <_> + + 0 -1 963 2.4709999561309814e-03 + + -9.5371198654174805e-01 1.8568399548530579e-01 + <_> + + 0 -1 964 5.5415999144315720e-02 + + -1.4405299723148346e-01 2.1506340503692627e+00 + <_> + + 0 -1 965 -1.0635499656200409e-01 + + -1.0911970138549805e+00 1.3228000700473785e-01 + <_> + + 0 -1 966 -7.9889995977282524e-03 + + 1.0253400355577469e-01 -5.1744902133941650e-01 + <_> + + 0 -1 967 7.5567997992038727e-02 + + 5.8965001255273819e-02 1.2354209423065186e+00 + <_> + + 0 -1 968 -9.2805996537208557e-02 + + -1.3431650400161743e+00 -3.4462999552488327e-02 + <_> + + 0 -1 969 4.9431998282670975e-02 + + 4.9601998180150986e-02 1.6054730415344238e+00 + <_> + + 0 -1 970 -1.1772999539971352e-02 + + -1.0261050462722778e+00 -4.1559999808669090e-03 + <_> + + 0 -1 971 8.5886001586914062e-02 + + 8.4642998874187469e-02 9.5220798254013062e-01 + <_> + + 0 -1 972 8.1031002104282379e-02 + + -1.4687100052833557e-01 1.9359990358352661e+00 + <_> + 136 + -3.4265899658203125e+00 + + <_> + + 0 -1 973 -3.3840999007225037e-02 + + 6.5889501571655273e-01 -6.9755297899246216e-01 + <_> + + 0 -1 974 1.5410000458359718e-02 + + -9.0728402137756348e-01 3.0478599667549133e-01 + <_> + + 0 -1 975 5.4905999451875687e-02 + + -4.9774798750877380e-01 5.7132601737976074e-01 + <_> + + 0 -1 976 2.1390000358223915e-02 + + -4.2565199732780457e-01 5.8096802234649658e-01 + <_> + + 0 -1 977 7.8849997371435165e-03 + + -4.7905999422073364e-01 4.3016499280929565e-01 + <_> + + 0 -1 978 -3.7544999271631241e-02 + + 5.0861597061157227e-01 -1.9985899329185486e-01 + <_> + + 0 -1 979 1.5925799310207367e-01 + + -2.3263600468635559e-01 1.0993319749832153e+00 + <_> + + 0 -1 980 -6.8939998745918274e-02 + + 4.0569001436233521e-01 5.6855000555515289e-02 + <_> + + 0 -1 981 -3.3695001155138016e-02 + + 4.5132800936698914e-01 -3.3332800865173340e-01 + <_> + + 0 -1 982 -6.3314996659755707e-02 + + -8.5015702247619629e-01 2.2341699898242950e-01 + <_> + + 0 -1 983 7.3699997738003731e-03 + + -9.3082201480865479e-01 5.9216998517513275e-02 + <_> + + 0 -1 984 -9.5969997346401215e-03 + + -1.2794899940490723e+00 1.8447299301624298e-01 + <_> + + 0 -1 985 -1.3067999482154846e-01 + + 5.8426898717880249e-01 -2.6007199287414551e-01 + <_> + + 0 -1 986 5.7402998208999634e-02 + + -5.3789000958204269e-02 7.1175599098205566e-01 + <_> + + 0 -1 987 -7.2340001352131367e-03 + + -8.6962199211120605e-01 7.5214996933937073e-02 + <_> + + 0 -1 988 3.1098999083042145e-02 + + -7.5006999075412750e-02 9.0781599283218384e-01 + <_> + + 0 -1 989 3.5854000598192215e-02 + + -2.4795499444007874e-01 7.2272098064422607e-01 + <_> + + 0 -1 990 -3.1534999608993530e-02 + + -1.1238329410552979e+00 2.0988300442695618e-01 + <_> + + 0 -1 991 -1.9437000155448914e-02 + + -1.4499390125274658e+00 -1.5100000426173210e-02 + <_> + + 0 -1 992 -7.2420001961290836e-03 + + 5.3864902257919312e-01 -1.1375399678945541e-01 + <_> + + 0 -1 993 8.1639997661113739e-03 + + 6.6889002919197083e-02 -7.6872897148132324e-01 + <_> + + 0 -1 994 -4.3653000146150589e-02 + + 1.1413530111312866e+00 4.0217000991106033e-02 + <_> + + 0 -1 995 2.6569999754428864e-02 + + -2.4719099700450897e-01 5.9295099973678589e-01 + <_> + + 0 -1 996 3.2216999679803848e-02 + + -4.0024999529123306e-02 3.2688000798225403e-01 + <_> + + 0 -1 997 -7.2236001491546631e-02 + + 5.8729398250579834e-01 -2.5396001338958740e-01 + <_> + + 0 -1 998 3.1424999237060547e-02 + + 1.5315100550651550e-01 -5.6042098999023438e-01 + <_> + + 0 -1 999 -4.7699999413453043e-04 + + 1.6958899796009064e-01 -5.2626699209213257e-01 + <_> + + 0 -1 1000 2.7189999818801880e-03 + + -1.4944599568843842e-01 2.9658699035644531e-01 + <_> + + 0 -1 1001 3.2875001430511475e-02 + + -3.9943501353263855e-01 2.5156599283218384e-01 + <_> + + 0 -1 1002 -1.4553000219166279e-02 + + 2.7972599864006042e-01 -4.7203800082206726e-01 + <_> + + 0 -1 1003 3.8017999380826950e-02 + + -2.9200001154094934e-03 -1.1300059556961060e+00 + <_> + + 0 -1 1004 2.8659999370574951e-03 + + 4.1111800074577332e-01 -2.6220801472663879e-01 + <_> + + 0 -1 1005 -4.1606999933719635e-02 + + -1.4293819665908813e+00 -1.9132999703288078e-02 + <_> + + 0 -1 1006 -2.4802999570965767e-02 + + -2.5013598799705505e-01 1.5978699922561646e-01 + <_> + + 0 -1 1007 1.0098000057041645e-02 + + 4.3738998472690582e-02 -6.9986099004745483e-01 + <_> + + 0 -1 1008 -2.0947000011801720e-02 + + -9.4137799739837646e-01 2.3204000294208527e-01 + <_> + + 0 -1 1009 2.2458000108599663e-02 + + -2.7185800671577454e-01 4.5319199562072754e-01 + <_> + + 0 -1 1010 -3.7110999226570129e-02 + + -1.0314660072326660e+00 1.4421799778938293e-01 + <_> + + 0 -1 1011 -1.0648000054061413e-02 + + 6.3107001781463623e-01 -2.5520798563957214e-01 + <_> + + 0 -1 1012 5.5422998964786530e-02 + + 1.6206599771976471e-01 -1.7722640037536621e+00 + <_> + + 0 -1 1013 2.1601999178528786e-02 + + -2.5016099214553833e-01 5.4119801521301270e-01 + <_> + + 0 -1 1014 8.7000000348780304e-05 + + -2.9008901119232178e-01 3.3507999777793884e-01 + <_> + + 0 -1 1015 1.4406000263988972e-02 + + -7.8840004280209541e-03 -1.1677219867706299e+00 + <_> + + 0 -1 1016 1.0777399688959122e-01 + + 1.1292000114917755e-01 -2.4940319061279297e+00 + <_> + + 0 -1 1017 3.5943999886512756e-02 + + -1.9480599462985992e-01 9.5757502317428589e-01 + <_> + + 0 -1 1018 -3.9510000497102737e-03 + + 3.0927801132202148e-01 -2.5530201196670532e-01 + <_> + + 0 -1 1019 2.0942000672221184e-02 + + -7.6319999061524868e-03 -1.0086350440979004e+00 + <_> + + 0 -1 1020 -2.9877999797463417e-02 + + -4.6027699112892151e-01 1.9507199525833130e-01 + <_> + + 0 -1 1021 2.5971999391913414e-02 + + -1.2187999673187733e-02 -1.0035500526428223e+00 + <_> + + 0 -1 1022 1.0603000409901142e-02 + + -7.5969003140926361e-02 4.1669899225234985e-01 + <_> + + 0 -1 1023 8.5819996893405914e-03 + + -2.6648598909378052e-01 3.9111500978469849e-01 + <_> + + 0 -1 1024 2.1270999684929848e-02 + + 1.8273900449275970e-01 -3.6052298545837402e-01 + <_> + + 0 -1 1025 7.4518002569675446e-02 + + -1.8938399851322174e-01 9.2658001184463501e-01 + <_> + + 0 -1 1026 4.6569998376071453e-03 + + -1.4506199955940247e-01 3.3294600248336792e-01 + <_> + + 0 -1 1027 1.7119999974966049e-03 + + -5.2464002370834351e-01 8.9879997074604034e-02 + <_> + + 0 -1 1028 9.8500004969537258e-04 + + -3.8381999731063843e-01 2.4392999708652496e-01 + <_> + + 0 -1 1029 2.8233999386429787e-02 + + -5.7879998348653316e-03 -1.2617139816284180e+00 + <_> + + 0 -1 1030 -3.2678000628948212e-02 + + -5.7953298091888428e-01 1.6955299675464630e-01 + <_> + + 0 -1 1031 2.2536000236868858e-02 + + 2.2281000390648842e-02 -8.7869602441787720e-01 + <_> + + 0 -1 1032 -2.1657999604940414e-02 + + -6.5108501911163330e-01 1.2966899573802948e-01 + <_> + + 0 -1 1033 7.6799998059868813e-03 + + -3.3965200185775757e-01 2.2013300657272339e-01 + <_> + + 0 -1 1034 1.4592000283300877e-02 + + 1.5077300369739532e-01 -5.0452399253845215e-01 + <_> + + 0 -1 1035 2.7868000790476799e-02 + + -2.5045299530029297e-01 4.5741999149322510e-01 + <_> + + 0 -1 1036 5.6940000504255295e-03 + + -1.0948500037193298e-01 5.5757802724838257e-01 + <_> + + 0 -1 1037 -1.0002999566495419e-02 + + -9.7366297245025635e-01 1.8467999994754791e-02 + <_> + + 0 -1 1038 -4.0719998069107533e-03 + + 3.8222199678421021e-01 -1.6921100020408630e-01 + <_> + + 0 -1 1039 -2.2593999281525612e-02 + + -1.0391089916229248e+00 5.1839998923242092e-03 + <_> + + 0 -1 1040 -3.9579998701810837e-02 + + -5.5109229087829590e+00 1.1163999885320663e-01 + <_> + + 0 -1 1041 -1.7537999898195267e-02 + + 9.5485800504684448e-01 -1.8584500253200531e-01 + <_> + + 0 -1 1042 9.0300003066658974e-03 + + 1.0436000302433968e-02 8.2114797830581665e-01 + <_> + + 0 -1 1043 -7.9539995640516281e-03 + + 2.2632899880409241e-01 -3.4568199515342712e-01 + <_> + + 0 -1 1044 2.7091000229120255e-02 + + 1.6430099308490753e-01 -1.3926379680633545e+00 + <_> + + 0 -1 1045 -2.0625999197363853e-02 + + -8.6366099119186401e-01 2.3880000226199627e-03 + <_> + + 0 -1 1046 -7.1989998221397400e-02 + + -2.8192629814147949e+00 1.1570499837398529e-01 + <_> + + 0 -1 1047 -2.6964999735355377e-02 + + -1.2946130037307739e+00 -2.4661000818014145e-02 + <_> + + 0 -1 1048 -4.7377999871969223e-02 + + -8.1306397914886475e-01 1.1831399798393250e-01 + <_> + + 0 -1 1049 -1.0895600169897079e-01 + + 6.5937900543212891e-01 -2.0843900740146637e-01 + <_> + + 0 -1 1050 1.3574000447988510e-02 + + 7.4240001849830151e-03 5.3152197599411011e-01 + <_> + + 0 -1 1051 -6.6920001991093159e-03 + + 3.0655801296234131e-01 -3.1084299087524414e-01 + <_> + + 0 -1 1052 -3.9070001803338528e-03 + + 2.5576499104499817e-01 -5.2932001650333405e-02 + <_> + + 0 -1 1053 -3.7613000720739365e-02 + + -1.4350049495697021e+00 -1.5448000282049179e-02 + <_> + + 0 -1 1054 8.6329998448491096e-03 + + -1.6884399950504303e-01 4.2124900221824646e-01 + <_> + + 0 -1 1055 -3.2097000628709793e-02 + + -6.4979398250579834e-01 4.1110001504421234e-02 + <_> + + 0 -1 1056 5.8495998382568359e-02 + + -5.2963998168706894e-02 6.3368302583694458e-01 + <_> + + 0 -1 1057 -4.0901999920606613e-02 + + -9.2101097106933594e-01 9.0640000998973846e-03 + <_> + + 0 -1 1058 -1.9925000146031380e-02 + + 5.3759998083114624e-01 -6.2996998429298401e-02 + <_> + + 0 -1 1059 -4.6020001173019409e-03 + + -5.4333502054214478e-01 8.4104999899864197e-02 + <_> + + 0 -1 1060 1.6824999824166298e-02 + + 1.5563699603080750e-01 -4.0171200037002563e-01 + <_> + + 0 -1 1061 9.4790002331137657e-03 + + -2.4245299398899078e-01 5.1509499549865723e-01 + <_> + + 0 -1 1062 -1.9534999504685402e-02 + + -5.1118397712707520e-01 1.3831999897956848e-01 + <_> + + 0 -1 1063 1.0746000334620476e-02 + + -2.1854999661445618e-01 6.2828701734542847e-01 + <_> + + 0 -1 1064 3.7927001714706421e-02 + + 1.1640299856662750e-01 -2.7301959991455078e+00 + <_> + + 0 -1 1065 1.6390999779105186e-02 + + -1.4635999687016010e-02 -1.0797250270843506e+00 + <_> + + 0 -1 1066 -1.9785000011324883e-02 + + 1.2166420221328735e+00 3.3275000751018524e-02 + <_> + + 0 -1 1067 1.1067000217735767e-02 + + -2.5388300418853760e-01 4.4038599729537964e-01 + <_> + + 0 -1 1068 5.2479999139904976e-03 + + 2.2496800124645233e-01 -2.4216499924659729e-01 + <_> + + 0 -1 1069 -1.1141999624669552e-02 + + 2.5018098950386047e-01 -3.0811500549316406e-01 + <_> + + 0 -1 1070 -1.0666999965906143e-02 + + -3.2729101181030273e-01 2.6168298721313477e-01 + <_> + + 0 -1 1071 1.0545299947261810e-01 + + -5.5750001221895218e-02 -1.9605729579925537e+00 + <_> + + 0 -1 1072 5.4827999323606491e-02 + + -1.9519999623298645e-03 7.3866099119186401e-01 + <_> + + 0 -1 1073 1.7760999500751495e-02 + + -3.0647200345993042e-01 2.6346999406814575e-01 + <_> + + 0 -1 1074 -3.1185999512672424e-02 + + -2.4600900709629059e-01 1.7082199454307556e-01 + <_> + + 0 -1 1075 -5.7296000421047211e-02 + + 4.7033500671386719e-01 -2.6048299670219421e-01 + <_> + + 0 -1 1076 -1.1312000453472137e-02 + + 3.8628900051116943e-01 -2.8817000985145569e-01 + <_> + + 0 -1 1077 3.0592000111937523e-02 + + -4.8826001584529877e-02 -1.7638969421386719e+00 + <_> + + 0 -1 1078 1.8489999929443002e-03 + + 2.1099899709224701e-01 -2.5940999388694763e-02 + <_> + + 0 -1 1079 1.1419000104069710e-02 + + -1.6829599440097809e-01 1.0278660058975220e+00 + <_> + + 0 -1 1080 8.1403002142906189e-02 + + 1.1531999707221985e-01 -1.2482399940490723e+00 + <_> + + 0 -1 1081 5.3495999425649643e-02 + + -4.6303998678922653e-02 -1.7165969610214233e+00 + <_> + + 0 -1 1082 -2.3948000743985176e-02 + + -4.0246599912643433e-01 2.0562100410461426e-01 + <_> + + 0 -1 1083 6.7690000869333744e-03 + + -3.3152300119400024e-01 2.0683400332927704e-01 + <_> + + 0 -1 1084 -3.2343998551368713e-02 + + -7.2632801532745361e-01 2.0073500275611877e-01 + <_> + + 0 -1 1085 3.7863001227378845e-02 + + -1.5631000697612762e-01 1.6697460412979126e+00 + <_> + + 0 -1 1086 1.5440000221133232e-02 + + 1.9487400352954865e-01 -3.5384199023246765e-01 + <_> + + 0 -1 1087 -4.4376000761985779e-02 + + 8.2093602418899536e-01 -1.8193599581718445e-01 + <_> + + 0 -1 1088 -2.3102000355720520e-02 + + -4.3044099211692810e-01 1.2375400215387344e-01 + <_> + + 0 -1 1089 1.9400000572204590e-02 + + -2.9726000502705574e-02 -1.1597590446472168e+00 + <_> + + 0 -1 1090 1.0385700315237045e-01 + + 1.1149899661540985e-01 -4.6835222244262695e+00 + <_> + + 0 -1 1091 -1.8964000046253204e-02 + + 2.1773819923400879e+00 -1.4544400572776794e-01 + <_> + + 0 -1 1092 3.8750998675823212e-02 + + -4.9446001648902893e-02 3.4018298983573914e-01 + <_> + + 0 -1 1093 2.2766999900341034e-02 + + -3.2802999019622803e-01 3.0531400442123413e-01 + <_> + + 0 -1 1094 -3.1357001513242722e-02 + + 1.1520819664001465e+00 2.7305999770760536e-02 + <_> + + 0 -1 1095 9.6909999847412109e-03 + + -3.8799500465393066e-01 2.1512599289417267e-01 + <_> + + 0 -1 1096 -4.9284998327493668e-02 + + -1.6774909496307373e+00 1.5774199366569519e-01 + <_> + + 0 -1 1097 -3.9510998874902725e-02 + + -9.7647899389266968e-01 -1.0552000254392624e-02 + <_> + + 0 -1 1098 4.7997999936342239e-02 + + 2.0843900740146637e-01 -6.8992799520492554e-01 + <_> + + 0 -1 1099 5.1422998309135437e-02 + + -1.6665300726890564e-01 1.2149239778518677e+00 + <_> + + 0 -1 1100 1.4279999770224094e-02 + + 2.3627699911594391e-01 -4.1396799683570862e-01 + <_> + + 0 -1 1101 -9.1611996293067932e-02 + + -9.2830902338027954e-01 -1.8345000222325325e-02 + <_> + + 0 -1 1102 6.5080001950263977e-03 + + -7.3647201061248779e-01 1.9497099518775940e-01 + <_> + + 0 -1 1103 3.5723000764846802e-02 + + 1.4197799563407898e-01 -4.2089301347732544e-01 + <_> + + 0 -1 1104 5.0638001412153244e-02 + + 1.1644000187516212e-02 7.8486597537994385e-01 + <_> + + 0 -1 1105 -1.4613999985158443e-02 + + -1.1909500360488892e+00 -3.5128001123666763e-02 + <_> + + 0 -1 1106 -3.8662999868392944e-02 + + 2.4314730167388916e+00 6.5647996962070465e-02 + <_> + + 0 -1 1107 -4.0346998721361160e-02 + + 7.1755301952362061e-01 -1.9108299911022186e-01 + <_> + + 0 -1 1108 2.3902000859379768e-02 + + 1.5646199882030487e-01 -7.9294800758361816e-01 + <_> + 137 + -3.5125269889831543e+00 + + <_> + + 0 -1 1109 8.5640000179409981e-03 + + -8.1450700759887695e-01 5.8875298500061035e-01 + <_> + + 0 -1 1110 -1.3292600214481354e-01 + + 9.3213397264480591e-01 -2.9367300868034363e-01 + <_> + + 0 -1 1111 9.8400004208087921e-03 + + -5.6462901830673218e-01 4.1647699475288391e-01 + <_> + + 0 -1 1112 5.0889998674392700e-03 + + -7.9232800006866455e-01 1.6975000500679016e-01 + <_> + + 0 -1 1113 -6.1039000749588013e-02 + + -1.4169000387191772e+00 2.5020999833941460e-02 + <_> + + 0 -1 1114 -4.6599999768659472e-04 + + 3.7982499599456787e-01 -4.1567099094390869e-01 + <_> + + 0 -1 1115 3.3889999613165855e-03 + + -4.0768599510192871e-01 3.5548499226570129e-01 + <_> + + 0 -1 1116 2.1006999537348747e-02 + + -2.4080100655555725e-01 8.6112701892852783e-01 + <_> + + 0 -1 1117 7.5559997931122780e-03 + + -8.7467199563980103e-01 9.8572000861167908e-02 + <_> + + 0 -1 1118 2.4779999628663063e-02 + + 1.5566200017929077e-01 -6.9229799509048462e-01 + <_> + + 0 -1 1119 -3.5620000213384628e-02 + + -1.1472270488739014e+00 3.6359999328851700e-02 + <_> + + 0 -1 1120 1.9810000434517860e-02 + + 1.5516200661659241e-01 -6.9520097970962524e-01 + <_> + + 0 -1 1121 1.5019999817013741e-02 + + 4.1990000754594803e-02 -9.6622800827026367e-01 + <_> + + 0 -1 1122 -2.3137999698519707e-02 + + 4.3396899104118347e-01 2.4160000029951334e-03 + <_> + + 0 -1 1123 -1.8743000924587250e-02 + + 4.3481099605560303e-01 -3.2522499561309814e-01 + <_> + + 0 -1 1124 4.5080000162124634e-01 + + -9.4573996961116791e-02 7.2421300411224365e-01 + <_> + + 0 -1 1125 1.1854999698698521e-02 + + -3.8133099675178528e-01 3.0098399519920349e-01 + <_> + + 0 -1 1126 -2.4830000475049019e-02 + + 8.9300602674484253e-01 -1.0295899957418442e-01 + <_> + + 0 -1 1127 -4.4743001461029053e-02 + + 8.6280298233032227e-01 -2.1716499328613281e-01 + <_> + + 0 -1 1128 -1.4600000344216824e-02 + + 6.0069400072097778e-01 -1.5906299650669098e-01 + <_> + + 0 -1 1129 -2.4527000263333321e-02 + + -1.5872869491577148e+00 -2.1817000582814217e-02 + <_> + + 0 -1 1130 2.3024000227451324e-02 + + 1.6853399574756622e-01 -3.8106900453567505e-01 + <_> + + 0 -1 1131 -2.4917000904679298e-02 + + 5.0810897350311279e-01 -2.7279898524284363e-01 + <_> + + 0 -1 1132 1.0130000300705433e-03 + + -4.3138799071311951e-01 2.6438099145889282e-01 + <_> + + 0 -1 1133 1.5603000298142433e-02 + + -3.1624200940132141e-01 5.5715900659561157e-01 + <_> + + 0 -1 1134 -2.6685999706387520e-02 + + 1.0553920269012451e+00 2.9074000194668770e-02 + <_> + + 0 -1 1135 1.3940000208094716e-03 + + -7.1873801946640015e-01 6.5390996634960175e-02 + <_> + + 0 -1 1136 -6.4799998654052615e-04 + + 2.4884399771690369e-01 -2.0978200435638428e-01 + <_> + + 0 -1 1137 -3.1888000667095184e-02 + + -6.8844497203826904e-01 6.3589997589588165e-02 + <_> + + 0 -1 1138 -4.9290000461041927e-03 + + -5.9152501821517944e-01 2.7943599224090576e-01 + <_> + + 0 -1 1139 3.1168000772595406e-02 + + 4.5223999768495560e-02 -8.8639199733734131e-01 + <_> + + 0 -1 1140 -3.3663000911474228e-02 + + -6.1590200662612915e-01 1.5749299526214600e-01 + <_> + + 0 -1 1141 1.1966999620199203e-02 + + -3.0606698989868164e-01 4.2293301224708557e-01 + <_> + + 0 -1 1142 -3.4680001437664032e-02 + + -1.3734940290451050e+00 1.5908700227737427e-01 + <_> + + 0 -1 1143 9.9290004000067711e-03 + + -5.5860197544097900e-01 1.2119200080633163e-01 + <_> + + 0 -1 1144 5.9574998915195465e-02 + + 4.9720001406967640e-03 8.2055401802062988e-01 + <_> + + 0 -1 1145 -6.5428003668785095e-02 + + 1.5651429891586304e+00 -1.6817499697208405e-01 + <_> + + 0 -1 1146 -9.2895999550819397e-02 + + -1.5794529914855957e+00 1.4661799371242523e-01 + <_> + + 0 -1 1147 -4.1184000670909882e-02 + + -1.5518720149993896e+00 -2.9969999566674232e-02 + <_> + + 0 -1 1148 2.1447999402880669e-02 + + 1.7196300625801086e-01 -6.9343197345733643e-01 + <_> + + 0 -1 1149 -2.5569999590516090e-02 + + -1.3061310052871704e+00 -2.4336999282240868e-02 + <_> + + 0 -1 1150 -4.1200999170541763e-02 + + -1.3821059465408325e+00 1.4801800251007080e-01 + <_> + + 0 -1 1151 -1.7668999731540680e-02 + + -7.0889997482299805e-01 3.6524001508951187e-02 + <_> + + 0 -1 1152 9.0060001239180565e-03 + + -4.0913999080657959e-02 8.0373102426528931e-01 + <_> + + 0 -1 1153 -1.1652999557554722e-02 + + 5.7546800374984741e-01 -2.4991700053215027e-01 + <_> + + 0 -1 1154 -7.4780001305043697e-03 + + -4.9280899763107300e-01 1.9810900092124939e-01 + <_> + + 0 -1 1155 8.5499999113380909e-04 + + -4.8858100175857544e-01 1.3563099503517151e-01 + <_> + + 0 -1 1156 -3.0538000166416168e-02 + + -6.0278397798538208e-01 1.8522000312805176e-01 + <_> + + 0 -1 1157 -1.8846999853849411e-02 + + 2.3565599322319031e-01 -3.5136300325393677e-01 + <_> + + 0 -1 1158 -8.1129996106028557e-03 + + -8.1304997205734253e-02 2.1069599688053131e-01 + <_> + + 0 -1 1159 -3.4830000251531601e-02 + + -1.2065670490264893e+00 -1.4251999557018280e-02 + <_> + + 0 -1 1160 1.9021000713109970e-02 + + 2.3349900543689728e-01 -4.5664900541305542e-01 + <_> + + 0 -1 1161 -1.9004000350832939e-02 + + -8.1075799465179443e-01 1.3140000402927399e-02 + <_> + + 0 -1 1162 -8.9057996869087219e-02 + + 6.1542397737503052e-01 3.2983001321554184e-02 + <_> + + 0 -1 1163 6.8620000965893269e-03 + + -2.9583099484443665e-01 2.7003699541091919e-01 + <_> + + 0 -1 1164 -2.8240999206900597e-02 + + -6.1102700233459473e-01 1.7357499897480011e-01 + <_> + + 0 -1 1165 -3.2099999953061342e-04 + + -5.3322899341583252e-01 6.8539001047611237e-02 + <_> + + 0 -1 1166 -1.0829100012779236e-01 + + -1.2879559993743896e+00 1.1801700294017792e-01 + <_> + + 0 -1 1167 1.5878999605774879e-02 + + -1.7072600126266479e-01 1.1103910207748413e+00 + <_> + + 0 -1 1168 8.6859995499253273e-03 + + -1.0995099693536758e-01 4.6010500192642212e-01 + <_> + + 0 -1 1169 -2.5234999135136604e-02 + + 1.0220669507980347e+00 -1.8694299459457397e-01 + <_> + + 0 -1 1170 -1.3508999720215797e-02 + + -7.8316599130630493e-01 1.4202600717544556e-01 + <_> + + 0 -1 1171 -7.7149998396635056e-03 + + -8.8060700893402100e-01 1.1060000397264957e-02 + <_> + + 0 -1 1172 7.1580000221729279e-02 + + 1.1369399726390839e-01 -1.1032789945602417e+00 + <_> + + 0 -1 1173 -1.3554000295698643e-02 + + -8.1096500158309937e-01 3.4080001059919596e-03 + <_> + + 0 -1 1174 2.9450000729411840e-03 + + -7.2879999876022339e-02 3.4998100996017456e-01 + <_> + + 0 -1 1175 -5.0833001732826233e-02 + + -1.2868590354919434e+00 -2.8842000290751457e-02 + <_> + + 0 -1 1176 -8.7989997118711472e-03 + + 4.7613599896430969e-01 -1.4690400660037994e-01 + <_> + + 0 -1 1177 2.1424399316310883e-01 + + -5.9702001512050629e-02 -2.4802260398864746e+00 + <_> + + 0 -1 1178 1.3962999917566776e-02 + + 1.7420299351215363e-01 -4.3911001086235046e-01 + <_> + + 0 -1 1179 4.2502000927925110e-02 + + -1.9965299963951111e-01 7.0654797554016113e-01 + <_> + + 0 -1 1180 1.9827999174594879e-02 + + -6.9136001169681549e-02 6.1643397808074951e-01 + <_> + + 0 -1 1181 -3.3560000360012054e-02 + + -1.2740780115127563e+00 -2.5673000141978264e-02 + <_> + + 0 -1 1182 6.3542999327182770e-02 + + 1.2403500080108643e-01 -1.0776289701461792e+00 + <_> + + 0 -1 1183 2.1933000534772873e-02 + + 1.4952000230550766e-02 -7.1023499965667725e-01 + <_> + + 0 -1 1184 -7.8424997627735138e-02 + + 6.2033998966217041e-01 3.3610999584197998e-02 + <_> + + 0 -1 1185 1.4390000142157078e-02 + + -3.6324599385261536e-01 1.7308300733566284e-01 + <_> + + 0 -1 1186 -6.7309997975826263e-02 + + 5.2374100685119629e-01 1.2799999676644802e-02 + <_> + + 0 -1 1187 1.3047499954700470e-01 + + -1.7122499644756317e-01 1.1235200166702271e+00 + <_> + + 0 -1 1188 -4.6245999634265900e-02 + + -1.1908329725265503e+00 1.7425599694252014e-01 + <_> + + 0 -1 1189 -2.9842000454664230e-02 + + 8.3930599689483643e-01 -1.8064199388027191e-01 + <_> + + 0 -1 1190 -3.8099999073892832e-04 + + 3.5532799363136292e-01 -2.3842300474643707e-01 + <_> + + 0 -1 1191 -2.2378999739885330e-02 + + -8.7943899631500244e-01 -7.8399997437372804e-04 + <_> + + 0 -1 1192 -1.5569999814033508e-03 + + -1.4253300428390503e-01 2.5876200199127197e-01 + <_> + + 0 -1 1193 1.2013000436127186e-02 + + -2.9015499353408813e-01 2.6051101088523865e-01 + <_> + + 0 -1 1194 2.4384999647736549e-02 + + -3.1438998878002167e-02 5.8695900440216064e-01 + <_> + + 0 -1 1195 -4.7180999070405960e-02 + + 6.9430100917816162e-01 -2.1816100180149078e-01 + <_> + + 0 -1 1196 -2.4893999099731445e-02 + + -6.4599299430847168e-01 1.5611599385738373e-01 + <_> + + 0 -1 1197 2.1944999694824219e-02 + + -2.7742000296711922e-02 -1.1346880197525024e+00 + <_> + + 0 -1 1198 1.8809899687767029e-01 + + -1.0076000355184078e-02 1.2429029941558838e+00 + <_> + + 0 -1 1199 -7.7872000634670258e-02 + + 8.5008001327514648e-01 -1.9015499949455261e-01 + <_> + + 0 -1 1200 -4.8769000917673111e-02 + + -2.0763080120086670e+00 1.2179400026798248e-01 + <_> + + 0 -1 1201 -1.7115000635385513e-02 + + -8.5687297582626343e-01 7.8760003671050072e-03 + <_> + + 0 -1 1202 -2.7499999850988388e-03 + + 3.8645499944686890e-01 -1.1391499638557434e-01 + <_> + + 0 -1 1203 -9.8793998360633850e-02 + + -1.7233899831771851e+00 -5.6063000112771988e-02 + <_> + + 0 -1 1204 -2.1936999633908272e-02 + + 5.4749399423599243e-01 -4.2481999844312668e-02 + <_> + + 0 -1 1205 6.1096999794244766e-02 + + -3.8945000618696213e-02 -1.0807880163192749e+00 + <_> + + 0 -1 1206 -2.4563999846577644e-02 + + 5.8311098814010620e-01 -9.7599998116493225e-04 + <_> + + 0 -1 1207 3.3752001821994781e-02 + + -1.3795999810099602e-02 -8.4730297327041626e-01 + <_> + + 0 -1 1208 3.8199000060558319e-02 + + 1.5114299952983856e-01 -7.9473400115966797e-01 + <_> + + 0 -1 1209 -2.0117999985814095e-02 + + 5.1579099893569946e-01 -2.1445399522781372e-01 + <_> + + 0 -1 1210 2.4734999984502792e-02 + + -2.2105000913143158e-02 4.2917698621749878e-01 + <_> + + 0 -1 1211 -2.4357000365853310e-02 + + -8.6201298236846924e-01 -3.6760000512003899e-03 + <_> + + 0 -1 1212 -2.6442000642418861e-02 + + -4.5397499203681946e-01 2.2462800145149231e-01 + <_> + + 0 -1 1213 -3.4429999068379402e-03 + + 1.3073000311851501e-01 -3.8622701168060303e-01 + <_> + + 0 -1 1214 1.0701700299978256e-01 + + 1.3158600032329559e-01 -7.9306900501251221e-01 + <_> + + 0 -1 1215 4.5152999460697174e-02 + + -2.5296801328659058e-01 4.0672400593757629e-01 + <_> + + 0 -1 1216 4.4349998235702515e-02 + + 2.2613000124692917e-02 7.9618102312088013e-01 + <_> + + 0 -1 1217 1.0839999886229634e-03 + + -3.9158400893211365e-01 1.1639100313186646e-01 + <_> + + 0 -1 1218 7.1433000266551971e-02 + + 8.2466997206211090e-02 1.2530590295791626e+00 + <_> + + 0 -1 1219 3.5838000476360321e-02 + + -1.8203300237655640e-01 7.7078700065612793e-01 + <_> + + 0 -1 1220 -2.0839000120759010e-02 + + -6.1744397878646851e-01 1.5891399979591370e-01 + <_> + + 0 -1 1221 4.2525801062583923e-01 + + -4.8978000879287720e-02 -1.8422030210494995e+00 + <_> + + 0 -1 1222 1.1408000253140926e-02 + + 1.7918199300765991e-01 -1.5383499860763550e-01 + <_> + + 0 -1 1223 -1.5364999882876873e-02 + + -8.4016501903533936e-01 -1.0280000278726220e-03 + <_> + + 0 -1 1224 -1.5212000347673893e-02 + + -1.8995699286460876e-01 1.7130999267101288e-01 + <_> + + 0 -1 1225 -1.8972000107169151e-02 + + -7.9541999101638794e-01 6.6800001077353954e-03 + <_> + + 0 -1 1226 -3.3330000005662441e-03 + + -2.3530800640583038e-01 2.4730099737644196e-01 + <_> + + 0 -1 1227 9.3248002231121063e-02 + + -5.4758001118898392e-02 -1.8324300050735474e+00 + <_> + + 0 -1 1228 -1.2555000372231007e-02 + + 2.6385200023651123e-01 -3.8526400923728943e-01 + <_> + + 0 -1 1229 -2.7070000767707825e-02 + + -6.6929799318313599e-01 2.0340999588370323e-02 + <_> + + 0 -1 1230 -2.3677000775933266e-02 + + 6.7265301942825317e-01 -1.4344000257551670e-02 + <_> + + 0 -1 1231 -1.4275000430643559e-02 + + 3.0186399817466736e-01 -2.8514400124549866e-01 + <_> + + 0 -1 1232 2.8096999973058701e-02 + + 1.4766000211238861e-01 -1.4078520536422729e+00 + <_> + + 0 -1 1233 5.0840001553297043e-02 + + -1.8613600730895996e-01 7.9953002929687500e-01 + <_> + + 0 -1 1234 1.1505999602377415e-02 + + 1.9118399918079376e-01 -8.5035003721714020e-02 + <_> + + 0 -1 1235 -1.4661000110208988e-02 + + 4.5239299535751343e-01 -2.2205199301242828e-01 + <_> + + 0 -1 1236 2.2842499613761902e-01 + + 1.3488399982452393e-01 -1.2894610166549683e+00 + <_> + + 0 -1 1237 1.1106900125741959e-01 + + -2.0753799378871918e-01 5.4561597108840942e-01 + <_> + + 0 -1 1238 3.2450000289827585e-03 + + 3.2053700089454651e-01 -1.6403500735759735e-01 + <_> + + 0 -1 1239 8.5309997200965881e-02 + + -2.0210500061511993e-01 5.3296798467636108e-01 + <_> + + 0 -1 1240 2.2048000246286392e-02 + + 1.5698599815368652e-01 -1.7014099657535553e-01 + <_> + + 0 -1 1241 -1.5676999464631081e-02 + + -6.2863498926162720e-01 4.0761999785900116e-02 + <_> + + 0 -1 1242 3.3112901449203491e-01 + + 1.6609300673007965e-01 -1.0326379537582397e+00 + <_> + + 0 -1 1243 8.8470000773668289e-03 + + -2.5076198577880859e-01 3.1660598516464233e-01 + <_> + + 0 -1 1244 4.6080000698566437e-02 + + 1.5352100133895874e-01 -1.6333500146865845e+00 + <_> + + 0 -1 1245 -3.7703000009059906e-02 + + 5.6873798370361328e-01 -2.0102599263191223e-01 + <_> + 159 + -3.5939640998840332e+00 + + <_> + + 0 -1 1246 -8.1808999180793762e-02 + + 5.7124799489974976e-01 -6.7438799142837524e-01 + <_> + + 0 -1 1247 2.1761199831962585e-01 + + -3.8610199093818665e-01 9.0343999862670898e-01 + <_> + + 0 -1 1248 1.4878000132739544e-02 + + 2.2241599857807159e-01 -1.2779350280761719e+00 + <_> + + 0 -1 1249 5.2434999495744705e-02 + + -2.8690400719642639e-01 7.5742298364639282e-01 + <_> + + 0 -1 1250 9.1429995372891426e-03 + + -6.4880400896072388e-01 2.2268800437450409e-01 + <_> + + 0 -1 1251 7.9169999808073044e-03 + + -2.9253599047660828e-01 3.1030198931694031e-01 + <_> + + 0 -1 1252 -2.6084000244736671e-02 + + 4.5532700419425964e-01 -3.8500601053237915e-01 + <_> + + 0 -1 1253 -2.9400000348687172e-03 + + -5.1264399290084839e-01 2.7432298660278320e-01 + <_> + + 0 -1 1254 5.7130001485347748e-02 + + 1.5788000077009201e-02 -1.2133100032806396e+00 + <_> + + 0 -1 1255 -6.1309998854994774e-03 + + 3.9174601435661316e-01 -3.0866798758506775e-01 + <_> + + 0 -1 1256 -4.0405001491308212e-02 + + 1.1901949644088745e+00 -2.0347100496292114e-01 + <_> + + 0 -1 1257 -2.0297000184655190e-02 + + -6.8239498138427734e-01 2.0458699762821198e-01 + <_> + + 0 -1 1258 -1.7188999801874161e-02 + + -8.4939897060394287e-01 3.8433000445365906e-02 + <_> + + 0 -1 1259 -2.4215999990701675e-02 + + -1.1039420366287231e+00 1.5975099802017212e-01 + <_> + + 0 -1 1260 5.6869000196456909e-02 + + -1.9595299661159515e-01 1.1806850433349609e+00 + <_> + + 0 -1 1261 3.6199999158270657e-04 + + -4.0847799181938171e-01 3.2938599586486816e-01 + <_> + + 0 -1 1262 9.9790003150701523e-03 + + -2.9673001170158386e-01 4.1547900438308716e-01 + <_> + + 0 -1 1263 -5.2625000476837158e-02 + + -1.3069299459457397e+00 1.7862600088119507e-01 + <_> + + 0 -1 1264 -1.3748999685049057e-02 + + 2.3665800690650940e-01 -4.4536599516868591e-01 + <_> + + 0 -1 1265 -3.0517000705003738e-02 + + 2.9018300771713257e-01 -1.1210100352764130e-01 + <_> + + 0 -1 1266 -3.0037501454353333e-01 + + -2.4237680435180664e+00 -4.2830999940633774e-02 + <_> + + 0 -1 1267 -3.5990998148918152e-02 + + 8.8206499814987183e-01 -4.7012999653816223e-02 + <_> + + 0 -1 1268 -5.5112000554800034e-02 + + 8.0119001865386963e-01 -2.0490999519824982e-01 + <_> + + 0 -1 1269 3.3762000501155853e-02 + + 1.4617599546909332e-01 -1.1349489688873291e+00 + <_> + + 0 -1 1270 -8.2710003480315208e-03 + + -8.1604897975921631e-01 1.8988000229001045e-02 + <_> + + 0 -1 1271 -5.4399999789893627e-03 + + -7.0980900526046753e-01 2.2343699634075165e-01 + <_> + + 0 -1 1272 3.1059999018907547e-03 + + -7.2808599472045898e-01 4.0224999189376831e-02 + <_> + + 0 -1 1273 5.3651999682188034e-02 + + 1.7170900106430054e-01 -1.1163710355758667e+00 + <_> + + 0 -1 1274 -1.2541399896144867e-01 + + 2.7680370807647705e+00 -1.4611500501632690e-01 + <_> + + 0 -1 1275 9.2542000114917755e-02 + + 1.1609800159931183e-01 -3.9635529518127441e+00 + <_> + + 0 -1 1276 3.8513999432325363e-02 + + -7.6399999670684338e-03 -9.8780900239944458e-01 + <_> + + 0 -1 1277 -2.0200000144541264e-03 + + 2.3059999942779541e-01 -7.4970299005508423e-01 + <_> + + 0 -1 1278 9.7599998116493225e-03 + + -3.1137999892234802e-01 3.0287799239158630e-01 + <_> + + 0 -1 1279 2.4095000699162483e-02 + + -4.9529999494552612e-02 5.2690100669860840e-01 + <_> + + 0 -1 1280 -1.7982000485062599e-02 + + -1.1610640287399292e+00 -5.7000000961124897e-03 + <_> + + 0 -1 1281 -1.0555000044405460e-02 + + -2.7189099788665771e-01 2.3597699403762817e-01 + <_> + + 0 -1 1282 -7.2889998555183411e-03 + + -5.4219102859497070e-01 8.1914000213146210e-02 + <_> + + 0 -1 1283 2.3939000442624092e-02 + + 1.7975799739360809e-01 -6.7049497365951538e-01 + <_> + + 0 -1 1284 -1.8365999683737755e-02 + + 6.2664300203323364e-01 -2.0970100164413452e-01 + <_> + + 0 -1 1285 1.5715999528765678e-02 + + 2.4193699657917023e-01 -1.0444309711456299e+00 + <_> + + 0 -1 1286 -4.8804000020027161e-02 + + -9.4060599803924561e-01 -3.7519999314099550e-03 + <_> + + 0 -1 1287 6.7130001261830330e-03 + + -7.5432002544403076e-02 6.1575299501419067e-01 + <_> + + 0 -1 1288 9.7770001739263535e-03 + + 3.9285000413656235e-02 -8.4810298681259155e-01 + <_> + + 0 -1 1289 1.4744999818503857e-02 + + 1.6968999803066254e-01 -5.0906401872634888e-01 + <_> + + 0 -1 1290 9.7079001367092133e-02 + + -3.3103000372648239e-02 -1.2706379890441895e+00 + <_> + + 0 -1 1291 4.8285998404026031e-02 + + 9.4329997897148132e-02 2.7203190326690674e+00 + <_> + + 0 -1 1292 9.7810002043843269e-03 + + -3.9533400535583496e-01 1.5363800525665283e-01 + <_> + + 0 -1 1293 -3.9893999695777893e-02 + + -2.2767400741577148e-01 1.3913999497890472e-01 + <_> + + 0 -1 1294 2.2848000749945641e-02 + + -2.7391999959945679e-01 3.4199500083923340e-01 + <_> + + 0 -1 1295 6.7179999314248562e-03 + + -1.0874299705028534e-01 4.8125401139259338e-01 + <_> + + 0 -1 1296 5.9599999338388443e-02 + + -4.9522001296281815e-02 -2.0117089748382568e+00 + <_> + + 0 -1 1297 6.9340001791715622e-03 + + 1.5037499368190765e-01 -1.1271899938583374e-01 + <_> + + 0 -1 1298 1.5757000073790550e-02 + + -2.0885000005364418e-02 -1.1651979684829712e+00 + <_> + + 0 -1 1299 -4.9690000712871552e-02 + + -8.0213499069213867e-01 1.4372299611568451e-01 + <_> + + 0 -1 1300 5.2347000688314438e-02 + + -2.0836700499057770e-01 6.1677598953247070e-01 + <_> + + 0 -1 1301 2.2430999204516411e-02 + + 2.0305900275707245e-01 -7.5326198339462280e-01 + <_> + + 0 -1 1302 4.1142001748085022e-02 + + -1.8118199706077576e-01 1.0033359527587891e+00 + <_> + + 0 -1 1303 -2.1632000803947449e-02 + + 4.9998998641967773e-01 -3.4662999212741852e-02 + <_> + + 0 -1 1304 -8.2808002829551697e-02 + + 1.1711900234222412e+00 -1.8433600664138794e-01 + <_> + + 0 -1 1305 8.5060000419616699e-03 + + -6.3225001096725464e-02 2.9024899005889893e-01 + <_> + + 0 -1 1306 7.8905001282691956e-02 + + -2.3274500668048859e-01 5.9695798158645630e-01 + <_> + + 0 -1 1307 -9.0207003057003021e-02 + + -8.2211899757385254e-01 1.7772200703620911e-01 + <_> + + 0 -1 1308 -2.9269000515341759e-02 + + 6.0860699415206909e-01 -2.1468900144100189e-01 + <_> + + 0 -1 1309 6.9499998353421688e-03 + + -4.2665999382734299e-02 6.0512101650238037e-01 + <_> + + 0 -1 1310 -8.0629996955394745e-03 + + -1.1508270502090454e+00 -2.7286000549793243e-02 + <_> + + 0 -1 1311 1.9595999270677567e-02 + + -9.1880001127719879e-03 5.6857800483703613e-01 + <_> + + 0 -1 1312 -1.4884999953210354e-02 + + 3.7658798694610596e-01 -2.7149501442909241e-01 + <_> + + 0 -1 1313 2.5217000395059586e-02 + + -9.9991001188755035e-02 2.4664700031280518e-01 + <_> + + 0 -1 1314 -1.5855999663472176e-02 + + 6.6826701164245605e-01 -2.0614700019359589e-01 + <_> + + 0 -1 1315 2.9441000893712044e-02 + + 1.5832200646400452e-01 -7.6060897111892700e-01 + <_> + + 0 -1 1316 -8.5279997438192368e-03 + + 3.8212299346923828e-01 -2.5407800078392029e-01 + <_> + + 0 -1 1317 2.4421999230980873e-02 + + 1.5105099976062775e-01 -2.8752899169921875e-01 + <_> + + 0 -1 1318 -3.3886998891830444e-02 + + -6.8002802133560181e-01 3.4327000379562378e-02 + <_> + + 0 -1 1319 -2.0810000132769346e-03 + + 2.5413900613784790e-01 -2.6859098672866821e-01 + <_> + + 0 -1 1320 3.0358999967575073e-02 + + -3.0842000618577003e-02 -1.1476809978485107e+00 + <_> + + 0 -1 1321 4.0210001170635223e-03 + + -3.5253798961639404e-01 2.9868099093437195e-01 + <_> + + 0 -1 1322 2.7681000530719757e-02 + + -3.8148999214172363e-02 -1.3262039422988892e+00 + <_> + + 0 -1 1323 7.9039996489882469e-03 + + -2.3737000301480293e-02 7.0503002405166626e-01 + <_> + + 0 -1 1324 4.4031001627445221e-02 + + 1.0674899816513062e-01 -4.5261201262474060e-01 + <_> + + 0 -1 1325 -3.2370999455451965e-02 + + 4.6674901247024536e-01 -6.1546999961137772e-02 + <_> + + 0 -1 1326 2.0933000370860100e-02 + + -2.8447899222373962e-01 4.3845599889755249e-01 + <_> + + 0 -1 1327 2.5227999314665794e-02 + + -2.2537000477313995e-02 7.0389097929000854e-01 + <_> + + 0 -1 1328 6.5520000644028187e-03 + + -3.2554900646209717e-01 2.4023699760437012e-01 + <_> + + 0 -1 1329 -5.8557998389005661e-02 + + -1.2227720022201538e+00 1.1668799817562103e-01 + <_> + + 0 -1 1330 3.1899999827146530e-02 + + -1.9305000081658363e-02 -1.0973169803619385e+00 + <_> + + 0 -1 1331 -3.0445000156760216e-02 + + 6.5582501888275146e-01 7.5090996921062469e-02 + <_> + + 0 -1 1332 1.4933000318706036e-02 + + -5.2155798673629761e-01 1.1523099988698959e-01 + <_> + + 0 -1 1333 -4.9008000642061234e-02 + + -7.8303998708724976e-01 1.6657200455665588e-01 + <_> + + 0 -1 1334 8.3158999681472778e-02 + + -2.6879999786615372e-03 -8.5282301902770996e-01 + <_> + + 0 -1 1335 2.3902999237179756e-02 + + -5.1010999828577042e-02 4.1999098658561707e-01 + <_> + + 0 -1 1336 1.6428999602794647e-02 + + 1.9232999533414841e-02 -6.5049099922180176e-01 + <_> + + 0 -1 1337 -1.1838000267744064e-02 + + -6.2409800291061401e-01 1.5411199629306793e-01 + <_> + + 0 -1 1338 -1.6799999866634607e-04 + + 1.7589199542999268e-01 -3.4338700771331787e-01 + <_> + + 0 -1 1339 1.9193999469280243e-02 + + 4.3418999761343002e-02 7.9069197177886963e-01 + <_> + + 0 -1 1340 -1.0032000020146370e-02 + + 4.5648899674415588e-01 -2.2494800388813019e-01 + <_> + + 0 -1 1341 -1.4004000462591648e-02 + + 3.3570998907089233e-01 -4.8799999058246613e-03 + <_> + + 0 -1 1342 -1.0319899767637253e-01 + + -2.3378000259399414e+00 -5.8933001011610031e-02 + <_> + + 0 -1 1343 -9.5697000622749329e-02 + + -6.6153901815414429e-01 2.0098599791526794e-01 + <_> + + 0 -1 1344 -4.1480999439954758e-02 + + 4.5939201116561890e-01 -2.2314099967479706e-01 + <_> + + 0 -1 1345 2.4099999573081732e-03 + + -2.6898598670959473e-01 2.4922999739646912e-01 + <_> + + 0 -1 1346 1.0724999755620956e-01 + + -1.8640199303627014e-01 7.2769802808761597e-01 + <_> + + 0 -1 1347 3.1870000530034304e-03 + + -2.4608999490737915e-02 2.8643900156021118e-01 + <_> + + 0 -1 1348 2.9167000204324722e-02 + + -3.4683000296354294e-02 -1.1162580251693726e+00 + <_> + + 0 -1 1349 1.1287000030279160e-02 + + 6.3760001212358475e-03 6.6632097959518433e-01 + <_> + + 0 -1 1350 -1.2001000344753265e-02 + + 4.2420101165771484e-01 -2.6279801130294800e-01 + <_> + + 0 -1 1351 -1.2695999816060066e-02 + + -2.1957000717520714e-02 1.8936799466609955e-01 + <_> + + 0 -1 1352 2.4597000330686569e-02 + + -3.4963998943567276e-02 -1.0989320278167725e+00 + <_> + + 0 -1 1353 4.5953001827001572e-02 + + 1.1109799891710281e-01 -2.9306049346923828e+00 + <_> + + 0 -1 1354 -2.7241000905632973e-02 + + 2.9101699590682983e-01 -2.7407899498939514e-01 + <_> + + 0 -1 1355 4.0063999593257904e-02 + + 1.1877900362014771e-01 -6.2801802158355713e-01 + <_> + + 0 -1 1356 2.3055000230669975e-02 + + 1.4813800156116486e-01 -3.7007498741149902e-01 + <_> + + 0 -1 1357 -2.3737000301480293e-02 + + -5.3724801540374756e-01 1.9358199834823608e-01 + <_> + + 0 -1 1358 7.7522002160549164e-02 + + -6.0194000601768494e-02 -1.9489669799804688e+00 + <_> + + 0 -1 1359 -1.3345000334084034e-02 + + -4.5229598879814148e-01 1.8741500377655029e-01 + <_> + + 0 -1 1360 -2.1719999611377716e-02 + + 1.2144249677658081e+00 -1.5365800261497498e-01 + <_> + + 0 -1 1361 -7.1474999189376831e-02 + + -2.3047130107879639e+00 1.0999900102615356e-01 + <_> + + 0 -1 1362 -5.4999999701976776e-03 + + -7.1855199337005615e-01 2.0100999623537064e-02 + <_> + + 0 -1 1363 2.6740999892354012e-02 + + 7.3545001447200775e-02 9.8786002397537231e-01 + <_> + + 0 -1 1364 -3.9407998323440552e-02 + + -1.2227380275726318e+00 -4.3506998568773270e-02 + <_> + + 0 -1 1365 2.5888999924063683e-02 + + 1.3409300148487091e-01 -1.1770780086517334e+00 + <_> + + 0 -1 1366 4.8925001174211502e-02 + + -3.0810000374913216e-02 -9.3479502201080322e-01 + <_> + + 0 -1 1367 3.6892998963594437e-02 + + 1.3333700597286224e-01 -1.4998290538787842e+00 + <_> + + 0 -1 1368 7.8929997980594635e-02 + + -1.4538800716400146e-01 1.5631790161132812e+00 + <_> + + 0 -1 1369 2.9006000608205795e-02 + + 1.9383700191974640e-01 -6.7642802000045776e-01 + <_> + + 0 -1 1370 6.3089998438954353e-03 + + -3.7465399503707886e-01 1.0857500135898590e-01 + <_> + + 0 -1 1371 -6.5830998122692108e-02 + + 8.1059402227401733e-01 3.0201999470591545e-02 + <_> + + 0 -1 1372 -6.8965002894401550e-02 + + 8.3772599697113037e-01 -1.7140999436378479e-01 + <_> + + 0 -1 1373 -1.1669100075960159e-01 + + -9.4647198915481567e-01 1.3123199343681335e-01 + <_> + + 0 -1 1374 -1.3060000492259860e-03 + + 4.6007998287677765e-02 -5.2011597156524658e-01 + <_> + + 0 -1 1375 -4.4558998197317123e-02 + + -1.9423669576644897e+00 1.3200700283050537e-01 + <_> + + 0 -1 1376 5.1033001393079758e-02 + + -2.1480999886989594e-01 4.8673900961875916e-01 + <_> + + 0 -1 1377 -3.1578000634908676e-02 + + 5.9989798069000244e-01 7.9159997403621674e-03 + <_> + + 0 -1 1378 2.1020000800490379e-02 + + -2.2069500386714935e-01 5.4046201705932617e-01 + <_> + + 0 -1 1379 -1.3824200630187988e-01 + + 6.2957501411437988e-01 -2.1712999790906906e-02 + <_> + + 0 -1 1380 5.2228998392820358e-02 + + -2.3360900580883026e-01 4.9760800600051880e-01 + <_> + + 0 -1 1381 2.5884000584483147e-02 + + 1.8041999638080597e-01 -2.2039200365543365e-01 + <_> + + 0 -1 1382 -1.2138999998569489e-02 + + -6.9731897115707397e-01 1.5712000429630280e-02 + <_> + + 0 -1 1383 -2.4237999692559242e-02 + + 3.4593299031257629e-01 7.1469999849796295e-02 + <_> + + 0 -1 1384 -2.5272000581026077e-02 + + -8.7583297491073608e-01 -9.8240002989768982e-03 + <_> + + 0 -1 1385 1.2597000226378441e-02 + + 2.3649999499320984e-01 -2.8731200098991394e-01 + <_> + + 0 -1 1386 5.7330999523401260e-02 + + -6.1530999839305878e-02 -2.2326040267944336e+00 + <_> + + 0 -1 1387 1.6671000048518181e-02 + + -1.9850100576877594e-01 4.0810701251029968e-01 + <_> + + 0 -1 1388 -2.2818999364972115e-02 + + 9.6487599611282349e-01 -2.0245699584484100e-01 + <_> + + 0 -1 1389 3.7000001611886546e-05 + + -5.8908998966217041e-02 2.7055400609970093e-01 + <_> + + 0 -1 1390 -7.6700001955032349e-03 + + -4.5317101478576660e-01 8.9628003537654877e-02 + <_> + + 0 -1 1391 9.4085998833179474e-02 + + 1.1604599654674530e-01 -1.0951169729232788e+00 + <_> + + 0 -1 1392 -6.2267001718282700e-02 + + 1.8096530437469482e+00 -1.4773200452327728e-01 + <_> + + 0 -1 1393 1.7416000366210938e-02 + + 2.3068200051784515e-01 -4.2417600750923157e-01 + <_> + + 0 -1 1394 -2.2066000849008560e-02 + + 4.9270299077033997e-01 -2.0630900561809540e-01 + <_> + + 0 -1 1395 -1.0404000058770180e-02 + + 6.0924297571182251e-01 2.8130000457167625e-02 + <_> + + 0 -1 1396 -9.3670003116130829e-03 + + 4.0171200037002563e-01 -2.1681700646877289e-01 + <_> + + 0 -1 1397 -2.9039999470114708e-02 + + -8.4876501560211182e-01 1.4246800541877747e-01 + <_> + + 0 -1 1398 -2.1061999723315239e-02 + + -7.9198300838470459e-01 -1.2595999985933304e-02 + <_> + + 0 -1 1399 -3.7000998854637146e-02 + + -6.7488902807235718e-01 1.2830400466918945e-01 + <_> + + 0 -1 1400 1.0735999792814255e-02 + + 3.6779999732971191e-02 -6.3393002748489380e-01 + <_> + + 0 -1 1401 1.6367599368095398e-01 + + 1.3803899288177490e-01 -4.7189000248908997e-01 + <_> + + 0 -1 1402 9.4917997717857361e-02 + + -1.3855700194835663e-01 1.9492419958114624e+00 + <_> + + 0 -1 1403 3.5261999815702438e-02 + + 1.3721899688243866e-01 -2.1186530590057373e+00 + <_> + + 0 -1 1404 1.2811000458896160e-02 + + -2.0008100569248199e-01 4.9507799744606018e-01 + <_> + 155 + -3.3933560848236084e+00 + + <_> + + 0 -1 1405 1.3904400169849396e-01 + + -4.6581199765205383e-01 7.6431602239608765e-01 + <_> + + 0 -1 1406 1.1916999705135822e-02 + + -9.4398999214172363e-01 3.9726299047470093e-01 + <_> + + 0 -1 1407 -1.0006999596953392e-02 + + 3.2718798518180847e-01 -6.3367402553558350e-01 + <_> + + 0 -1 1408 -6.0479999519884586e-03 + + 2.7427899837493896e-01 -5.7446998357772827e-01 + <_> + + 0 -1 1409 -1.2489999644458294e-03 + + 2.3629300296306610e-01 -6.8593502044677734e-01 + <_> + + 0 -1 1410 3.2382000237703323e-02 + + -5.7630199193954468e-01 2.7492699027061462e-01 + <_> + + 0 -1 1411 -1.3957999646663666e-02 + + -6.1061501502990723e-01 2.4541600048542023e-01 + <_> + + 0 -1 1412 1.1159999994561076e-03 + + -5.6539100408554077e-01 2.7179300785064697e-01 + <_> + + 0 -1 1413 2.7000000045518391e-05 + + -8.0235999822616577e-01 1.1509100347757339e-01 + <_> + + 0 -1 1414 -2.5700000696815550e-04 + + -8.1205898523330688e-01 2.3844699561595917e-01 + <_> + + 0 -1 1415 4.0460000745952129e-03 + + 1.3909600675106049e-01 -6.6163200139999390e-01 + <_> + + 0 -1 1416 1.4356000348925591e-02 + + -1.6485199332237244e-01 4.1901698708534241e-01 + <_> + + 0 -1 1417 -5.5374998599290848e-02 + + 1.4425870180130005e+00 -1.8820199370384216e-01 + <_> + + 0 -1 1418 9.3594998121261597e-02 + + 1.3548299670219421e-01 -9.1636097431182861e-01 + <_> + + 0 -1 1419 2.6624999940395355e-02 + + -3.3748298883438110e-01 3.9233601093292236e-01 + <_> + + 0 -1 1420 3.7469998933374882e-03 + + -1.1615400016307831e-01 4.4399300217628479e-01 + <_> + + 0 -1 1421 -3.1886000186204910e-02 + + -9.9498301744461060e-01 1.6120000509545207e-03 + <_> + + 0 -1 1422 -2.2600000724196434e-02 + + -4.8067399859428406e-01 1.7007300257682800e-01 + <_> + + 0 -1 1423 2.5202000513672829e-02 + + 3.5580001771450043e-02 -8.0215400457382202e-01 + <_> + + 0 -1 1424 -3.1036999076604843e-02 + + -1.0895340442657471e+00 1.8081900477409363e-01 + <_> + + 0 -1 1425 -2.6475999504327774e-02 + + 9.5671200752258301e-01 -2.1049399673938751e-01 + <_> + + 0 -1 1426 -1.3853999786078930e-02 + + -1.0370320081710815e+00 2.2166700661182404e-01 + <_> + + 0 -1 1427 -6.2925003468990326e-02 + + 9.0199398994445801e-01 -1.9085299968719482e-01 + <_> + + 0 -1 1428 -4.4750999659299850e-02 + + -1.0119110345840454e+00 1.4691199362277985e-01 + <_> + + 0 -1 1429 -2.0428000018000603e-02 + + 6.1624497175216675e-01 -2.3552699387073517e-01 + <_> + + 0 -1 1430 -8.0329999327659607e-03 + + -8.3279997110366821e-02 2.1728700399398804e-01 + <_> + + 0 -1 1431 8.7280003353953362e-03 + + 6.5458998084068298e-02 -6.0318702459335327e-01 + <_> + + 0 -1 1432 -2.7202000841498375e-02 + + -9.3447399139404297e-01 1.5270000696182251e-01 + <_> + + 0 -1 1433 -1.6471000388264656e-02 + + -8.4177100658416748e-01 1.3332000002264977e-02 + <_> + + 0 -1 1434 -1.3744000345468521e-02 + + 6.0567200183868408e-01 -9.2021003365516663e-02 + <_> + + 0 -1 1435 2.9164999723434448e-02 + + -2.8114000335335732e-02 -1.4014569520950317e+00 + <_> + + 0 -1 1436 3.7457000464200974e-02 + + 1.3080599904060364e-01 -4.9382498860359192e-01 + <_> + + 0 -1 1437 -2.5070000439882278e-02 + + -1.1289390325546265e+00 -1.4600000344216824e-02 + <_> + + 0 -1 1438 -6.3812002539634705e-02 + + 7.5871598720550537e-01 -1.8200000049546361e-03 + <_> + + 0 -1 1439 -9.3900002539157867e-03 + + 2.9936400055885315e-01 -2.9487800598144531e-01 + <_> + + 0 -1 1440 -7.6000002445653081e-04 + + 1.9725000485777855e-02 1.9993899762630463e-01 + <_> + + 0 -1 1441 -2.1740999072790146e-02 + + -8.5247898101806641e-01 4.9169998615980148e-02 + <_> + + 0 -1 1442 -1.7869999632239342e-02 + + -5.9985999017953873e-02 1.5222500264644623e-01 + <_> + + 0 -1 1443 -2.4831000715494156e-02 + + 3.5603401064872742e-01 -2.6259899139404297e-01 + <_> + + 0 -1 1444 1.5715500712394714e-01 + + 1.5599999460391700e-04 1.0428730249404907e+00 + <_> + + 0 -1 1445 6.9026999175548553e-02 + + -3.3006999641656876e-02 -1.1796669960021973e+00 + <_> + + 0 -1 1446 -1.1021999642252922e-02 + + 5.8987700939178467e-01 -5.7647999376058578e-02 + <_> + + 0 -1 1447 -1.3834999874234200e-02 + + 5.9502798318862915e-01 -2.4418599903583527e-01 + <_> + + 0 -1 1448 -3.0941000208258629e-02 + + -1.1723799705505371e+00 1.6907000541687012e-01 + <_> + + 0 -1 1449 2.1258000284433365e-02 + + -1.8900999799370766e-02 -1.0684759616851807e+00 + <_> + + 0 -1 1450 9.3079999089241028e-02 + + 1.6305600106716156e-01 -1.3375270366668701e+00 + <_> + + 0 -1 1451 2.9635999351739883e-02 + + -2.2524799406528473e-01 4.5400100946426392e-01 + <_> + + 0 -1 1452 -1.2199999764561653e-04 + + 2.7409100532531738e-01 -3.7371399998664856e-01 + <_> + + 0 -1 1453 -4.2098000645637512e-02 + + -7.5828802585601807e-01 1.7137000337243080e-02 + <_> + + 0 -1 1454 -2.2505000233650208e-02 + + -2.2759300470352173e-01 2.3698699474334717e-01 + <_> + + 0 -1 1455 -1.2862999923527241e-02 + + 1.9252400100231171e-01 -3.2127100229263306e-01 + <_> + + 0 -1 1456 2.7860000729560852e-02 + + 1.6723699867725372e-01 -1.0209059715270996e+00 + <_> + + 0 -1 1457 -2.7807999402284622e-02 + + 1.2824759483337402e+00 -1.7225299775600433e-01 + <_> + + 0 -1 1458 -6.1630001291632652e-03 + + -5.4072898626327515e-01 2.3885700106620789e-01 + <_> + + 0 -1 1459 -2.0436000078916550e-02 + + 6.3355398178100586e-01 -2.1090599894523621e-01 + <_> + + 0 -1 1460 -1.2307999655604362e-02 + + -4.9778199195861816e-01 1.7402599751949310e-01 + <_> + + 0 -1 1461 -4.0493998676538467e-02 + + -1.1848740577697754e+00 -3.3890999853610992e-02 + <_> + + 0 -1 1462 2.9657000675797462e-02 + + 2.1740999072790146e-02 1.0069919824600220e+00 + <_> + + 0 -1 1463 6.8379999138414860e-03 + + 2.9217999428510666e-02 -5.9906297922134399e-01 + <_> + + 0 -1 1464 1.6164999455213547e-02 + + -2.1000799536705017e-01 3.7637299299240112e-01 + <_> + + 0 -1 1465 5.0193000584840775e-02 + + 2.5319999549537897e-03 -7.1668201684951782e-01 + <_> + + 0 -1 1466 1.9680000841617584e-03 + + -2.1921400725841522e-01 3.2298699021339417e-01 + <_> + + 0 -1 1467 2.4979999288916588e-02 + + -9.6840001642704010e-03 -7.7572900056838989e-01 + <_> + + 0 -1 1468 -1.5809999778866768e-02 + + 4.4637501239776611e-01 -6.1760000884532928e-02 + <_> + + 0 -1 1469 3.7206999957561493e-02 + + -2.0495399832725525e-01 5.7722198963165283e-01 + <_> + + 0 -1 1470 -7.9264998435974121e-02 + + -7.6745402812957764e-01 1.2550400197505951e-01 + <_> + + 0 -1 1471 -1.7152000218629837e-02 + + -1.4121830463409424e+00 -5.1704000681638718e-02 + <_> + + 0 -1 1472 3.2740000635385513e-02 + + 1.9334000349044800e-01 -6.3633698225021362e-01 + <_> + + 0 -1 1473 -1.1756999790668488e-01 + + 8.4325402975082397e-01 -1.8018600344657898e-01 + <_> + + 0 -1 1474 1.2057200074195862e-01 + + 1.2530000507831573e-01 -2.1213600635528564e+00 + <_> + + 0 -1 1475 4.2779999785125256e-03 + + -4.6604400873184204e-01 8.9643999934196472e-02 + <_> + + 0 -1 1476 -7.2544999420642853e-02 + + 5.1826500892639160e-01 1.6823999583721161e-02 + <_> + + 0 -1 1477 1.7710599303245544e-01 + + -3.0910000205039978e-02 -1.1046639680862427e+00 + <_> + + 0 -1 1478 8.4229996427893639e-03 + + 2.4445800483226776e-01 -3.8613098859786987e-01 + <_> + + 0 -1 1479 -1.3035000301897526e-02 + + 9.8004400730133057e-01 -1.7016500234603882e-01 + <_> + + 0 -1 1480 1.8912000581622124e-02 + + 2.0248499512672424e-01 -3.8545900583267212e-01 + <_> + + 0 -1 1481 2.1447999402880669e-02 + + -2.5717198848724365e-01 3.5181200504302979e-01 + <_> + + 0 -1 1482 6.3357003033161163e-02 + + 1.6994799673557281e-01 -9.1383802890777588e-01 + <_> + + 0 -1 1483 -3.2435998320579529e-02 + + -8.5681599378585815e-01 -2.1680999547243118e-02 + <_> + + 0 -1 1484 -2.3564999923110008e-02 + + 5.6115597486495972e-01 -2.2400000307243317e-04 + <_> + + 0 -1 1485 1.8789000809192657e-02 + + -2.5459799170494080e-01 3.4512901306152344e-01 + <_> + + 0 -1 1486 3.1042000278830528e-02 + + 7.5719999149441719e-03 3.4800198674201965e-01 + <_> + + 0 -1 1487 -1.1226999573409557e-02 + + -6.0219800472259521e-01 4.2814999818801880e-02 + <_> + + 0 -1 1488 -1.2845999561250210e-02 + + 4.2020401358604431e-01 -5.3801000118255615e-02 + <_> + + 0 -1 1489 -1.2791999615728855e-02 + + 2.2724500298500061e-01 -3.2398000359535217e-01 + <_> + + 0 -1 1490 6.8651996552944183e-02 + + 9.3532003462314606e-02 10. + <_> + + 0 -1 1491 5.2789999172091484e-03 + + -2.6926299929618835e-01 3.3303201198577881e-01 + <_> + + 0 -1 1492 -3.8779001682996750e-02 + + -7.2365301847457886e-01 1.7806500196456909e-01 + <_> + + 0 -1 1493 6.1820000410079956e-03 + + -3.5119399428367615e-01 1.6586300730705261e-01 + <_> + + 0 -1 1494 1.7515200376510620e-01 + + 1.1623100191354752e-01 -1.5419290065765381e+00 + <_> + + 0 -1 1495 1.1627999693155289e-01 + + -9.1479998081922531e-03 -9.9842602014541626e-01 + <_> + + 0 -1 1496 -2.2964000701904297e-02 + + 2.0565399527549744e-01 1.5432000160217285e-02 + <_> + + 0 -1 1497 -5.1410000771284103e-02 + + 5.8072400093078613e-01 -2.0118400454521179e-01 + <_> + + 0 -1 1498 2.2474199533462524e-01 + + 1.8728999421000481e-02 1.0829299688339233e+00 + <_> + + 0 -1 1499 9.4860000535845757e-03 + + -3.3171299099922180e-01 1.9902999699115753e-01 + <_> + + 0 -1 1500 -1.1846300214529037e-01 + + 1.3711010217666626e+00 6.8926997482776642e-02 + <_> + + 0 -1 1501 3.7810999900102615e-02 + + -9.3600002583116293e-04 -8.3996999263763428e-01 + <_> + + 0 -1 1502 2.2202000021934509e-02 + + -1.1963999830186367e-02 3.6673998832702637e-01 + <_> + + 0 -1 1503 -3.6366000771522522e-02 + + 3.7866500020027161e-01 -2.7714800834655762e-01 + <_> + + 0 -1 1504 -1.3184699416160583e-01 + + -2.7481179237365723e+00 1.0666900128126144e-01 + <_> + + 0 -1 1505 -4.1655998677015305e-02 + + 4.7524300217628479e-01 -2.3249800503253937e-01 + <_> + + 0 -1 1506 -3.3151999115943909e-02 + + -5.7929402589797974e-01 1.7434400320053101e-01 + <_> + + 0 -1 1507 1.5769999474287033e-02 + + -1.1284000240266323e-02 -8.3701401948928833e-01 + <_> + + 0 -1 1508 -3.9363000541925430e-02 + + 3.4821599721908569e-01 -1.7455400526523590e-01 + <_> + + 0 -1 1509 -6.7849002778530121e-02 + + 1.4225699901580811e+00 -1.4765599370002747e-01 + <_> + + 0 -1 1510 -2.6775000616908073e-02 + + 2.3947000503540039e-01 1.3271999545395374e-02 + <_> + + 0 -1 1511 3.9919000118970871e-02 + + -8.9999996125698090e-03 -7.5938898324966431e-01 + <_> + + 0 -1 1512 1.0065600275993347e-01 + + -1.8685000017285347e-02 7.6245301961898804e-01 + <_> + + 0 -1 1513 -8.1022001802921295e-02 + + -9.0439099073410034e-01 -8.5880002006888390e-03 + <_> + + 0 -1 1514 -2.1258000284433365e-02 + + -2.1319599449634552e-01 2.1919700503349304e-01 + <_> + + 0 -1 1515 -1.0630999691784382e-02 + + 1.9598099589347839e-01 -3.5768100619316101e-01 + <_> + + 0 -1 1516 8.1300002057105303e-04 + + -9.2794999480247498e-02 2.6145899295806885e-01 + <_> + + 0 -1 1517 3.4650000743567944e-03 + + -5.5336099863052368e-01 2.7386000379920006e-02 + <_> + + 0 -1 1518 1.8835999071598053e-02 + + 1.8446099758148193e-01 -6.6934299468994141e-01 + <_> + + 0 -1 1519 -2.5631999596953392e-02 + + 1.9382879734039307e+00 -1.4708900451660156e-01 + <_> + + 0 -1 1520 -4.0939999744296074e-03 + + -2.6451599597930908e-01 2.0733200013637543e-01 + <_> + + 0 -1 1521 -8.9199998183175921e-04 + + -5.5031597614288330e-01 5.0374999642372131e-02 + <_> + + 0 -1 1522 -4.9518000334501266e-02 + + -2.5615389347076416e+00 1.3141700625419617e-01 + <_> + + 0 -1 1523 1.1680999770760536e-02 + + -2.4819800257682800e-01 3.9982700347900391e-01 + <_> + + 0 -1 1524 3.4563999623060226e-02 + + 1.6178800165653229e-01 -7.1418899297714233e-01 + <_> + + 0 -1 1525 -8.2909995689988136e-03 + + 2.2180099785327911e-01 -2.9181700944900513e-01 + <_> + + 0 -1 1526 -2.2358000278472900e-02 + + 3.1044098734855652e-01 -2.7280000504106283e-03 + <_> + + 0 -1 1527 -3.0801000073552132e-02 + + -9.5672702789306641e-01 -8.3400001749396324e-03 + <_> + + 0 -1 1528 4.3779000639915466e-02 + + 1.2556900084018707e-01 -1.1759619712829590e+00 + <_> + + 0 -1 1529 4.3046001344919205e-02 + + -5.8876998722553253e-02 -1.8568470478057861e+00 + <_> + + 0 -1 1530 2.7188999578356743e-02 + + 4.2858000844717026e-02 3.9036700129508972e-01 + <_> + + 0 -1 1531 9.4149997457861900e-03 + + -4.3567001819610596e-02 -1.1094470024108887e+00 + <_> + + 0 -1 1532 9.4311997294425964e-02 + + 4.0256999433040619e-02 9.8442298173904419e-01 + <_> + + 0 -1 1533 1.7025099694728851e-01 + + 2.9510000720620155e-02 -6.9509297609329224e-01 + <_> + + 0 -1 1534 -4.7148000448942184e-02 + + 1.0338569879531860e+00 6.7602001130580902e-02 + <_> + + 0 -1 1535 1.1186300218105316e-01 + + -6.8682998418807983e-02 -2.4985830783843994e+00 + <_> + + 0 -1 1536 -1.4353999868035316e-02 + + -5.9481900930404663e-01 1.5001699328422546e-01 + <_> + + 0 -1 1537 3.4024000167846680e-02 + + -6.4823001623153687e-02 -2.1382639408111572e+00 + <_> + + 0 -1 1538 2.1601999178528786e-02 + + 5.5309999734163284e-02 7.8292900323867798e-01 + <_> + + 0 -1 1539 2.1771999076008797e-02 + + -7.1279997937381268e-03 -7.2148102521896362e-01 + <_> + + 0 -1 1540 8.2416996359825134e-02 + + 1.4609499275684357e-01 -1.3636670112609863e+00 + <_> + + 0 -1 1541 8.4671996533870697e-02 + + -1.7784699797630310e-01 7.2857701778411865e-01 + <_> + + 0 -1 1542 -5.5128000676631927e-02 + + -5.9402400255203247e-01 1.9357800483703613e-01 + <_> + + 0 -1 1543 -6.4823001623153687e-02 + + -1.0783840417861938e+00 -4.0734000504016876e-02 + <_> + + 0 -1 1544 -2.2769000381231308e-02 + + 7.7900201082229614e-01 3.4960000775754452e-03 + <_> + + 0 -1 1545 5.4756000638008118e-02 + + -6.5683998167514801e-02 -1.8188409805297852e+00 + <_> + + 0 -1 1546 -8.9000001025851816e-05 + + -1.7891999334096909e-02 2.0768299698829651e-01 + <_> + + 0 -1 1547 9.8361998796463013e-02 + + -5.5946998298168182e-02 -1.4153920412063599e+00 + <_> + + 0 -1 1548 -7.0930002257227898e-03 + + 3.4135299921035767e-01 -1.2089899927377701e-01 + <_> + + 0 -1 1549 5.0278000533580780e-02 + + -2.6286700367927551e-01 2.5797298550605774e-01 + <_> + + 0 -1 1550 -5.7870000600814819e-03 + + -1.3178600370883942e-01 1.7350199818611145e-01 + <_> + + 0 -1 1551 1.3973999768495560e-02 + + 2.8518000617623329e-02 -6.1152201890945435e-01 + <_> + + 0 -1 1552 2.1449999883770943e-02 + + 2.6181999593973160e-02 3.0306598544120789e-01 + <_> + + 0 -1 1553 -2.9214000329375267e-02 + + 4.4940599799156189e-01 -2.2803099453449249e-01 + <_> + + 0 -1 1554 4.8099999548867345e-04 + + -1.9879999756813049e-01 2.0744499564170837e-01 + <_> + + 0 -1 1555 1.7109999898821115e-03 + + -5.4037201404571533e-01 6.7865997552871704e-02 + <_> + + 0 -1 1556 8.6660003289580345e-03 + + -1.3128000311553478e-02 5.2297902107238770e-01 + <_> + + 0 -1 1557 6.3657999038696289e-02 + + 6.8299002945423126e-02 -4.9235099554061890e-01 + <_> + + 0 -1 1558 -2.7968000620603561e-02 + + 6.8183898925781250e-01 7.8781001269817352e-02 + <_> + + 0 -1 1559 4.8953998833894730e-02 + + -2.0622399449348450e-01 5.0388097763061523e-01 + <_> + 169 + -3.2396929264068604e+00 + + <_> + + 0 -1 1560 -2.9312999919056892e-02 + + 7.1284699440002441e-01 -5.8230698108673096e-01 + <_> + + 0 -1 1561 1.2415099889039993e-01 + + -3.6863499879837036e-01 6.0067200660705566e-01 + <_> + + 0 -1 1562 7.9349996522068977e-03 + + -8.6008298397064209e-01 2.1724699437618256e-01 + <_> + + 0 -1 1563 3.0365999788045883e-02 + + -2.7186998724937439e-01 6.1247897148132324e-01 + <_> + + 0 -1 1564 2.5218000635504723e-02 + + -3.4748300909996033e-01 5.0427699089050293e-01 + <_> + + 0 -1 1565 1.0014000348746777e-02 + + -3.1898999214172363e-01 4.1376799345016479e-01 + <_> + + 0 -1 1566 -1.6775000840425491e-02 + + -6.9048100709915161e-01 9.4830997288227081e-02 + <_> + + 0 -1 1567 -2.6950000319629908e-03 + + -2.0829799771308899e-01 2.3737199604511261e-01 + <_> + + 0 -1 1568 4.2257998138666153e-02 + + -4.9366700649261475e-01 1.8170599639415741e-01 + <_> + + 0 -1 1569 -4.8505000770092010e-02 + + 1.3429640531539917e+00 3.9769001305103302e-02 + <_> + + 0 -1 1570 2.8992999345064163e-02 + + 4.6496000140905380e-02 -8.1643497943878174e-01 + <_> + + 0 -1 1571 -4.0089000016450882e-02 + + -7.1197801828384399e-01 2.2553899884223938e-01 + <_> + + 0 -1 1572 -4.1021998971700668e-02 + + 1.0057929754257202e+00 -1.9690200686454773e-01 + <_> + + 0 -1 1573 1.1838000267744064e-02 + + -1.2600000016391277e-02 8.0767101049423218e-01 + <_> + + 0 -1 1574 -2.1328000351786613e-02 + + -8.2023900747299194e-01 2.0524999126791954e-02 + <_> + + 0 -1 1575 -2.3904999718070030e-02 + + 5.4210501909255981e-01 -7.4767000973224640e-02 + <_> + + 0 -1 1576 1.8008999526500702e-02 + + -3.3827701210975647e-01 4.2358601093292236e-01 + <_> + + 0 -1 1577 -4.3614000082015991e-02 + + -1.1983489990234375e+00 1.5566200017929077e-01 + <_> + + 0 -1 1578 -9.2449998483061790e-03 + + -8.9029997587203979e-01 1.1003999970853329e-02 + <_> + + 0 -1 1579 4.7485001385211945e-02 + + 1.6664099693298340e-01 -9.0764498710632324e-01 + <_> + + 0 -1 1580 -1.4233999885618687e-02 + + 6.2695199251174927e-01 -2.5791200995445251e-01 + <_> + + 0 -1 1581 3.8010000716894865e-03 + + -2.8229999542236328e-01 2.6624599099159241e-01 + <_> + + 0 -1 1582 3.4330000635236502e-03 + + -6.3771998882293701e-01 9.8422996699810028e-02 + <_> + + 0 -1 1583 -2.9221000149846077e-02 + + -7.6769900321960449e-01 2.2634500265121460e-01 + <_> + + 0 -1 1584 -6.4949998632073402e-03 + + 4.5600101351737976e-01 -2.6528900861740112e-01 + <_> + + 0 -1 1585 -3.0034000054001808e-02 + + -7.6551097631454468e-01 1.4009299874305725e-01 + <_> + + 0 -1 1586 7.8360000625252724e-03 + + 4.6755999326705933e-02 -7.2356200218200684e-01 + <_> + + 0 -1 1587 8.8550001382827759e-03 + + -4.9141999334096909e-02 5.1472699642181396e-01 + <_> + + 0 -1 1588 9.5973998308181763e-02 + + -2.0068999379873276e-02 -1.0850950479507446e+00 + <_> + + 0 -1 1589 -3.2876998186111450e-02 + + -9.5875298976898193e-01 1.4543600380420685e-01 + <_> + + 0 -1 1590 -1.3384000398218632e-02 + + -7.0013600587844849e-01 2.9157999902963638e-02 + <_> + + 0 -1 1591 1.5235999599099159e-02 + + -2.8235700726509094e-01 2.5367999076843262e-01 + <_> + + 0 -1 1592 1.2054000049829483e-02 + + -2.5303399562835693e-01 4.6526700258255005e-01 + <_> + + 0 -1 1593 -7.6295003294944763e-02 + + -6.9915801286697388e-01 1.3217200338840485e-01 + <_> + + 0 -1 1594 -1.2040000408887863e-02 + + 4.5894598960876465e-01 -2.3856499791145325e-01 + <_> + + 0 -1 1595 2.1916000172495842e-02 + + 1.8268600106239319e-01 -6.1629700660705566e-01 + <_> + + 0 -1 1596 -2.7330000884830952e-03 + + -6.3257902860641479e-01 3.4219000488519669e-02 + <_> + + 0 -1 1597 -4.8652000725269318e-02 + + -1.0297729969024658e+00 1.7386500537395477e-01 + <_> + + 0 -1 1598 -1.0463999584317207e-02 + + 3.4757301211357117e-01 -2.7464100718498230e-01 + <_> + + 0 -1 1599 -6.6550001502037048e-03 + + -2.8980299830436707e-01 2.4037900567054749e-01 + <_> + + 0 -1 1600 8.5469996556639671e-03 + + -4.4340500235557556e-01 1.4267399907112122e-01 + <_> + + 0 -1 1601 1.9913999363780022e-02 + + 1.7740400135517120e-01 -2.4096299707889557e-01 + <_> + + 0 -1 1602 2.2012999281287193e-02 + + -1.0812000371515751e-02 -9.4690799713134766e-01 + <_> + + 0 -1 1603 -5.2179001271724701e-02 + + 1.6547499895095825e+00 9.6487000584602356e-02 + <_> + + 0 -1 1604 1.9698999822139740e-02 + + -6.7560002207756042e-03 -8.6311501264572144e-01 + <_> + + 0 -1 1605 2.3040000349283218e-02 + + -2.3519999813288450e-03 3.8531300425529480e-01 + <_> + + 0 -1 1606 -1.5038000419735909e-02 + + -6.1905699968338013e-01 3.1077999621629715e-02 + <_> + + 0 -1 1607 -4.9956001341342926e-02 + + 7.0657497644424438e-01 4.7880999743938446e-02 + <_> + + 0 -1 1608 -6.9269999861717224e-02 + + 3.9212900400161743e-01 -2.3848000168800354e-01 + <_> + + 0 -1 1609 4.7399997711181641e-03 + + -2.4309000000357628e-02 2.5386300683021545e-01 + <_> + + 0 -1 1610 -3.3923998475074768e-02 + + 4.6930399537086487e-01 -2.3321899771690369e-01 + <_> + + 0 -1 1611 -1.6231000423431396e-02 + + 3.2319200038909912e-01 -2.0545600354671478e-01 + <_> + + 0 -1 1612 -5.0193000584840775e-02 + + -1.2277870178222656e+00 -4.0798000991344452e-02 + <_> + + 0 -1 1613 5.6944001466035843e-02 + + 4.5184001326560974e-02 6.0197502374649048e-01 + <_> + + 0 -1 1614 4.0936999022960663e-02 + + -1.6772800683975220e-01 8.9819300174713135e-01 + <_> + + 0 -1 1615 -3.0839999672025442e-03 + + 3.3716198801994324e-01 -2.7240800857543945e-01 + <_> + + 0 -1 1616 -3.2600000500679016e-02 + + -8.5446500778198242e-01 1.9664999097585678e-02 + <_> + + 0 -1 1617 9.8480999469757080e-02 + + 5.4742000997066498e-02 6.3827300071716309e-01 + <_> + + 0 -1 1618 -3.8185000419616699e-02 + + 5.2274698019027710e-01 -2.3384800553321838e-01 + <_> + + 0 -1 1619 -4.5917000621557236e-02 + + 6.2829202413558960e-01 3.2859001308679581e-02 + <_> + + 0 -1 1620 -1.1955499649047852e-01 + + -6.1572700738906860e-01 3.4680001437664032e-02 + <_> + + 0 -1 1621 -1.2044399976730347e-01 + + -8.4380000829696655e-01 1.6530700027942657e-01 + <_> + + 0 -1 1622 7.0619001984596252e-02 + + -6.3261002302169800e-02 -1.9863929748535156e+00 + <_> + + 0 -1 1623 8.4889996796846390e-03 + + -1.7663399875164032e-01 3.8011199235916138e-01 + <_> + + 0 -1 1624 2.2710999473929405e-02 + + -2.7605999261140823e-02 -9.1921401023864746e-01 + <_> + + 0 -1 1625 4.9700000090524554e-04 + + -2.4293200671672821e-01 2.2878900170326233e-01 + <_> + + 0 -1 1626 3.4651998430490494e-02 + + -2.3705999553203583e-01 5.4010999202728271e-01 + <_> + + 0 -1 1627 -4.4700000435113907e-03 + + 3.9078998565673828e-01 -1.2693800032138824e-01 + <_> + + 0 -1 1628 2.3643000051379204e-02 + + -2.6663699746131897e-01 3.2312598824501038e-01 + <_> + + 0 -1 1629 1.2813000008463860e-02 + + 1.7540800571441650e-01 -6.0787999629974365e-01 + <_> + + 0 -1 1630 -1.1250999756157398e-02 + + -1.0852589607238770e+00 -2.8046000748872757e-02 + <_> + + 0 -1 1631 -4.1535001248121262e-02 + + 7.1887397766113281e-01 2.7982000261545181e-02 + <_> + + 0 -1 1632 -9.3470998108386993e-02 + + -1.1906319856643677e+00 -4.4810999184846878e-02 + <_> + + 0 -1 1633 -2.7249999344348907e-02 + + 6.2942498922348022e-01 9.5039997249841690e-03 + <_> + + 0 -1 1634 -2.1759999915957451e-02 + + 1.3233649730682373e+00 -1.5027000010013580e-01 + <_> + + 0 -1 1635 -9.6890004351735115e-03 + + -3.3947101235389709e-01 1.7085799574851990e-01 + <_> + + 0 -1 1636 6.9395996630191803e-02 + + -2.5657799839973450e-01 4.7652098536491394e-01 + <_> + + 0 -1 1637 3.1208999454975128e-02 + + 1.4154000580310822e-01 -3.4942001104354858e-01 + <_> + + 0 -1 1638 -4.9727000296115875e-02 + + -1.1675560474395752e+00 -4.0757998824119568e-02 + <_> + + 0 -1 1639 -2.0301999524235725e-02 + + -3.9486399292945862e-01 1.5814900398254395e-01 + <_> + + 0 -1 1640 -1.5367000363767147e-02 + + 4.9300000071525574e-01 -2.0092099905014038e-01 + <_> + + 0 -1 1641 -5.0735000520944595e-02 + + 1.8736059665679932e+00 8.6730003356933594e-02 + <_> + + 0 -1 1642 -2.0726000890135765e-02 + + -8.8938397169113159e-01 -7.3199998587369919e-03 + <_> + + 0 -1 1643 -3.0993999913334846e-02 + + -1.1664899587631226e+00 1.4274600148200989e-01 + <_> + + 0 -1 1644 -4.4269999489188194e-03 + + -6.6815102100372314e-01 4.4120000675320625e-03 + <_> + + 0 -1 1645 -4.5743998140096664e-02 + + -4.7955200076103210e-01 1.5121999382972717e-01 + <_> + + 0 -1 1646 1.6698999330401421e-02 + + 1.2048599869012833e-01 -4.5235899090766907e-01 + <_> + + 0 -1 1647 3.2210000790655613e-03 + + -7.7615000307559967e-02 2.7846598625183105e-01 + <_> + + 0 -1 1648 2.4434000253677368e-02 + + -1.9987100362777710e-01 6.7253702878952026e-01 + <_> + + 0 -1 1649 -7.9677999019622803e-02 + + 9.2222398519515991e-01 9.2557996511459351e-02 + <_> + + 0 -1 1650 4.4530000537633896e-02 + + -2.6690500974655151e-01 3.3320501446723938e-01 + <_> + + 0 -1 1651 -1.2528300285339355e-01 + + -5.4253101348876953e-01 1.3976299762725830e-01 + <_> + + 0 -1 1652 1.7971999943256378e-02 + + 1.8219999969005585e-02 -6.8048501014709473e-01 + <_> + + 0 -1 1653 1.9184000790119171e-02 + + -1.2583999894559383e-02 5.4126697778701782e-01 + <_> + + 0 -1 1654 4.0024001151323318e-02 + + -1.7638799548149109e-01 7.8810399770736694e-01 + <_> + + 0 -1 1655 1.3558999635279179e-02 + + 2.0737600326538086e-01 -4.7744300961494446e-01 + <_> + + 0 -1 1656 1.6220999881625175e-02 + + 2.3076999932527542e-02 -6.1182099580764771e-01 + <_> + + 0 -1 1657 1.1229000054299831e-02 + + -1.7728000879287720e-02 4.1764199733734131e-01 + <_> + + 0 -1 1658 3.9193000644445419e-02 + + -1.8948499858379364e-01 7.4019300937652588e-01 + <_> + + 0 -1 1659 -9.5539996400475502e-03 + + 4.0947100520133972e-01 -1.3508899509906769e-01 + <_> + + 0 -1 1660 2.7878999710083008e-02 + + -2.0350700616836548e-01 6.1625397205352783e-01 + <_> + + 0 -1 1661 -2.3600999265909195e-02 + + -1.6967060565948486e+00 1.4633199572563171e-01 + <_> + + 0 -1 1662 2.6930000633001328e-02 + + -3.0401999130845070e-02 -1.0909470319747925e+00 + <_> + + 0 -1 1663 2.8999999631196260e-04 + + -2.0076000690460205e-01 2.2314099967479706e-01 + <_> + + 0 -1 1664 -4.1124999523162842e-02 + + -4.5242199301719666e-01 5.7392001152038574e-02 + <_> + + 0 -1 1665 6.6789998672902584e-03 + + 2.3824900388717651e-01 -2.1262100338935852e-01 + <_> + + 0 -1 1666 4.7864999622106552e-02 + + -1.8194800615310669e-01 6.1918401718139648e-01 + <_> + + 0 -1 1667 -3.1679999083280563e-03 + + -2.7393200993537903e-01 2.5017300248146057e-01 + <_> + + 0 -1 1668 -8.6230002343654633e-03 + + -4.6280300617218018e-01 4.2397998273372650e-02 + <_> + + 0 -1 1669 -7.4350000359117985e-03 + + 4.1796800494194031e-01 -1.7079999670386314e-03 + <_> + + 0 -1 1670 -1.8769999733194709e-03 + + 1.4602300524711609e-01 -3.3721101284027100e-01 + <_> + + 0 -1 1671 -8.6226001381874084e-02 + + 7.5143402814865112e-01 1.0711999610066414e-02 + <_> + + 0 -1 1672 4.6833999454975128e-02 + + -1.9119599461555481e-01 4.8414900898933411e-01 + <_> + + 0 -1 1673 -9.2000002041459084e-05 + + 3.5220399498939514e-01 -1.7333300411701202e-01 + <_> + + 0 -1 1674 -1.6343999654054642e-02 + + -6.4397698640823364e-01 9.0680001303553581e-03 + <_> + + 0 -1 1675 4.5703999698162079e-02 + + 1.8216000869870186e-02 3.1970798969268799e-01 + <_> + + 0 -1 1676 -2.7382999658584595e-02 + + 1.0564049482345581e+00 -1.7276400327682495e-01 + <_> + + 0 -1 1677 -2.7602000162005424e-02 + + 2.9715499281883240e-01 -9.4600003212690353e-03 + <_> + + 0 -1 1678 7.6939999125897884e-03 + + -2.1660299599170685e-01 4.7385200858116150e-01 + <_> + + 0 -1 1679 -7.0500001311302185e-04 + + 2.4048799276351929e-01 -2.6776000857353210e-01 + <_> + + 0 -1 1680 1.1054199934005737e-01 + + -3.3539000898599625e-02 -1.0233880281448364e+00 + <_> + + 0 -1 1681 6.8765997886657715e-02 + + -4.3239998631179333e-03 5.7153397798538208e-01 + <_> + + 0 -1 1682 1.7999999690800905e-03 + + 7.7574998140335083e-02 -4.2092698812484741e-01 + <_> + + 0 -1 1683 1.9232000410556793e-01 + + 8.2021996378898621e-02 2.8810169696807861e+00 + <_> + + 0 -1 1684 1.5742099285125732e-01 + + -1.3708199560642242e-01 2.0890059471130371e+00 + <_> + + 0 -1 1685 -4.9387000501155853e-02 + + -1.8610910177230835e+00 1.4332099258899689e-01 + <_> + + 0 -1 1686 5.1929000765085220e-02 + + -1.8737000226974487e-01 5.4231601953506470e-01 + <_> + + 0 -1 1687 4.9965001642704010e-02 + + 1.4175300300121307e-01 -1.5625779628753662e+00 + <_> + + 0 -1 1688 -4.2633000761270523e-02 + + 1.6059479713439941e+00 -1.4712899923324585e-01 + <_> + + 0 -1 1689 -3.7553999572992325e-02 + + -8.0974900722503662e-01 1.3256999850273132e-01 + <_> + + 0 -1 1690 -3.7174999713897705e-02 + + -1.3945020437240601e+00 -5.7055000215768814e-02 + <_> + + 0 -1 1691 1.3945999555289745e-02 + + 3.3427000045776367e-02 5.7474797964096069e-01 + <_> + + 0 -1 1692 -4.4800000614486635e-04 + + -5.5327498912811279e-01 2.1952999755740166e-02 + <_> + + 0 -1 1693 3.1993001699447632e-02 + + 2.0340999588370323e-02 3.7459200620651245e-01 + <_> + + 0 -1 1694 -4.2799999937415123e-03 + + 4.4428700208663940e-01 -2.2999699413776398e-01 + <_> + + 0 -1 1695 9.8550003021955490e-03 + + 1.8315799534320831e-01 -4.0964999794960022e-01 + <_> + + 0 -1 1696 9.3356996774673462e-02 + + -6.3661001622676849e-02 -1.6929290294647217e+00 + <_> + + 0 -1 1697 1.7209999263286591e-02 + + 2.0153899490833282e-01 -4.6061098575592041e-01 + <_> + + 0 -1 1698 8.4319999441504478e-03 + + -3.2003998756408691e-01 1.5312199294567108e-01 + <_> + + 0 -1 1699 -1.4054999686777592e-02 + + 8.6882400512695312e-01 3.2575000077486038e-02 + <_> + + 0 -1 1700 -7.7180000953376293e-03 + + 6.3686698675155640e-01 -1.8425500392913818e-01 + <_> + + 0 -1 1701 2.8005000203847885e-02 + + 1.7357499897480011e-01 -4.7883599996566772e-01 + <_> + + 0 -1 1702 -1.8884999677538872e-02 + + 2.4101600050926208e-01 -2.6547598838806152e-01 + <_> + + 0 -1 1703 -1.8585000187158585e-02 + + 5.4232501983642578e-01 5.3633000701665878e-02 + <_> + + 0 -1 1704 -3.6437001079320908e-02 + + 2.3908898830413818e+00 -1.3634699583053589e-01 + <_> + + 0 -1 1705 3.2455001026391983e-02 + + 1.5910699963569641e-01 -6.7581498622894287e-01 + <_> + + 0 -1 1706 5.9781998395919800e-02 + + -2.3479999508708715e-03 -7.3053699731826782e-01 + <_> + + 0 -1 1707 9.8209995776414871e-03 + + -1.1444099992513657e-01 3.0570301413536072e-01 + <_> + + 0 -1 1708 -3.5163998603820801e-02 + + -1.0511469841003418e+00 -3.3103000372648239e-02 + <_> + + 0 -1 1709 2.7429999317973852e-03 + + -2.0135399699211121e-01 3.2754099369049072e-01 + <_> + + 0 -1 1710 8.1059997901320457e-03 + + -2.1383500099182129e-01 4.3362098932266235e-01 + <_> + + 0 -1 1711 8.8942997157573700e-02 + + 1.0940899699926376e-01 -4.7609338760375977e+00 + <_> + + 0 -1 1712 -3.0054999515414238e-02 + + -1.7169300317764282e+00 -6.0919001698493958e-02 + <_> + + 0 -1 1713 -2.1734999492764473e-02 + + 6.4778900146484375e-01 -3.2830998301506042e-02 + <_> + + 0 -1 1714 3.7648998200893402e-02 + + -1.0060000233352184e-02 -7.6569098234176636e-01 + <_> + + 0 -1 1715 2.7189999818801880e-03 + + 1.9888900220394135e-01 -8.2479000091552734e-02 + <_> + + 0 -1 1716 -1.0548000223934650e-02 + + -8.6613601446151733e-01 -2.5986000895500183e-02 + <_> + + 0 -1 1717 1.2966300547122955e-01 + + 1.3911999762058258e-01 -2.2271950244903564e+00 + <_> + + 0 -1 1718 -1.7676999792456627e-02 + + 3.3967700600624084e-01 -2.3989599943161011e-01 + <_> + + 0 -1 1719 -7.7051997184753418e-02 + + -2.5017969608306885e+00 1.2841999530792236e-01 + <_> + + 0 -1 1720 -1.9230000674724579e-02 + + 5.0641202926635742e-01 -1.9751599431037903e-01 + <_> + + 0 -1 1721 -5.1222998648881912e-02 + + -2.9333369731903076e+00 1.3858500123023987e-01 + <_> + + 0 -1 1722 2.0830000285059214e-03 + + -6.0043597221374512e-01 2.9718000441789627e-02 + <_> + + 0 -1 1723 2.5418000295758247e-02 + + 3.3915799856185913e-01 -1.4392000436782837e-01 + <_> + + 0 -1 1724 -2.3905999958515167e-02 + + -1.1082680225372314e+00 -4.7377001494169235e-02 + <_> + + 0 -1 1725 -6.3740001060068607e-03 + + 4.4533699750900269e-01 -6.7052997648715973e-02 + <_> + + 0 -1 1726 -3.7698999047279358e-02 + + -1.0406579971313477e+00 -4.1790001094341278e-02 + <_> + + 0 -1 1727 2.1655100584030151e-01 + + 3.3863000571727753e-02 8.2017302513122559e-01 + <_> + + 0 -1 1728 -1.3400999829173088e-02 + + 5.2903497219085693e-01 -1.9133000075817108e-01 + <_> + 196 + -3.2103500366210938e+00 + + <_> + + 0 -1 1729 7.1268998086452484e-02 + + -5.3631198406219482e-01 6.0715299844741821e-01 + <_> + + 0 -1 1730 5.6111000478267670e-02 + + -5.0141602754592896e-01 4.3976101279258728e-01 + <_> + + 0 -1 1731 4.0463998913764954e-02 + + -3.2922199368476868e-01 5.4834699630737305e-01 + <_> + + 0 -1 1732 6.3155002892017365e-02 + + -3.1701698899269104e-01 4.6152999997138977e-01 + <_> + + 0 -1 1733 1.0320999659597874e-02 + + 1.0694999992847443e-01 -9.8243898153305054e-01 + <_> + + 0 -1 1734 6.2606997787952423e-02 + + -1.4329700171947479e-01 7.1095001697540283e-01 + <_> + + 0 -1 1735 -3.9416000247001648e-02 + + 9.4380199909210205e-01 -2.1572099626064301e-01 + <_> + + 0 -1 1736 -5.3960001096129417e-03 + + -5.4611998796463013e-01 2.5303798913955688e-01 + <_> + + 0 -1 1737 1.0773199796676636e-01 + + 1.2496000155806541e-02 -1.0809199810028076e+00 + <_> + + 0 -1 1738 1.6982000321149826e-02 + + -3.1536400318145752e-01 5.1239997148513794e-01 + <_> + + 0 -1 1739 3.1216999515891075e-02 + + -4.5199999585747719e-03 -1.2443480491638184e+00 + <_> + + 0 -1 1740 -2.3106999695301056e-02 + + -7.6492899656295776e-01 2.0640599727630615e-01 + <_> + + 0 -1 1741 -1.1203999631106853e-02 + + 2.4092699587345123e-01 -3.5142099857330322e-01 + <_> + + 0 -1 1742 -4.7479998320341110e-03 + + -9.7007997334003448e-02 2.0638099312782288e-01 + <_> + + 0 -1 1743 -1.7358999699354172e-02 + + -7.9020297527313232e-01 2.1852999925613403e-02 + <_> + + 0 -1 1744 1.8851999193429947e-02 + + -1.0394600033760071e-01 5.4844200611114502e-01 + <_> + + 0 -1 1745 7.2249998338520527e-03 + + -4.0409401059150696e-01 2.6763799786567688e-01 + <_> + + 0 -1 1746 1.8915999680757523e-02 + + 2.0508000254631042e-01 -1.0206340551376343e+00 + <_> + + 0 -1 1747 3.1156999990344048e-02 + + 1.2400000123307109e-03 -8.7293499708175659e-01 + <_> + + 0 -1 1748 2.0951999351382256e-02 + + -5.5559999309480190e-03 8.0356198549270630e-01 + <_> + + 0 -1 1749 1.1291000060737133e-02 + + -3.6478400230407715e-01 2.2767899930477142e-01 + <_> + + 0 -1 1750 -5.7011000812053680e-02 + + -1.4295619726181030e+00 1.4322000741958618e-01 + <_> + + 0 -1 1751 7.2194002568721771e-02 + + -4.1850000619888306e-02 -1.9111829996109009e+00 + <_> + + 0 -1 1752 -1.9874000921845436e-02 + + 2.6425498723983765e-01 -3.2617700099945068e-01 + <_> + + 0 -1 1753 -1.6692999750375748e-02 + + -8.3907800912857056e-01 4.0799999260343611e-04 + <_> + + 0 -1 1754 -3.9834998548030853e-02 + + -4.8858499526977539e-01 1.6436100006103516e-01 + <_> + + 0 -1 1755 2.7009999379515648e-02 + + -1.8862499296665192e-01 8.3419400453567505e-01 + <_> + + 0 -1 1756 -3.9420002140104771e-03 + + 2.3231500387191772e-01 -7.2360001504421234e-02 + <_> + + 0 -1 1757 2.2833000868558884e-02 + + -3.5884000360965729e-02 -1.1549400091171265e+00 + <_> + + 0 -1 1758 -6.8888001143932343e-02 + + -1.7837309837341309e+00 1.5159000456333160e-01 + <_> + + 0 -1 1759 4.3097000569105148e-02 + + -2.1608099341392517e-01 5.0624102354049683e-01 + <_> + + 0 -1 1760 8.6239995434880257e-03 + + -1.7795599997043610e-01 2.8957900404930115e-01 + <_> + + 0 -1 1761 1.4561000280082226e-02 + + -1.1408000253140926e-02 -8.9402002096176147e-01 + <_> + + 0 -1 1762 -1.1501000262796879e-02 + + 3.0171999335289001e-01 -4.3659001588821411e-02 + <_> + + 0 -1 1763 -1.0971499979496002e-01 + + -9.5147097110748291e-01 -1.9973000511527061e-02 + <_> + + 0 -1 1764 4.5228000730276108e-02 + + 3.3110998570919037e-02 9.6619802713394165e-01 + <_> + + 0 -1 1765 -2.7047999203205109e-02 + + 9.7963601350784302e-01 -1.7261900007724762e-01 + <_> + + 0 -1 1766 1.8030999228358269e-02 + + -2.0801000297069550e-02 2.7385899424552917e-01 + <_> + + 0 -1 1767 5.0524998456239700e-02 + + -5.6802999228239059e-02 -1.7775089740753174e+00 + <_> + + 0 -1 1768 -2.9923999682068825e-02 + + 6.5329200029373169e-01 -2.3537000641226768e-02 + <_> + + 0 -1 1769 3.8058001548051834e-02 + + 2.6317000389099121e-02 -7.0665699243545532e-01 + <_> + + 0 -1 1770 1.8563899397850037e-01 + + -5.6039998307824135e-03 3.2873699069023132e-01 + <_> + + 0 -1 1771 -4.0670000016689301e-03 + + 3.4204798936843872e-01 -3.0171599984169006e-01 + <_> + + 0 -1 1772 1.0108999907970428e-02 + + -7.3600001633167267e-03 5.7981598377227783e-01 + <_> + + 0 -1 1773 -1.1567000299692154e-02 + + -5.2722197771072388e-01 4.6447999775409698e-02 + <_> + + 0 -1 1774 -6.5649999305605888e-03 + + -5.8529102802276611e-01 1.9101899862289429e-01 + <_> + + 0 -1 1775 1.0582000017166138e-02 + + 2.1073000505566597e-02 -6.8892598152160645e-01 + <_> + + 0 -1 1776 -2.0304000005125999e-02 + + -3.6400699615478516e-01 1.5338799357414246e-01 + <_> + + 0 -1 1777 2.3529999889433384e-03 + + 3.6164000630378723e-02 -5.9825098514556885e-01 + <_> + + 0 -1 1778 -1.4690000098198652e-03 + + -1.4707699418067932e-01 3.7507998943328857e-01 + <_> + + 0 -1 1779 8.6449999362230301e-03 + + -2.1708500385284424e-01 5.1936799287796021e-01 + <_> + + 0 -1 1780 -2.4326000362634659e-02 + + -1.0846769809722900e+00 1.4084799587726593e-01 + <_> + + 0 -1 1781 7.4418999254703522e-02 + + -1.5513800084590912e-01 1.1822769641876221e+00 + <_> + + 0 -1 1782 1.7077999189496040e-02 + + 4.4231001287698746e-02 9.1561102867126465e-01 + <_> + + 0 -1 1783 -2.4577999487519264e-02 + + -1.5504100322723389e+00 -5.4745998233556747e-02 + <_> + + 0 -1 1784 3.0205000191926956e-02 + + 1.6662800312042236e-01 -1.0001239776611328e+00 + <_> + + 0 -1 1785 1.2136000208556652e-02 + + -7.7079099416732788e-01 -4.8639997839927673e-03 + <_> + + 0 -1 1786 8.6717002093791962e-02 + + 1.1061699688434601e-01 -1.6857999563217163e+00 + <_> + + 0 -1 1787 -4.2309001088142395e-02 + + 1.1075930595397949e+00 -1.5438599884510040e-01 + <_> + + 0 -1 1788 -2.6420000940561295e-03 + + 2.7451899647712708e-01 -1.8456199765205383e-01 + <_> + + 0 -1 1789 -5.6662000715732574e-02 + + -8.0625599622726440e-01 -1.6928000375628471e-02 + <_> + + 0 -1 1790 2.3475000634789467e-02 + + 1.4187699556350708e-01 -2.5500899553298950e-01 + <_> + + 0 -1 1791 -2.0803000777959824e-02 + + 1.9826300442218781e-01 -3.1171199679374695e-01 + <_> + + 0 -1 1792 7.2599998675286770e-03 + + -5.0590999424457550e-02 4.1923800110816956e-01 + <_> + + 0 -1 1793 3.4160000085830688e-01 + + -1.6674900054931641e-01 9.2748600244522095e-01 + <_> + + 0 -1 1794 6.2029999680817127e-03 + + -1.2625899910926819e-01 4.0445300936698914e-01 + <_> + + 0 -1 1795 3.2692000269889832e-02 + + -3.2634999603033066e-02 -9.8939800262451172e-01 + <_> + + 0 -1 1796 2.1100000594742596e-04 + + -6.4534001052379608e-02 2.5473698973655701e-01 + <_> + + 0 -1 1797 7.2100001852959394e-04 + + -3.6618599295616150e-01 1.1973100155591965e-01 + <_> + + 0 -1 1798 5.4490998387336731e-02 + + 1.2073499709367752e-01 -1.0291390419006348e+00 + <_> + + 0 -1 1799 -1.0141000151634216e-02 + + -5.2177202701568604e-01 3.3734999597072601e-02 + <_> + + 0 -1 1800 -1.8815999850630760e-02 + + 6.5181797742843628e-01 1.3399999588727951e-03 + <_> + + 0 -1 1801 -5.3480002097785473e-03 + + 1.7370699346065521e-01 -3.4132000803947449e-01 + <_> + + 0 -1 1802 -1.0847000405192375e-02 + + -1.9699899852275848e-01 1.5045499801635742e-01 + <_> + + 0 -1 1803 -4.9926001578569412e-02 + + -5.0888502597808838e-01 3.0762000009417534e-02 + <_> + + 0 -1 1804 1.2160000391304493e-02 + + -6.9251999258995056e-02 1.8745499849319458e-01 + <_> + + 0 -1 1805 -2.2189998999238014e-03 + + -4.0849098563194275e-01 7.9954996705055237e-02 + <_> + + 0 -1 1806 3.1580000650137663e-03 + + -2.1124599874019623e-01 2.2366400063037872e-01 + <_> + + 0 -1 1807 4.1439998894929886e-03 + + -4.9900299310684204e-01 6.2917001545429230e-02 + <_> + + 0 -1 1808 -7.3730000294744968e-03 + + -2.0553299784660339e-01 2.2096699476242065e-01 + <_> + + 0 -1 1809 5.1812000572681427e-02 + + 1.8096800148487091e-01 -4.3495801091194153e-01 + <_> + + 0 -1 1810 1.8340000882744789e-02 + + 1.5200000256299973e-02 3.7991699576377869e-01 + <_> + + 0 -1 1811 1.7490799725055695e-01 + + -2.0920799672603607e-01 4.0013000369071960e-01 + <_> + + 0 -1 1812 5.3993999958038330e-02 + + 2.4751600623130798e-01 -2.6712900400161743e-01 + <_> + + 0 -1 1813 -3.2033199071884155e-01 + + -1.9094380140304565e+00 -6.6960997879505157e-02 + <_> + + 0 -1 1814 -2.7060000225901604e-02 + + -7.1371299028396606e-01 1.5904599428176880e-01 + <_> + + 0 -1 1815 7.7463999390602112e-02 + + -1.6970199346542358e-01 7.7552998065948486e-01 + <_> + + 0 -1 1816 2.3771999403834343e-02 + + 1.9021899998188019e-01 -6.0162097215652466e-01 + <_> + + 0 -1 1817 1.1501000262796879e-02 + + 7.7039999887347221e-03 -6.1730301380157471e-01 + <_> + + 0 -1 1818 3.2616000622510910e-02 + + 1.7159199714660645e-01 -7.0978200435638428e-01 + <_> + + 0 -1 1819 -4.4383000582456589e-02 + + -2.2606229782104492e+00 -7.3276996612548828e-02 + <_> + + 0 -1 1820 -5.8476001024246216e-02 + + 2.4087750911712646e+00 8.3091996610164642e-02 + <_> + + 0 -1 1821 1.9303999841213226e-02 + + -2.7082300186157227e-01 2.7369999885559082e-01 + <_> + + 0 -1 1822 -4.4705998152494431e-02 + + 3.1355598568916321e-01 -6.2492001801729202e-02 + <_> + + 0 -1 1823 -6.0334999114274979e-02 + + -1.4515119791030884e+00 -5.8761000633239746e-02 + <_> + + 0 -1 1824 1.1667000129818916e-02 + + -1.8084999173879623e-02 5.0479698181152344e-01 + <_> + + 0 -1 1825 2.8009999543428421e-02 + + -2.3302899301052094e-01 3.0708700418472290e-01 + <_> + + 0 -1 1826 6.5397001802921295e-02 + + 1.4135900139808655e-01 -5.0010901689529419e-01 + <_> + + 0 -1 1827 9.6239997074007988e-03 + + -2.2054600715637207e-01 3.9191201329231262e-01 + <_> + + 0 -1 1828 2.5510000996291637e-03 + + -1.1381500214338303e-01 2.0032300055027008e-01 + <_> + + 0 -1 1829 3.1847000122070312e-02 + + 2.5476999580860138e-02 -5.3326398134231567e-01 + <_> + + 0 -1 1830 3.3055000007152557e-02 + + 1.7807699739933014e-01 -6.2793898582458496e-01 + <_> + + 0 -1 1831 4.7600999474525452e-02 + + -1.4747899770736694e-01 1.4204180240631104e+00 + <_> + + 0 -1 1832 -1.9571999087929726e-02 + + -5.2693498134613037e-01 1.5838600695133209e-01 + <_> + + 0 -1 1833 -5.4730001837015152e-02 + + 8.8231599330902100e-01 -1.6627800464630127e-01 + <_> + + 0 -1 1834 -2.2686000913381577e-02 + + -4.8386898636817932e-01 1.5000100433826447e-01 + <_> + + 0 -1 1835 1.0713200271129608e-01 + + -2.1336199343204498e-01 4.2333900928497314e-01 + <_> + + 0 -1 1836 -3.6380000412464142e-02 + + -7.4198000133037567e-02 1.4589400589466095e-01 + <_> + + 0 -1 1837 1.3935999944806099e-02 + + -2.4911600351333618e-01 2.6771199703216553e-01 + <_> + + 0 -1 1838 2.0991999655961990e-02 + + 8.7959999218583107e-03 4.3064999580383301e-01 + <_> + + 0 -1 1839 4.9118999391794205e-02 + + -1.7591999471187592e-01 6.9282901287078857e-01 + <_> + + 0 -1 1840 3.6315999925136566e-02 + + 1.3145299255847931e-01 -3.3597299456596375e-01 + <_> + + 0 -1 1841 4.1228000074625015e-02 + + -4.5692000538110733e-02 -1.3515930175781250e+00 + <_> + + 0 -1 1842 1.5672000125050545e-02 + + 1.7544099688529968e-01 -6.0550000518560410e-02 + <_> + + 0 -1 1843 -1.6286000609397888e-02 + + -1.1308189630508423e+00 -3.9533000439405441e-02 + <_> + + 0 -1 1844 -3.0229999683797359e-03 + + -2.2454300522804260e-01 2.3628099262714386e-01 + <_> + + 0 -1 1845 -1.3786299526691437e-01 + + 4.5376899838447571e-01 -2.1098700165748596e-01 + <_> + + 0 -1 1846 -9.6760001033544540e-03 + + -1.5105099976062775e-01 2.0781700313091278e-01 + <_> + + 0 -1 1847 -2.4839999154210091e-02 + + -6.8350297212600708e-01 -8.0040004104375839e-03 + <_> + + 0 -1 1848 -1.3964399695396423e-01 + + 6.5011298656463623e-01 4.6544000506401062e-02 + <_> + + 0 -1 1849 -8.2153998315334320e-02 + + 4.4887199997901917e-01 -2.3591999709606171e-01 + <_> + + 0 -1 1850 3.8449999410659075e-03 + + -8.8173002004623413e-02 2.7346798777580261e-01 + <_> + + 0 -1 1851 -6.6579999402165413e-03 + + -4.6866598725318909e-01 7.7001996338367462e-02 + <_> + + 0 -1 1852 -1.5898000448942184e-02 + + 2.9268398880958557e-01 -2.1941000595688820e-02 + <_> + + 0 -1 1853 -5.0946000963449478e-02 + + -1.2093789577484131e+00 -4.2109999805688858e-02 + <_> + + 0 -1 1854 1.6837999224662781e-02 + + -4.5595999807119370e-02 5.0180697441101074e-01 + <_> + + 0 -1 1855 1.5918999910354614e-02 + + -2.6904299855232239e-01 2.6516300439834595e-01 + <_> + + 0 -1 1856 3.6309999413788319e-03 + + -1.3046100735664368e-01 3.1807100772857666e-01 + <_> + + 0 -1 1857 -8.6144998669624329e-02 + + 1.9443659782409668e+00 -1.3978299498558044e-01 + <_> + + 0 -1 1858 3.3140998333692551e-02 + + 1.5266799926757812e-01 -3.0866000801324844e-02 + <_> + + 0 -1 1859 -3.9679999463260174e-03 + + -7.1202301979064941e-01 -1.3844000175595284e-02 + <_> + + 0 -1 1860 -2.4008000269532204e-02 + + 9.2007797956466675e-01 4.6723999083042145e-02 + <_> + + 0 -1 1861 8.7320003658533096e-03 + + -2.2567300498485565e-01 3.1931799650192261e-01 + <_> + + 0 -1 1862 -2.7786999940872192e-02 + + -7.2337102890014648e-01 1.7018599808216095e-01 + <_> + + 0 -1 1863 -1.9455300271511078e-01 + + 1.2461860179901123e+00 -1.4736199378967285e-01 + <_> + + 0 -1 1864 -1.0869699716567993e-01 + + -1.4465179443359375e+00 1.2145300209522247e-01 + <_> + + 0 -1 1865 -1.9494999200105667e-02 + + -7.8153097629547119e-01 -2.3732999339699745e-02 + <_> + + 0 -1 1866 3.0650000553578138e-03 + + -8.5471397638320923e-01 1.6686999797821045e-01 + <_> + + 0 -1 1867 5.9193998575210571e-02 + + -1.4853699505329132e-01 1.1273469924926758e+00 + <_> + + 0 -1 1868 -5.4207999259233475e-02 + + 5.4726999998092651e-01 3.5523999482393265e-02 + <_> + + 0 -1 1869 -3.9324998855590820e-02 + + 3.6642599105834961e-01 -2.0543999969959259e-01 + <_> + + 0 -1 1870 8.2278996706008911e-02 + + -3.5007998347282410e-02 5.3994202613830566e-01 + <_> + + 0 -1 1871 -7.4479999020695686e-03 + + -6.1537498235702515e-01 -3.5319998860359192e-03 + <_> + + 0 -1 1872 7.3770000599324703e-03 + + -6.5591000020503998e-02 4.1961398720741272e-01 + <_> + + 0 -1 1873 7.0779998786747456e-03 + + -3.4129500389099121e-01 1.2536799907684326e-01 + <_> + + 0 -1 1874 -1.5581999905407429e-02 + + -3.0240398645401001e-01 2.1511000394821167e-01 + <_> + + 0 -1 1875 -2.7399999089539051e-03 + + 7.6553001999855042e-02 -4.1060501337051392e-01 + <_> + + 0 -1 1876 -7.0600003004074097e-02 + + -9.7356200218200684e-01 1.1241800338029861e-01 + <_> + + 0 -1 1877 -1.1706000193953514e-02 + + 1.8560700118541718e-01 -2.9755198955535889e-01 + <_> + + 0 -1 1878 7.1499997284263372e-04 + + -5.9650000184774399e-02 2.4824699759483337e-01 + <_> + + 0 -1 1879 -3.6866001784801483e-02 + + 3.2751700282096863e-01 -2.3059600591659546e-01 + <_> + + 0 -1 1880 -3.2526999711990356e-02 + + -2.9320299625396729e-01 1.5427699685096741e-01 + <_> + + 0 -1 1881 -7.4813999235630035e-02 + + -1.2143570184707642e+00 -5.2244000136852264e-02 + <_> + + 0 -1 1882 4.1469998657703400e-02 + + 1.3062499463558197e-01 -2.3274369239807129e+00 + <_> + + 0 -1 1883 -2.8880000114440918e-02 + + -6.6074597835540771e-01 -9.0960003435611725e-03 + <_> + + 0 -1 1884 4.6381998807191849e-02 + + 1.6630199551582336e-01 -6.6949498653411865e-01 + <_> + + 0 -1 1885 2.5424998998641968e-01 + + -5.4641999304294586e-02 -1.2676080465316772e+00 + <_> + + 0 -1 1886 2.4000001139938831e-03 + + 2.0276799798011780e-01 1.4667999930679798e-02 + <_> + + 0 -1 1887 -8.2805998623371124e-02 + + -7.8713601827621460e-01 -2.4468999356031418e-02 + <_> + + 0 -1 1888 -1.1438000015914440e-02 + + 2.8623399138450623e-01 -3.0894000083208084e-02 + <_> + + 0 -1 1889 -1.2913399934768677e-01 + + 1.7292929887771606e+00 -1.4293900132179260e-01 + <_> + + 0 -1 1890 3.8552999496459961e-02 + + 1.9232999533414841e-02 3.7732601165771484e-01 + <_> + + 0 -1 1891 1.0191400349140167e-01 + + -7.4533998966217041e-02 -3.3868899345397949e+00 + <_> + + 0 -1 1892 -1.9068000838160515e-02 + + 3.1814101338386536e-01 1.9261000677943230e-02 + <_> + + 0 -1 1893 -6.0775000602006912e-02 + + 7.6936298608779907e-01 -1.7644000053405762e-01 + <_> + + 0 -1 1894 2.4679999798536301e-02 + + 1.8396499752998352e-01 -3.0868801474571228e-01 + <_> + + 0 -1 1895 2.6759000495076180e-02 + + -2.3454900085926056e-01 3.3056598901748657e-01 + <_> + + 0 -1 1896 1.4969999901950359e-02 + + 1.7213599383831024e-01 -1.8248899281024933e-01 + <_> + + 0 -1 1897 2.6142999529838562e-02 + + -4.6463999897241592e-02 -1.1318379640579224e+00 + <_> + + 0 -1 1898 -3.7512000650167465e-02 + + 8.0404001474380493e-01 6.9660000503063202e-02 + <_> + + 0 -1 1899 -5.3229997865855694e-03 + + -8.1884402036666870e-01 -1.8224999308586121e-02 + <_> + + 0 -1 1900 1.7813000828027725e-02 + + 1.4957800507545471e-01 -1.8667200207710266e-01 + <_> + + 0 -1 1901 -3.4010000526905060e-02 + + -7.2852301597595215e-01 -1.6615999862551689e-02 + <_> + + 0 -1 1902 -1.5953000634908676e-02 + + 5.6944000720977783e-01 1.3832000084221363e-02 + <_> + + 0 -1 1903 1.9743999466300011e-02 + + 4.0525000542402267e-02 -4.1773399710655212e-01 + <_> + + 0 -1 1904 -1.0374800115823746e-01 + + -1.9825149774551392e+00 1.1960200220346451e-01 + <_> + + 0 -1 1905 -1.9285000860691071e-02 + + 5.0230598449707031e-01 -1.9745899736881256e-01 + <_> + + 0 -1 1906 -1.2780000455677509e-02 + + 4.0195000171661377e-01 -2.6957999914884567e-02 + <_> + + 0 -1 1907 -1.6352999955415726e-02 + + -7.6608800888061523e-01 -2.4209000170230865e-02 + <_> + + 0 -1 1908 -1.2763699889183044e-01 + + 8.6578500270843506e-01 6.4205996692180634e-02 + <_> + + 0 -1 1909 1.9068999215960503e-02 + + -5.5929797887802124e-01 -1.6880000475794077e-03 + <_> + + 0 -1 1910 3.2480999827384949e-02 + + 4.0722001343965530e-02 4.8925098776817322e-01 + <_> + + 0 -1 1911 9.4849998131394386e-03 + + -1.9231900572776794e-01 5.1139700412750244e-01 + <_> + + 0 -1 1912 5.0470000132918358e-03 + + 1.8706800043582916e-01 -1.6113600134849548e-01 + <_> + + 0 -1 1913 4.1267998516559601e-02 + + -4.8817999660968781e-02 -1.1326299905776978e+00 + <_> + + 0 -1 1914 -7.6358996331691742e-02 + + 1.4169390201568604e+00 8.7319999933242798e-02 + <_> + + 0 -1 1915 -7.2834998369216919e-02 + + 1.3189860582351685e+00 -1.4819100499153137e-01 + <_> + + 0 -1 1916 5.9576999396085739e-02 + + 4.8376999795436859e-02 8.5611802339553833e-01 + <_> + + 0 -1 1917 2.0263999700546265e-02 + + -2.1044099330902100e-01 3.3858999609947205e-01 + <_> + + 0 -1 1918 -8.0301001667976379e-02 + + -1.2464400529861450e+00 1.1857099831104279e-01 + <_> + + 0 -1 1919 -1.7835000529885292e-02 + + 2.5782299041748047e-01 -2.4564799666404724e-01 + <_> + + 0 -1 1920 1.1431000195443630e-02 + + 2.2949799895286560e-01 -2.9497599601745605e-01 + <_> + + 0 -1 1921 -2.5541000068187714e-02 + + -8.6252999305725098e-01 -7.0400000549852848e-04 + <_> + + 0 -1 1922 -7.6899997657164931e-04 + + 3.1511399149894714e-01 -1.4349000155925751e-01 + <_> + + 0 -1 1923 -1.4453999698162079e-02 + + 2.5148499011993408e-01 -2.8232899308204651e-01 + <_> + + 0 -1 1924 8.6730001494288445e-03 + + 2.6601400971412659e-01 -2.8190800547599792e-01 + <_> + 197 + -3.2772979736328125e+00 + + <_> + + 0 -1 1925 5.4708998650312424e-02 + + -5.4144299030303955e-01 6.1043000221252441e-01 + <_> + + 0 -1 1926 -1.0838799923658371e-01 + + 7.1739900112152100e-01 -4.1196098923683167e-01 + <_> + + 0 -1 1927 2.2996999323368073e-02 + + -5.8269798755645752e-01 2.9645600914955139e-01 + <_> + + 0 -1 1928 2.7540000155568123e-03 + + -7.4243897199630737e-01 1.4183300733566284e-01 + <_> + + 0 -1 1929 -2.1520000882446766e-03 + + 1.7879900336265564e-01 -6.8548601865768433e-01 + <_> + + 0 -1 1930 -2.2559000179171562e-02 + + -1.0775549411773682e+00 1.2388999760150909e-01 + <_> + + 0 -1 1931 8.3025000989437103e-02 + + 2.4500999599695206e-02 -1.0251879692077637e+00 + <_> + + 0 -1 1932 -6.6740000620484352e-03 + + -4.5283100008964539e-01 2.1230199933052063e-01 + <_> + + 0 -1 1933 7.6485000550746918e-02 + + -2.6972699165344238e-01 4.8580199480056763e-01 + <_> + + 0 -1 1934 5.4910001344978809e-03 + + -4.8871201276779175e-01 3.1616398692131042e-01 + <_> + + 0 -1 1935 -1.0414999909698963e-02 + + 4.1512900590896606e-01 -3.0044800043106079e-01 + <_> + + 0 -1 1936 2.7607999742031097e-02 + + 1.6203799843788147e-01 -9.9868500232696533e-01 + <_> + + 0 -1 1937 -2.3272000253200531e-02 + + -1.1024399995803833e+00 2.1124999970197678e-02 + <_> + + 0 -1 1938 -5.5619999766349792e-02 + + 6.5033102035522461e-01 -2.7938000857830048e-02 + <_> + + 0 -1 1939 -4.0631998330354691e-02 + + 4.2117300629615784e-01 -2.6763799786567688e-01 + <_> + + 0 -1 1940 -7.3560001328587532e-03 + + 3.5277798771858215e-01 -3.7854000926017761e-01 + <_> + + 0 -1 1941 1.7007000744342804e-02 + + -2.9189500212669373e-01 4.1053798794746399e-01 + <_> + + 0 -1 1942 -3.7034001201391220e-02 + + -1.3216309547424316e+00 1.2966500222682953e-01 + <_> + + 0 -1 1943 -1.9633000716567039e-02 + + -8.7702298164367676e-01 1.0799999581649899e-03 + <_> + + 0 -1 1944 -2.3546999320387840e-02 + + 2.6106101274490356e-01 -2.1481400728225708e-01 + <_> + + 0 -1 1945 -4.3352998793125153e-02 + + -9.9089699983596802e-01 -9.9560003727674484e-03 + <_> + + 0 -1 1946 -2.2183999419212341e-02 + + 6.3454401493072510e-01 -5.6547001004219055e-02 + <_> + + 0 -1 1947 1.6530999913811684e-02 + + 2.4664999917149544e-02 -7.3326802253723145e-01 + <_> + + 0 -1 1948 -3.2744001597166061e-02 + + -5.6297200918197632e-01 1.6640299558639526e-01 + <_> + + 0 -1 1949 7.1415998041629791e-02 + + -3.0000001424923539e-04 -9.3286401033401489e-01 + <_> + + 0 -1 1950 8.0999999772757292e-04 + + -9.5380000770092010e-02 2.5184699892997742e-01 + <_> + + 0 -1 1951 -8.4090000018477440e-03 + + -6.5496802330017090e-01 6.7300997674465179e-02 + <_> + + 0 -1 1952 -1.7254000529646873e-02 + + -4.6492999792098999e-01 1.6070899367332458e-01 + <_> + + 0 -1 1953 -1.8641000613570213e-02 + + -1.0594010353088379e+00 -1.9617000594735146e-02 + <_> + + 0 -1 1954 -9.1979997232556343e-03 + + 5.0716197490692139e-01 -1.5339200198650360e-01 + <_> + + 0 -1 1955 1.8538000062108040e-02 + + -3.0498200654983521e-01 7.3506200313568115e-01 + <_> + + 0 -1 1956 -5.0335001200437546e-02 + + -1.1140480041503906e+00 1.8000100553035736e-01 + <_> + + 0 -1 1957 -2.3529000580310822e-02 + + -8.6907899379730225e-01 -1.2459999881684780e-02 + <_> + + 0 -1 1958 -2.7100000530481339e-02 + + 6.5942901372909546e-01 -3.5323999822139740e-02 + <_> + + 0 -1 1959 6.5879998728632927e-03 + + -2.2953400015830994e-01 4.2425099015235901e-01 + <_> + + 0 -1 1960 2.3360000923275948e-02 + + 1.8356199562549591e-01 -9.8587298393249512e-01 + <_> + + 0 -1 1961 1.2946999631822109e-02 + + -3.3147400617599487e-01 2.1323199570178986e-01 + <_> + + 0 -1 1962 -6.6559999249875546e-03 + + -1.1951400339603424e-01 2.9752799868583679e-01 + <_> + + 0 -1 1963 -2.2570999339222908e-02 + + 3.8499400019645691e-01 -2.4434499442577362e-01 + <_> + + 0 -1 1964 -6.3813999295234680e-02 + + -8.9383500814437866e-01 1.4217500388622284e-01 + <_> + + 0 -1 1965 -4.9945000559091568e-02 + + 5.3864401578903198e-01 -2.0485299825668335e-01 + <_> + + 0 -1 1966 6.8319998681545258e-03 + + -5.6678999215364456e-02 3.9970999956130981e-01 + <_> + + 0 -1 1967 -5.5835999548435211e-02 + + -1.5239470005035400e+00 -5.1183000206947327e-02 + <_> + + 0 -1 1968 3.1957000494003296e-01 + + 7.4574001133441925e-02 1.2447799444198608e+00 + <_> + + 0 -1 1969 8.0955997109413147e-02 + + -1.9665500521659851e-01 5.9889698028564453e-01 + <_> + + 0 -1 1970 -1.4911999925971031e-02 + + -6.4020597934722900e-01 1.5807600319385529e-01 + <_> + + 0 -1 1971 4.6709001064300537e-02 + + 8.5239000618457794e-02 -4.5487201213836670e-01 + <_> + + 0 -1 1972 6.0539999976754189e-03 + + -4.3184000253677368e-01 2.2452600300312042e-01 + <_> + + 0 -1 1973 -3.4375999122858047e-02 + + 4.0202501416206360e-01 -2.3903599381446838e-01 + <_> + + 0 -1 1974 -3.4924000501632690e-02 + + 5.2870100736618042e-01 3.9709001779556274e-02 + <_> + + 0 -1 1975 3.0030000489205122e-03 + + -3.8754299283027649e-01 1.4192600548267365e-01 + <_> + + 0 -1 1976 -1.4132999815046787e-02 + + 8.7528401613235474e-01 8.5507996380329132e-02 + <_> + + 0 -1 1977 -6.7940000444650650e-03 + + -1.1649219989776611e+00 -3.3943001180887222e-02 + <_> + + 0 -1 1978 -5.2886001765727997e-02 + + 1.0930680036544800e+00 5.1187001168727875e-02 + <_> + + 0 -1 1979 -2.1079999860376120e-03 + + 1.3696199655532837e-01 -3.3849999308586121e-01 + <_> + + 0 -1 1980 1.8353000283241272e-02 + + 1.3661600649356842e-01 -4.0777799487113953e-01 + <_> + + 0 -1 1981 1.2671999633312225e-02 + + -1.4936000108718872e-02 -8.1707501411437988e-01 + <_> + + 0 -1 1982 1.2924999929964542e-02 + + 1.7625099420547485e-01 -3.2491698861122131e-01 + <_> + + 0 -1 1983 -1.7921000719070435e-02 + + -5.2745401859283447e-01 4.4443000108003616e-02 + <_> + + 0 -1 1984 1.9160000374540687e-03 + + -1.0978599637746811e-01 2.2067500650882721e-01 + <_> + + 0 -1 1985 -1.4697999693453312e-02 + + 3.9067798852920532e-01 -2.2224999964237213e-01 + <_> + + 0 -1 1986 -1.4972999691963196e-02 + + -2.5450900197029114e-01 1.7790000140666962e-01 + <_> + + 0 -1 1987 1.4636999927461147e-02 + + -2.5125000625848770e-02 -8.7121301889419556e-01 + <_> + + 0 -1 1988 -1.0974000208079815e-02 + + 7.9082798957824707e-01 2.0121000707149506e-02 + <_> + + 0 -1 1989 -9.1599998995661736e-03 + + -4.7906899452209473e-01 5.2232000976800919e-02 + <_> + + 0 -1 1990 4.6179997734725475e-03 + + -1.7244599759578705e-01 3.4527799487113953e-01 + <_> + + 0 -1 1991 2.3476999253034592e-02 + + 3.7760001141577959e-03 -6.5333700180053711e-01 + <_> + + 0 -1 1992 3.1766999512910843e-02 + + 1.6364000737667084e-02 5.8723700046539307e-01 + <_> + + 0 -1 1993 -1.8419999629259109e-02 + + 1.9993899762630463e-01 -3.2056498527526855e-01 + <_> + + 0 -1 1994 1.9543999806046486e-02 + + 1.8450200557708740e-01 -2.3793600499629974e-01 + <_> + + 0 -1 1995 4.1159498691558838e-01 + + -6.0382001101970673e-02 -1.6072119474411011e+00 + <_> + + 0 -1 1996 -4.1595999151468277e-02 + + -3.2756200432777405e-01 1.5058000385761261e-01 + <_> + + 0 -1 1997 -1.0335999540984631e-02 + + -6.2394398450851440e-01 1.3112000189721584e-02 + <_> + + 0 -1 1998 1.2392999604344368e-02 + + -3.3114999532699585e-02 5.5579900741577148e-01 + <_> + + 0 -1 1999 -8.7270000949501991e-03 + + 1.9883200526237488e-01 -3.7635600566864014e-01 + <_> + + 0 -1 2000 1.6295000910758972e-02 + + 2.0373000204563141e-01 -4.2800799012184143e-01 + <_> + + 0 -1 2001 -1.0483999736607075e-02 + + -5.6847000122070312e-01 4.4199001044034958e-02 + <_> + + 0 -1 2002 -1.2431999668478966e-02 + + 7.4641901254653931e-01 4.3678998947143555e-02 + <_> + + 0 -1 2003 -5.0374999642372131e-02 + + 8.5090100765228271e-01 -1.7773799598217010e-01 + <_> + + 0 -1 2004 4.9548000097274780e-02 + + 1.6784900426864624e-01 -2.9877498745918274e-01 + <_> + + 0 -1 2005 -4.1085001081228256e-02 + + -1.3302919864654541e+00 -4.9182001501321793e-02 + <_> + + 0 -1 2006 1.0069999843835831e-03 + + -6.0538999736309052e-02 1.8483200669288635e-01 + <_> + + 0 -1 2007 -5.0142999738454819e-02 + + 7.6447701454162598e-01 -1.8356999754905701e-01 + <_> + + 0 -1 2008 -8.7879998609423637e-03 + + 2.2655999660491943e-01 -6.3156999647617340e-02 + <_> + + 0 -1 2009 -5.0170999020338058e-02 + + -1.5899070501327515e+00 -6.1255000531673431e-02 + <_> + + 0 -1 2010 1.0216099768877029e-01 + + 1.2071800231933594e-01 -1.4120110273361206e+00 + <_> + + 0 -1 2011 -1.4372999779880047e-02 + + -1.3116970062255859e+00 -5.1936000585556030e-02 + <_> + + 0 -1 2012 1.0281999595463276e-02 + + -2.1639999467879534e-03 4.4247201085090637e-01 + <_> + + 0 -1 2013 -1.1814000084996223e-02 + + 6.5378099679946899e-01 -1.8723699450492859e-01 + <_> + + 0 -1 2014 7.2114996612071991e-02 + + 7.1846999228000641e-02 8.1496298313140869e-01 + <_> + + 0 -1 2015 -1.9001999869942665e-02 + + -6.7427200078964233e-01 -4.3200000072829425e-04 + <_> + + 0 -1 2016 -4.6990001574158669e-03 + + 3.3311501145362854e-01 5.5794000625610352e-02 + <_> + + 0 -1 2017 -5.8157000690698624e-02 + + 4.5572298765182495e-01 -2.0305100083351135e-01 + <_> + + 0 -1 2018 1.1360000353306532e-03 + + -4.4686999171972275e-02 2.2681899368762970e-01 + <_> + + 0 -1 2019 -4.9414999783039093e-02 + + 2.6694598793983459e-01 -2.6116999983787537e-01 + <_> + + 0 -1 2020 -1.1913800239562988e-01 + + -8.3017998933792114e-01 1.3248500227928162e-01 + <_> + + 0 -1 2021 -1.8303999677300453e-02 + + -6.7499202489852905e-01 1.7092000693082809e-02 + <_> + + 0 -1 2022 -7.9199997708201408e-03 + + -7.2287000715732574e-02 1.4425800740718842e-01 + <_> + + 0 -1 2023 5.1925998181104660e-02 + + 3.0921999365091324e-02 -5.5860602855682373e-01 + <_> + + 0 -1 2024 6.6724002361297607e-02 + + 1.3666400313377380e-01 -2.9411000013351440e-01 + <_> + + 0 -1 2025 -1.3778000138700008e-02 + + -5.9443902969360352e-01 1.5300000086426735e-02 + <_> + + 0 -1 2026 -1.7760999500751495e-02 + + 4.0496501326560974e-01 -3.3559999428689480e-03 + <_> + + 0 -1 2027 -4.2234998196363449e-02 + + -1.0897940397262573e+00 -4.0224999189376831e-02 + <_> + + 0 -1 2028 -1.3524999842047691e-02 + + 2.8921899199485779e-01 -2.5194799900054932e-01 + <_> + + 0 -1 2029 -1.1106000281870365e-02 + + 6.5312802791595459e-01 -1.8053700029850006e-01 + <_> + + 0 -1 2030 -1.2284599989652634e-01 + + -1.9570649862289429e+00 1.4815400540828705e-01 + <_> + + 0 -1 2031 4.7715999186038971e-02 + + -2.2875599563121796e-01 3.4233701229095459e-01 + <_> + + 0 -1 2032 3.1817000359296799e-02 + + 1.5976299345493317e-01 -1.0091969966888428e+00 + <_> + + 0 -1 2033 4.2570000514388084e-03 + + -3.8881298899650574e-01 8.4210000932216644e-02 + <_> + + 0 -1 2034 -6.1372999101877213e-02 + + 1.7152810096740723e+00 5.9324998408555984e-02 + <_> + + 0 -1 2035 -2.7030000928789377e-03 + + -3.8161700963973999e-01 8.5127003490924835e-02 + <_> + + 0 -1 2036 -6.8544000387191772e-02 + + -3.0925889015197754e+00 1.1788000166416168e-01 + <_> + + 0 -1 2037 1.0372500121593475e-01 + + -1.3769300282001495e-01 1.9009410142898560e+00 + <_> + + 0 -1 2038 1.5799000859260559e-02 + + -6.2660001218318939e-02 2.5917699933052063e-01 + <_> + + 0 -1 2039 -9.8040001466870308e-03 + + -5.6291598081588745e-01 4.3923001736402512e-02 + <_> + + 0 -1 2040 -9.0229995548725128e-03 + + 2.5287100672721863e-01 -4.1225999593734741e-02 + <_> + + 0 -1 2041 -6.3754998147487640e-02 + + -2.6178569793701172e+00 -7.4005998671054840e-02 + <_> + + 0 -1 2042 3.8954999297857285e-02 + + 5.9032998979091644e-02 8.5945600271224976e-01 + <_> + + 0 -1 2043 -3.9802998304367065e-02 + + 9.3600499629974365e-01 -1.5639400482177734e-01 + <_> + + 0 -1 2044 5.0301998853683472e-02 + + 1.3725900650024414e-01 -2.5549728870391846e+00 + <_> + + 0 -1 2045 4.6250000596046448e-02 + + -1.3964000158011913e-02 -7.1026200056076050e-01 + <_> + + 0 -1 2046 6.2196001410484314e-02 + + 5.9526000171899796e-02 1.6509100198745728e+00 + <_> + + 0 -1 2047 -6.4776003360748291e-02 + + 7.1368998289108276e-01 -1.7270000278949738e-01 + <_> + + 0 -1 2048 2.7522999793291092e-02 + + 1.4631600677967072e-01 -8.1428997218608856e-02 + <_> + + 0 -1 2049 3.9900001138448715e-04 + + -3.7144500017166138e-01 1.0152699798345566e-01 + <_> + + 0 -1 2050 -4.3299999088048935e-03 + + -2.3756299912929535e-01 2.6798400282859802e-01 + <_> + + 0 -1 2051 4.7297000885009766e-02 + + -2.7682000771164894e-02 -8.4910297393798828e-01 + <_> + + 0 -1 2052 1.2508999556303024e-02 + + 1.8730199337005615e-01 -5.6001102924346924e-01 + <_> + + 0 -1 2053 4.5899000018835068e-02 + + -1.5601199865341187e-01 9.7073000669479370e-01 + <_> + + 0 -1 2054 1.9853399693965912e-01 + + 1.4895500242710114e-01 -1.1015529632568359e+00 + <_> + + 0 -1 2055 1.6674999147653580e-02 + + -1.6615299880504608e-01 8.2210999727249146e-01 + <_> + + 0 -1 2056 1.9829999655485153e-03 + + -7.1249999105930328e-02 2.8810900449752808e-01 + <_> + + 0 -1 2057 2.2447999566793442e-02 + + -2.0981000736355782e-02 -7.8416502475738525e-01 + <_> + + 0 -1 2058 -1.3913000002503395e-02 + + -1.8165799975395203e-01 2.0491799712181091e-01 + <_> + + 0 -1 2059 -7.7659999951720238e-03 + + -4.5595899224281311e-01 6.3576996326446533e-02 + <_> + + 0 -1 2060 -1.3209000229835510e-02 + + 2.6632300019264221e-01 -1.7795999348163605e-01 + <_> + + 0 -1 2061 4.9052998423576355e-02 + + -1.5476800501346588e-01 1.1069979667663574e+00 + <_> + + 0 -1 2062 2.0263999700546265e-02 + + 6.8915002048015594e-02 6.9867497682571411e-01 + <_> + + 0 -1 2063 -1.6828000545501709e-02 + + 2.7607199549674988e-01 -2.5139200687408447e-01 + <_> + + 0 -1 2064 -1.6939499974250793e-01 + + -3.0767529010772705e+00 1.1617500334978104e-01 + <_> + + 0 -1 2065 -1.1336100101470947e-01 + + -1.4639229774475098e+00 -5.1447000354528427e-02 + <_> + + 0 -1 2066 -7.7685996890068054e-02 + + 8.8430202007293701e-01 4.3306998908519745e-02 + <_> + + 0 -1 2067 -1.5568000264465809e-02 + + 1.3672499358654022e-01 -3.4505501389503479e-01 + <_> + + 0 -1 2068 -6.6018998622894287e-02 + + -1.0300110578536987e+00 1.1601399630308151e-01 + <_> + + 0 -1 2069 8.3699999377131462e-03 + + 7.6429001986980438e-02 -4.4002500176429749e-01 + <_> + + 0 -1 2070 3.5402998328208923e-02 + + 1.1979500204324722e-01 -7.2668302059173584e-01 + <_> + + 0 -1 2071 -3.9051000028848648e-02 + + 6.7375302314758301e-01 -1.8196000158786774e-01 + <_> + + 0 -1 2072 -9.7899995744228363e-03 + + 2.1264599263668060e-01 3.6756001412868500e-02 + <_> + + 0 -1 2073 -2.3047000169754028e-02 + + 4.4742199778556824e-01 -2.0986700057983398e-01 + <_> + + 0 -1 2074 3.1169999856501818e-03 + + 3.7544000893831253e-02 2.7808201313018799e-01 + <_> + + 0 -1 2075 1.3136000372469425e-02 + + -1.9842399656772614e-01 5.4335701465606689e-01 + <_> + + 0 -1 2076 1.4782000333070755e-02 + + 1.3530600070953369e-01 -1.1153600364923477e-01 + <_> + + 0 -1 2077 -6.0139000415802002e-02 + + 8.4039300680160522e-01 -1.6711600124835968e-01 + <_> + + 0 -1 2078 5.1998998969793320e-02 + + 1.7372000217437744e-01 -7.8547602891921997e-01 + <_> + + 0 -1 2079 2.4792000651359558e-02 + + -1.7739200592041016e-01 6.6752600669860840e-01 + <_> + + 0 -1 2080 -1.2014999985694885e-02 + + -1.4263699948787689e-01 1.6070500016212463e-01 + <_> + + 0 -1 2081 -9.8655998706817627e-02 + + 1.0429769754409790e+00 -1.5770199894905090e-01 + <_> + + 0 -1 2082 1.1758299916982651e-01 + + 1.0955700278282166e-01 -4.4920377731323242e+00 + <_> + + 0 -1 2083 -1.8922999501228333e-02 + + -7.8543400764465332e-01 1.2984000146389008e-02 + <_> + + 0 -1 2084 -2.8390999883413315e-02 + + -6.0569900274276733e-01 1.2903499603271484e-01 + <_> + + 0 -1 2085 1.3182999566197395e-02 + + -1.4415999874472618e-02 -7.3210501670837402e-01 + <_> + + 0 -1 2086 -1.1653000116348267e-01 + + -2.0442469120025635e+00 1.4053100347518921e-01 + <_> + + 0 -1 2087 -3.8880000356584787e-03 + + -4.1861599683761597e-01 7.8704997897148132e-02 + <_> + + 0 -1 2088 3.1229000538587570e-02 + + 2.4632999673485756e-02 4.1870400309562683e-01 + <_> + + 0 -1 2089 2.5198999792337418e-02 + + -1.7557799816131592e-01 6.4710599184036255e-01 + <_> + + 0 -1 2090 -2.8124000877141953e-02 + + -2.2005599737167358e-01 1.4121000468730927e-01 + <_> + + 0 -1 2091 3.6499001085758209e-02 + + -6.8426996469497681e-02 -2.3410849571228027e+00 + <_> + + 0 -1 2092 -7.2292998433113098e-02 + + 1.2898750305175781e+00 8.4875002503395081e-02 + <_> + + 0 -1 2093 -4.1671000421047211e-02 + + -1.1630970239639282e+00 -5.3752999752759933e-02 + <_> + + 0 -1 2094 4.7703001648187637e-02 + + 7.0101000368595123e-02 7.3676502704620361e-01 + <_> + + 0 -1 2095 6.5793000161647797e-02 + + -1.7755299806594849e-01 6.9780498743057251e-01 + <_> + + 0 -1 2096 1.3904999941587448e-02 + + 2.1936799585819244e-01 -2.0390799641609192e-01 + <_> + + 0 -1 2097 -2.7730999514460564e-02 + + 6.1867898702621460e-01 -1.7804099619388580e-01 + <_> + + 0 -1 2098 -1.5879999846220016e-02 + + -4.6484100818634033e-01 1.8828600645065308e-01 + <_> + + 0 -1 2099 7.4128001928329468e-02 + + -1.2858100235462189e-01 3.2792479991912842e+00 + <_> + + 0 -1 2100 -8.9000002481043339e-04 + + -3.0117601156234741e-01 2.3818799853324890e-01 + <_> + + 0 -1 2101 1.7965000122785568e-02 + + -2.2284999489784241e-01 2.9954001307487488e-01 + <_> + + 0 -1 2102 -2.5380000006407499e-03 + + 2.5064399838447571e-01 -1.3665600121021271e-01 + <_> + + 0 -1 2103 -9.0680001303553581e-03 + + 2.9017499089241028e-01 -2.8929701447486877e-01 + <_> + + 0 -1 2104 4.9169998615980148e-02 + + 1.9156399369239807e-01 -6.8328702449798584e-01 + <_> + + 0 -1 2105 -3.0680999159812927e-02 + + -7.5677001476287842e-01 -1.3279999606311321e-02 + <_> + + 0 -1 2106 1.0017400234937668e-01 + + 8.4453999996185303e-02 1.0888710021972656e+00 + <_> + + 0 -1 2107 3.1950001139193773e-03 + + -2.6919400691986084e-01 1.9537900388240814e-01 + <_> + + 0 -1 2108 3.5503000020980835e-02 + + 1.3632300496101379e-01 -5.6917202472686768e-01 + <_> + + 0 -1 2109 4.5900000259280205e-04 + + -4.0443998575210571e-01 1.4074799418449402e-01 + <_> + + 0 -1 2110 2.5258999317884445e-02 + + 1.6243200004100800e-01 -5.5741798877716064e-01 + <_> + + 0 -1 2111 -5.1549999043345451e-03 + + 3.1132599711418152e-01 -2.2756099700927734e-01 + <_> + + 0 -1 2112 1.5869999770075083e-03 + + -2.6867699623107910e-01 1.9565400481224060e-01 + <_> + + 0 -1 2113 -1.6204999759793282e-02 + + 1.5486499667167664e-01 -3.4057798981666565e-01 + <_> + + 0 -1 2114 -2.9624000191688538e-02 + + 1.1466799974441528e+00 9.0557999908924103e-02 + <_> + + 0 -1 2115 -1.5930000226944685e-03 + + -7.1257501840591431e-01 -7.0400000549852848e-04 + <_> + + 0 -1 2116 -5.4019000381231308e-02 + + 4.1537499427795410e-01 2.7246000245213509e-02 + <_> + + 0 -1 2117 -6.6211000084877014e-02 + + -1.3340090513229370e+00 -4.7352999448776245e-02 + <_> + + 0 -1 2118 2.7940999716520309e-02 + + 1.4446300268173218e-01 -5.1518398523330688e-01 + <_> + + 0 -1 2119 2.8957000002264977e-02 + + -4.9966000020503998e-02 -1.1929039955139160e+00 + <_> + + 0 -1 2120 -2.0424999296665192e-02 + + 6.3881301879882812e-01 3.8141001015901566e-02 + <_> + + 0 -1 2121 1.2416999787092209e-02 + + -2.1547000110149384e-01 4.9477699398994446e-01 + <_> + 181 + -3.3196411132812500e+00 + + <_> + + 0 -1 2122 4.3274000287055969e-02 + + -8.0494397878646851e-01 3.9897298812866211e-01 + <_> + + 0 -1 2123 1.8615500628948212e-01 + + -3.1655299663543701e-01 6.8877297639846802e-01 + <_> + + 0 -1 2124 3.1860999763011932e-02 + + -6.4266198873519897e-01 2.5550898909568787e-01 + <_> + + 0 -1 2125 1.4022000133991241e-02 + + -4.5926600694656372e-01 3.1171199679374695e-01 + <_> + + 0 -1 2126 -6.3029997982084751e-03 + + 4.6026900410652161e-01 -2.7438500523567200e-01 + <_> + + 0 -1 2127 -5.4310001432895660e-03 + + 3.6608600616455078e-01 -2.7205801010131836e-01 + <_> + + 0 -1 2128 1.6822999343276024e-02 + + 2.3476999253034592e-02 -8.8443797826766968e-01 + <_> + + 0 -1 2129 2.6039000600576401e-02 + + 1.7488799989223480e-01 -5.4564702510833740e-01 + <_> + + 0 -1 2130 -2.6720000430941582e-02 + + -9.6396499872207642e-01 2.3524999618530273e-02 + <_> + + 0 -1 2131 -1.7041999846696854e-02 + + -7.0848798751831055e-01 2.1468099951744080e-01 + <_> + + 0 -1 2132 5.9569999575614929e-03 + + 7.3601000010967255e-02 -6.8225598335266113e-01 + <_> + + 0 -1 2133 -2.8679999522864819e-03 + + -7.4935001134872437e-01 2.3803399503231049e-01 + <_> + + 0 -1 2134 -4.3774999678134918e-02 + + 6.8323302268981934e-01 -2.1380299329757690e-01 + <_> + + 0 -1 2135 5.1633000373840332e-02 + + -1.2566499412059784e-01 6.7523801326751709e-01 + <_> + + 0 -1 2136 8.1780003383755684e-03 + + 7.0689998567104340e-02 -8.0665898323059082e-01 + <_> + + 0 -1 2137 -5.2841998636722565e-02 + + 9.5433902740478516e-01 1.6548000276088715e-02 + <_> + + 0 -1 2138 5.2583999931812286e-02 + + -2.8414401412010193e-01 4.7129800915718079e-01 + <_> + + 0 -1 2139 -1.2659000232815742e-02 + + 3.8445401191711426e-01 -6.2288001179695129e-02 + <_> + + 0 -1 2140 1.1694000102579594e-02 + + 5.6000000768108293e-05 -1.0173139572143555e+00 + <_> + + 0 -1 2141 -2.3918999359011650e-02 + + 8.4921300411224365e-01 5.7399999350309372e-03 + <_> + + 0 -1 2142 -6.1673998832702637e-02 + + -9.2571401596069336e-01 -1.7679999582469463e-03 + <_> + + 0 -1 2143 -1.8279999494552612e-03 + + -5.4372298717498779e-01 2.4932399392127991e-01 + <_> + + 0 -1 2144 3.5257998853921890e-02 + + -7.3719997890293598e-03 -9.3963998556137085e-01 + <_> + + 0 -1 2145 -1.8438000231981277e-02 + + 7.2136700153350830e-01 1.0491999797523022e-02 + <_> + + 0 -1 2146 -3.8389001041650772e-02 + + 1.9272600114345551e-01 -3.5832101106643677e-01 + <_> + + 0 -1 2147 9.9720999598503113e-02 + + 1.1354199796915054e-01 -1.6304190158843994e+00 + <_> + + 0 -1 2148 8.4462001919746399e-02 + + -5.3420998156070709e-02 -1.6981120109558105e+00 + <_> + + 0 -1 2149 4.0270000696182251e-02 + + -1.0783199965953827e-01 5.1926600933074951e-01 + <_> + + 0 -1 2150 5.8935999870300293e-02 + + -1.8053700029850006e-01 9.5119798183441162e-01 + <_> + + 0 -1 2151 1.4957000315189362e-01 + + 1.6785299777984619e-01 -1.1591869592666626e+00 + <_> + + 0 -1 2152 6.9399998756125569e-04 + + 2.0491400361061096e-01 -3.3118200302124023e-01 + <_> + + 0 -1 2153 -3.3369001001119614e-02 + + 9.3468099832534790e-01 -2.9639999847859144e-03 + <_> + + 0 -1 2154 9.3759996816515923e-03 + + 3.7000000011175871e-03 -7.7549797296524048e-01 + <_> + + 0 -1 2155 4.3193999677896500e-02 + + -2.2040000185370445e-03 7.4589699506759644e-01 + <_> + + 0 -1 2156 -6.7555002868175507e-02 + + 7.2292101383209229e-01 -1.8404200673103333e-01 + <_> + + 0 -1 2157 -3.1168600916862488e-01 + + 1.0014270544052124e+00 3.4003000706434250e-02 + <_> + + 0 -1 2158 2.9743999242782593e-02 + + -4.6356000006198883e-02 -1.2781809568405151e+00 + <_> + + 0 -1 2159 1.0737000033259392e-02 + + 1.4812000095844269e-02 6.6649997234344482e-01 + <_> + + 0 -1 2160 -2.8841000050306320e-02 + + -9.4222599267959595e-01 -2.0796999335289001e-02 + <_> + + 0 -1 2161 -5.7649998925626278e-03 + + -4.3541899323463440e-01 2.3386000096797943e-01 + <_> + + 0 -1 2162 2.8410999104380608e-02 + + -1.7615799605846405e-01 8.5765302181243896e-01 + <_> + + 0 -1 2163 -2.9007999226450920e-02 + + 5.7978099584579468e-01 2.8565999120473862e-02 + <_> + + 0 -1 2164 2.4965999647974968e-02 + + -2.2729000076651573e-02 -9.6773099899291992e-01 + <_> + + 0 -1 2165 1.2036000378429890e-02 + + -1.4214700460433960e-01 5.1687997579574585e-01 + <_> + + 0 -1 2166 -4.2514000087976456e-02 + + 9.7273802757263184e-01 -1.8119800090789795e-01 + <_> + + 0 -1 2167 1.0276000015437603e-02 + + -8.3099998533725739e-02 3.1762799620628357e-01 + <_> + + 0 -1 2168 -6.9191999733448029e-02 + + -2.0668580532073975e+00 -6.0173999518156052e-02 + <_> + + 0 -1 2169 -4.6769999898970127e-03 + + 4.4131800532341003e-01 2.3209000006318092e-02 + <_> + + 0 -1 2170 -1.3923999853432178e-02 + + 2.8606700897216797e-01 -2.9152700304985046e-01 + <_> + + 0 -1 2171 -1.5333999879658222e-02 + + -5.7414501905441284e-01 2.3063300549983978e-01 + <_> + + 0 -1 2172 -1.0239000432193279e-02 + + 3.4479200839996338e-01 -2.6080399751663208e-01 + <_> + + 0 -1 2173 -5.0988998264074326e-02 + + 5.6154102087020874e-01 6.1218999326229095e-02 + <_> + + 0 -1 2174 3.0689999461174011e-02 + + -1.4772799611091614e-01 1.6378489732742310e+00 + <_> + + 0 -1 2175 -1.1223999783396721e-02 + + 2.4006199836730957e-01 -4.4864898920059204e-01 + <_> + + 0 -1 2176 -6.2899999320507050e-03 + + 4.3119499087333679e-01 -2.3808999359607697e-01 + <_> + + 0 -1 2177 7.8590996563434601e-02 + + 1.9865000620484352e-02 8.0853801965713501e-01 + <_> + + 0 -1 2178 -1.0178999975323677e-02 + + 1.8193200230598450e-01 -3.2877799868583679e-01 + <_> + + 0 -1 2179 3.1227000057697296e-02 + + 1.4973899722099304e-01 -1.4180339574813843e+00 + <_> + + 0 -1 2180 4.0196999907493591e-02 + + -1.9760499894618988e-01 5.8508199453353882e-01 + <_> + + 0 -1 2181 1.6138000413775444e-02 + + 5.0000002374872565e-04 3.9050000905990601e-01 + <_> + + 0 -1 2182 -4.5519001781940460e-02 + + 1.2646820545196533e+00 -1.5632599592208862e-01 + <_> + + 0 -1 2183 -1.8130000680685043e-02 + + 6.5148502588272095e-01 1.0235999710857868e-02 + <_> + + 0 -1 2184 -1.4001999981701374e-02 + + -1.0344820022583008e+00 -3.2182998955249786e-02 + <_> + + 0 -1 2185 -3.8816001266241074e-02 + + -4.7874298691749573e-01 1.6290700435638428e-01 + <_> + + 0 -1 2186 3.1656000763177872e-02 + + -2.0983399450778961e-01 5.4575902223587036e-01 + <_> + + 0 -1 2187 -1.0839999653398991e-02 + + 5.1898801326751709e-01 -1.5080000273883343e-02 + <_> + + 0 -1 2188 1.2032999657094479e-02 + + -2.1107600629329681e-01 7.5937002897262573e-01 + <_> + + 0 -1 2189 7.0772998034954071e-02 + + 1.8048800528049469e-01 -7.4048501253128052e-01 + <_> + + 0 -1 2190 5.3139799833297729e-01 + + -1.4491699635982513e-01 1.5360039472579956e+00 + <_> + + 0 -1 2191 -1.4774000272154808e-02 + + -2.8153699636459351e-01 2.0407299697399139e-01 + <_> + + 0 -1 2192 -2.2410000674426556e-03 + + -4.4876301288604736e-01 5.3989000618457794e-02 + <_> + + 0 -1 2193 4.9968000501394272e-02 + + 4.1514001786708832e-02 2.9417100548744202e-01 + <_> + + 0 -1 2194 -4.7701999545097351e-02 + + 3.9674299955368042e-01 -2.8301799297332764e-01 + <_> + + 0 -1 2195 -9.1311000287532806e-02 + + 2.1994259357452393e+00 8.7964996695518494e-02 + <_> + + 0 -1 2196 3.8070000708103180e-02 + + -2.8025600314140320e-01 2.5156199932098389e-01 + <_> + + 0 -1 2197 -1.5538999810814857e-02 + + 3.4157499670982361e-01 1.7924999818205833e-02 + <_> + + 0 -1 2198 -1.5445999801158905e-02 + + 2.8680199384689331e-01 -2.5135898590087891e-01 + <_> + + 0 -1 2199 -5.7388000190258026e-02 + + 6.3830000162124634e-01 8.8597998023033142e-02 + <_> + + 0 -1 2200 -5.9440000914037228e-03 + + 7.9016998410224915e-02 -4.0774899721145630e-01 + <_> + + 0 -1 2201 -6.9968998432159424e-02 + + -4.4644200801849365e-01 1.7219600081443787e-01 + <_> + + 0 -1 2202 -2.5064999237656593e-02 + + -9.8270201683044434e-01 -3.5388000309467316e-02 + <_> + + 0 -1 2203 1.7216000705957413e-02 + + 2.2705900669097900e-01 -8.0550098419189453e-01 + <_> + + 0 -1 2204 -4.4279001653194427e-02 + + 8.3951997756958008e-01 -1.7429600656032562e-01 + <_> + + 0 -1 2205 4.3988998979330063e-02 + + 1.1557199805974960e-01 -1.9666889905929565e+00 + <_> + + 0 -1 2206 1.5907000750303268e-02 + + -3.7576001137495041e-02 -1.0311100482940674e+00 + <_> + + 0 -1 2207 -9.2754997313022614e-02 + + -1.3530019521713257e+00 1.2141299992799759e-01 + <_> + + 0 -1 2208 7.1037001907825470e-02 + + -1.7684300243854523e-01 7.4485200643539429e-01 + <_> + + 0 -1 2209 5.7762000709772110e-02 + + 1.2835599482059479e-01 -4.4444200396537781e-01 + <_> + + 0 -1 2210 -1.6432000324130058e-02 + + 8.0152702331542969e-01 -1.7491699755191803e-01 + <_> + + 0 -1 2211 2.3939000442624092e-02 + + 1.6144999861717224e-01 -1.2364500015974045e-01 + <_> + + 0 -1 2212 1.2636000290513039e-02 + + 1.5411999821662903e-01 -3.3293798565864563e-01 + <_> + + 0 -1 2213 -5.4347999393939972e-02 + + -1.8400700092315674e+00 1.4835999906063080e-01 + <_> + + 0 -1 2214 -1.3261999934911728e-02 + + -8.0838799476623535e-01 -2.7726000174880028e-02 + <_> + + 0 -1 2215 6.1340001411736012e-03 + + -1.3785000145435333e-01 3.2858499884605408e-01 + <_> + + 0 -1 2216 2.8991000726819038e-02 + + -2.5516999885439873e-02 -8.3387202024459839e-01 + <_> + + 0 -1 2217 -2.1986000239849091e-02 + + -7.3739999532699585e-01 1.7887100577354431e-01 + <_> + + 0 -1 2218 5.3269998170435429e-03 + + -4.5449298620223999e-01 6.8791002035140991e-02 + <_> + + 0 -1 2219 8.6047999560832977e-02 + + 2.1008500456809998e-01 -3.7808901071548462e-01 + <_> + + 0 -1 2220 -8.5549997165799141e-03 + + 4.0134999155998230e-01 -2.1074099838733673e-01 + <_> + + 0 -1 2221 6.7790001630783081e-03 + + -2.1648999303579330e-02 4.5421499013900757e-01 + <_> + + 0 -1 2222 -6.3959998078644276e-03 + + -4.9818599224090576e-01 7.5907997786998749e-02 + <_> + + 0 -1 2223 8.9469999074935913e-03 + + 1.7857700586318970e-01 -2.8454899787902832e-01 + <_> + + 0 -1 2224 3.2589999027550220e-03 + + 4.6624999493360519e-02 -5.5206298828125000e-01 + <_> + + 0 -1 2225 4.1476998478174210e-02 + + 1.7550499737262726e-01 -2.0703999698162079e-01 + <_> + + 0 -1 2226 -6.7449999041855335e-03 + + -4.6392598748207092e-01 6.9303996860980988e-02 + <_> + + 0 -1 2227 3.0564999207854271e-02 + + 5.1734998822212219e-02 7.5550502538681030e-01 + <_> + + 0 -1 2228 -7.4780001305043697e-03 + + 1.4893899857997894e-01 -3.1906801462173462e-01 + <_> + + 0 -1 2229 8.9088998734951019e-02 + + 1.3738800585269928e-01 -1.1379710435867310e+00 + <_> + + 0 -1 2230 7.3230001144111156e-03 + + -2.8829199075698853e-01 1.9088600575923920e-01 + <_> + + 0 -1 2231 -1.8205000087618828e-02 + + -3.0178600549697876e-01 1.6795800626277924e-01 + <_> + + 0 -1 2232 -2.5828000158071518e-02 + + -9.8137998580932617e-01 -1.9860999658703804e-02 + <_> + + 0 -1 2233 1.0936199873685837e-01 + + 4.8790000379085541e-02 5.3118300437927246e-01 + <_> + + 0 -1 2234 -1.1424999684095383e-02 + + 2.3705999553203583e-01 -2.7925300598144531e-01 + <_> + + 0 -1 2235 -5.7565998286008835e-02 + + 4.7255399823188782e-01 6.5171003341674805e-02 + <_> + + 0 -1 2236 1.0278300195932388e-01 + + -2.0765100419521332e-01 5.0947701930999756e-01 + <_> + + 0 -1 2237 2.7041999623179436e-02 + + 1.6421200335025787e-01 -1.4508620500564575e+00 + <_> + + 0 -1 2238 -1.3635000213980675e-02 + + -5.6543898582458496e-01 2.3788999766111374e-02 + <_> + + 0 -1 2239 -3.2158198952674866e-01 + + -3.5602829456329346e+00 1.1801300197839737e-01 + <_> + + 0 -1 2240 2.0458100736141205e-01 + + -3.7016000598669052e-02 -1.0225499868392944e+00 + <_> + + 0 -1 2241 -7.0347003638744354e-02 + + -5.6491899490356445e-01 1.8525199592113495e-01 + <_> + + 0 -1 2242 3.7831000983715057e-02 + + -2.9901999980211258e-02 -8.2921499013900757e-01 + <_> + + 0 -1 2243 -7.0298001170158386e-02 + + -5.3172302246093750e-01 1.4430199563503265e-01 + <_> + + 0 -1 2244 6.3221000134944916e-02 + + -2.2041200101375580e-01 4.7952198982238770e-01 + <_> + + 0 -1 2245 3.6393001675605774e-02 + + 1.4222699403762817e-01 -6.1193901300430298e-01 + <_> + + 0 -1 2246 4.0099998004734516e-03 + + -3.4560799598693848e-01 1.1738699674606323e-01 + <_> + + 0 -1 2247 -4.9106001853942871e-02 + + 9.5984101295471191e-01 6.4934998750686646e-02 + <_> + + 0 -1 2248 -7.1583002805709839e-02 + + 1.7385669946670532e+00 -1.4252899587154388e-01 + <_> + + 0 -1 2249 -3.8008999079465866e-02 + + 1.3872820138931274e+00 6.6188000142574310e-02 + <_> + + 0 -1 2250 -3.1570000573992729e-03 + + 5.3677000105381012e-02 -5.4048001766204834e-01 + <_> + + 0 -1 2251 1.9458999857306480e-02 + + -9.3620002269744873e-02 3.9131000638008118e-01 + <_> + + 0 -1 2252 1.1293999850749969e-02 + + 3.7223998457193375e-02 -5.4251801967620850e-01 + <_> + + 0 -1 2253 -3.3495001494884491e-02 + + 9.5307898521423340e-01 3.7696998566389084e-02 + <_> + + 0 -1 2254 9.2035003006458282e-02 + + -1.3488399982452393e-01 2.2897069454193115e+00 + <_> + + 0 -1 2255 3.7529999390244484e-03 + + 2.2824199497699738e-01 -5.9983700513839722e-01 + <_> + + 0 -1 2256 1.2848000042140484e-02 + + -2.2005200386047363e-01 3.7221899628639221e-01 + <_> + + 0 -1 2257 -1.4316199719905853e-01 + + 1.2855789661407471e+00 4.7237001359462738e-02 + <_> + + 0 -1 2258 -9.6879996359348297e-02 + + -3.9550929069519043e+00 -7.2903998196125031e-02 + <_> + + 0 -1 2259 -8.8459998369216919e-03 + + 3.7674999237060547e-01 -4.6484000980854034e-02 + <_> + + 0 -1 2260 1.5900000929832458e-02 + + -2.4457000195980072e-02 -8.0034798383712769e-01 + <_> + + 0 -1 2261 7.0372000336647034e-02 + + 1.7019000649452209e-01 -6.3068997859954834e-01 + <_> + + 0 -1 2262 -3.7953998893499374e-02 + + -9.3667197227478027e-01 -4.1214000433683395e-02 + <_> + + 0 -1 2263 5.1597899198532104e-01 + + 1.3080599904060364e-01 -1.5802290439605713e+00 + <_> + + 0 -1 2264 -3.2843001186847687e-02 + + -1.1441620588302612e+00 -4.9173999577760696e-02 + <_> + + 0 -1 2265 -3.6357000470161438e-02 + + 4.9606400728225708e-01 -3.4458998590707779e-02 + <_> + + 0 -1 2266 6.8080001510679722e-03 + + -3.0997800827026367e-01 1.7054800689220428e-01 + <_> + + 0 -1 2267 -1.6114000231027603e-02 + + -3.7904599308967590e-01 1.6078999638557434e-01 + <_> + + 0 -1 2268 8.4530003368854523e-03 + + -1.8655499815940857e-01 5.6367701292037964e-01 + <_> + + 0 -1 2269 -1.3752399384975433e-01 + + -5.8989900350570679e-01 1.1749500036239624e-01 + <_> + + 0 -1 2270 1.7688000202178955e-01 + + -1.5424899756908417e-01 9.2911100387573242e-01 + <_> + + 0 -1 2271 7.9309996217489243e-03 + + 3.2190701365470886e-01 -1.6392600536346436e-01 + <_> + + 0 -1 2272 1.0971800237894058e-01 + + -1.5876500308513641e-01 1.0186259746551514e+00 + <_> + + 0 -1 2273 -3.0293000862002373e-02 + + 7.5587302446365356e-01 3.1794998794794083e-02 + <_> + + 0 -1 2274 -2.3118000477552414e-02 + + -8.8451498746871948e-01 -9.5039997249841690e-03 + <_> + + 0 -1 2275 -3.0900000128895044e-03 + + 2.3838299512863159e-01 -1.1606200039386749e-01 + <_> + + 0 -1 2276 -3.3392000943422318e-02 + + -1.8738139867782593e+00 -6.8502999842166901e-02 + <_> + + 0 -1 2277 1.3190000317990780e-02 + + 1.2919899821281433e-01 -6.7512202262878418e-01 + <_> + + 0 -1 2278 1.4661000110208988e-02 + + -2.4829000234603882e-02 -7.4396800994873047e-01 + <_> + + 0 -1 2279 -1.3248000293970108e-02 + + 4.6820199489593506e-01 -2.4165000766515732e-02 + <_> + + 0 -1 2280 -1.6218999400734901e-02 + + 4.0083798766136169e-01 -2.1255700290203094e-01 + <_> + + 0 -1 2281 -2.9052000492811203e-02 + + -1.5650019645690918e+00 1.4375899732112885e-01 + <_> + + 0 -1 2282 -1.0153199732303619e-01 + + -1.9220689535140991e+00 -6.9559998810291290e-02 + <_> + + 0 -1 2283 3.7753999233245850e-02 + + 1.3396799564361572e-01 -2.2639141082763672e+00 + <_> + + 0 -1 2284 -2.8555598855018616e-01 + + 1.0215270519256592e+00 -1.5232199430465698e-01 + <_> + + 0 -1 2285 1.5360699594020844e-01 + + -9.7409002482891083e-02 4.1662400960922241e-01 + <_> + + 0 -1 2286 -2.1199999901000410e-04 + + 1.1271899938583374e-01 -4.1653999686241150e-01 + <_> + + 0 -1 2287 -2.0597999915480614e-02 + + 6.0540497303009033e-01 6.2467999756336212e-02 + <_> + + 0 -1 2288 3.7353999912738800e-02 + + -1.8919000029563904e-01 4.6464699506759644e-01 + <_> + + 0 -1 2289 5.7275000959634781e-02 + + 1.1565300077199936e-01 -1.3213009834289551e+00 + <_> + + 0 -1 2290 5.1029999740421772e-03 + + -2.8061500191688538e-01 1.9313399493694305e-01 + <_> + + 0 -1 2291 -5.4644998162984848e-02 + + 7.2428500652313232e-01 7.5447998940944672e-02 + <_> + + 0 -1 2292 2.5349000468850136e-02 + + -1.9481800496578217e-01 4.6032801270484924e-01 + <_> + + 0 -1 2293 2.4311000481247902e-02 + + 1.5564100444316864e-01 -4.9913901090621948e-01 + <_> + + 0 -1 2294 3.5962000489234924e-02 + + -5.8573000133037567e-02 -1.5418399572372437e+00 + <_> + + 0 -1 2295 -1.0000699758529663e-01 + + -1.6100039482116699e+00 1.1450500041246414e-01 + <_> + + 0 -1 2296 8.4435999393463135e-02 + + -6.1406999826431274e-02 -1.4673349857330322e+00 + <_> + + 0 -1 2297 1.5947999432682991e-02 + + 1.6287900507450104e-01 -1.1026400327682495e-01 + <_> + + 0 -1 2298 3.3824000507593155e-02 + + -1.7932699620723724e-01 5.7218402624130249e-01 + <_> + + 0 -1 2299 -6.1996001750230789e-02 + + 4.6511812210083008e+00 9.4534002244472504e-02 + <_> + + 0 -1 2300 6.9876998662948608e-02 + + -1.6985900700092316e-01 8.7028998136520386e-01 + <_> + + 0 -1 2301 -2.7916999533772469e-02 + + 9.1042500734329224e-01 5.6827001273632050e-02 + <_> + + 0 -1 2302 -1.2764000333845615e-02 + + 2.2066700458526611e-01 -2.7769100666046143e-01 + <_> + 199 + -3.2573320865631104e+00 + + <_> + + 0 -1 2303 2.1662000566720963e-02 + + -8.9868897199630737e-01 2.9436299204826355e-01 + <_> + + 0 -1 2304 1.0044500231742859e-01 + + -3.7659201025962830e-01 6.0891002416610718e-01 + <_> + + 0 -1 2305 2.6003999635577202e-02 + + -3.8128501176834106e-01 3.9217400550842285e-01 + <_> + + 0 -1 2306 2.8441000729799271e-02 + + -1.8182300031185150e-01 5.8927202224731445e-01 + <_> + + 0 -1 2307 3.8612000644207001e-02 + + -2.2399599850177765e-01 6.3779997825622559e-01 + <_> + + 0 -1 2308 -4.6594999730587006e-02 + + 7.0812201499938965e-01 -1.4666199684143066e-01 + <_> + + 0 -1 2309 -4.2791999876499176e-02 + + 4.7680398821830750e-01 -2.9233199357986450e-01 + <_> + + 0 -1 2310 3.7960000336170197e-03 + + -1.8510299921035767e-01 5.2626699209213257e-01 + <_> + + 0 -1 2311 4.2348999530076981e-02 + + 3.9244998246431351e-02 -8.9197701215744019e-01 + <_> + + 0 -1 2312 1.9598999992012978e-02 + + -2.3358400166034698e-01 4.4146499037742615e-01 + <_> + + 0 -1 2313 8.7400001939386129e-04 + + -4.6063598990440369e-01 1.7689600586891174e-01 + <_> + + 0 -1 2314 -4.3629999272525311e-03 + + 3.3493199944496155e-01 -2.9893401265144348e-01 + <_> + + 0 -1 2315 1.6973000019788742e-02 + + -1.6408699750900269e-01 1.5993679761886597e+00 + <_> + + 0 -1 2316 3.6063998937606812e-02 + + 2.2601699829101562e-01 -5.3186100721359253e-01 + <_> + + 0 -1 2317 -7.0864997804164886e-02 + + 1.5220500528812408e-01 -4.1914600133895874e-01 + <_> + + 0 -1 2318 -6.3075996935367584e-02 + + -1.4874019622802734e+00 1.2953700125217438e-01 + <_> + + 0 -1 2319 2.9670000076293945e-02 + + -1.9145900011062622e-01 9.8184901475906372e-01 + <_> + + 0 -1 2320 3.7873998284339905e-02 + + 1.3459500670433044e-01 -5.6316298246383667e-01 + <_> + + 0 -1 2321 -3.3289000391960144e-02 + + -1.0828030109405518e+00 -1.1504000052809715e-02 + <_> + + 0 -1 2322 -3.1608998775482178e-02 + + -5.9224498271942139e-01 1.3394799828529358e-01 + <_> + + 0 -1 2323 1.0740000288933516e-03 + + -4.9185800552368164e-01 9.4446003437042236e-02 + <_> + + 0 -1 2324 -7.1556001901626587e-02 + + 5.9710198640823364e-01 -3.9553001523017883e-02 + <_> + + 0 -1 2325 -8.1170000135898590e-02 + + -1.1817820072174072e+00 -2.8254000470042229e-02 + <_> + + 0 -1 2326 4.4860001653432846e-03 + + -6.1028099060058594e-01 2.2619099915027618e-01 + <_> + + 0 -1 2327 -4.2176000773906708e-02 + + -1.1435619592666626e+00 -2.9001999646425247e-02 + <_> + + 0 -1 2328 -6.5640002489089966e-02 + + -1.6470279693603516e+00 1.2810300290584564e-01 + <_> + + 0 -1 2329 1.8188999965786934e-02 + + -3.1149399280548096e-01 2.5739601254463196e-01 + <_> + + 0 -1 2330 -5.1520001143217087e-02 + + -6.9206899404525757e-01 1.5270799398422241e-01 + <_> + + 0 -1 2331 -4.7150999307632446e-02 + + -7.1868300437927246e-01 2.6879999786615372e-03 + <_> + + 0 -1 2332 1.7488999292254448e-02 + + 2.2371199727058411e-01 -5.5381798744201660e-01 + <_> + + 0 -1 2333 -2.5264000520110130e-02 + + 1.0319819450378418e+00 -1.7496499419212341e-01 + <_> + + 0 -1 2334 -4.0745001286268234e-02 + + 4.4961598515510559e-01 3.9349000900983810e-02 + <_> + + 0 -1 2335 -3.7666998803615570e-02 + + -8.5475701093673706e-01 -1.2463999912142754e-02 + <_> + + 0 -1 2336 -1.3411000370979309e-02 + + 5.7845598459243774e-01 -1.7467999830842018e-02 + <_> + + 0 -1 2337 -7.8999997640494257e-05 + + -3.7749201059341431e-01 1.3961799442768097e-01 + <_> + + 0 -1 2338 -1.1415000073611736e-02 + + -2.6186600327491760e-01 2.3712499439716339e-01 + <_> + + 0 -1 2339 3.7200000137090683e-02 + + -2.8626000508666039e-02 -1.2945239543914795e+00 + <_> + + 0 -1 2340 3.4050000831484795e-03 + + 2.0531399548053741e-01 -1.8747499585151672e-01 + <_> + + 0 -1 2341 -2.2483000531792641e-02 + + 6.7027199268341064e-01 -1.9594000279903412e-01 + <_> + + 0 -1 2342 2.3274999111890793e-02 + + 1.7405399680137634e-01 -3.2746300101280212e-01 + <_> + + 0 -1 2343 -1.3917000032961369e-02 + + -8.3954298496246338e-01 -6.3760001212358475e-03 + <_> + + 0 -1 2344 7.5429999269545078e-03 + + -3.4194998443126678e-02 5.8998197317123413e-01 + <_> + + 0 -1 2345 -1.1539000086486340e-02 + + 4.2142799496650696e-01 -2.3510499298572540e-01 + <_> + + 0 -1 2346 5.2501998841762543e-02 + + 6.9303996860980988e-02 7.3226499557495117e-01 + <_> + + 0 -1 2347 5.2715998142957687e-02 + + -1.5688100457191467e-01 1.0907289981842041e+00 + <_> + + 0 -1 2348 -1.1726000346243382e-02 + + -7.0934301614761353e-01 1.6828800737857819e-01 + <_> + + 0 -1 2349 9.5945999026298523e-02 + + -1.6192899644374847e-01 1.0072519779205322e+00 + <_> + + 0 -1 2350 -1.5871999785304070e-02 + + 3.9008399844169617e-01 -5.3777001798152924e-02 + <_> + + 0 -1 2351 3.4818001091480255e-02 + + 1.7179999500513077e-02 -9.3941801786422729e-01 + <_> + + 0 -1 2352 3.4791998565196991e-02 + + 5.0462998449802399e-02 5.4465699195861816e-01 + <_> + + 0 -1 2353 1.6284000128507614e-02 + + -2.6981300115585327e-01 4.0365299582481384e-01 + <_> + + 0 -1 2354 -4.4319000095129013e-02 + + 8.4399998188018799e-01 3.2882999628782272e-02 + <_> + + 0 -1 2355 -5.5689997971057892e-03 + + 1.5309399366378784e-01 -3.4959799051284790e-01 + <_> + + 0 -1 2356 -6.5842002630233765e-02 + + -9.2711198329925537e-01 1.6800999641418457e-01 + <_> + + 0 -1 2357 -7.3337003588676453e-02 + + 5.1614499092102051e-01 -2.0236000418663025e-01 + <_> + + 0 -1 2358 1.6450000926852226e-02 + + 1.3950599730014801e-01 -4.9301299452781677e-01 + <_> + + 0 -1 2359 -9.2630004510283470e-03 + + -9.0101999044418335e-01 -1.6116000711917877e-02 + <_> + + 0 -1 2360 5.9139998629689217e-03 + + 1.9858199357986450e-01 -1.6731299459934235e-01 + <_> + + 0 -1 2361 -8.4699998842552304e-04 + + 9.4005003571510315e-02 -4.1570898890495300e-01 + <_> + + 0 -1 2362 2.0532900094985962e-01 + + -6.0022000223398209e-02 7.0993602275848389e-01 + <_> + + 0 -1 2363 -1.6883000731468201e-02 + + 2.4392199516296387e-01 -3.0551800131797791e-01 + <_> + + 0 -1 2364 -1.9111000001430511e-02 + + 6.1229902505874634e-01 2.4252999573945999e-02 + <_> + + 0 -1 2365 -2.5962999090552330e-02 + + 9.0764999389648438e-01 -1.6722099483013153e-01 + <_> + + 0 -1 2366 -2.1762000396847725e-02 + + -3.1384700536727905e-01 2.0134599506855011e-01 + <_> + + 0 -1 2367 -2.4119999259710312e-02 + + -6.6588401794433594e-01 7.4559999629855156e-03 + <_> + + 0 -1 2368 4.7129999846220016e-02 + + 5.9533998370170593e-02 8.7804502248764038e-01 + <_> + + 0 -1 2369 -4.5984998345375061e-02 + + 8.0067998170852661e-01 -1.7252300679683685e-01 + <_> + + 0 -1 2370 2.6507999747991562e-02 + + 1.8774099647998810e-01 -6.0850602388381958e-01 + <_> + + 0 -1 2371 -4.8615001142024994e-02 + + 5.8644098043441772e-01 -1.9427700340747833e-01 + <_> + + 0 -1 2372 -1.8562000244855881e-02 + + -2.5587901473045349e-01 1.6326199471950531e-01 + <_> + + 0 -1 2373 1.2678000144660473e-02 + + -1.4228000305593014e-02 -7.6738101243972778e-01 + <_> + + 0 -1 2374 -1.1919999960809946e-03 + + 2.0495000481605530e-01 -1.1404299736022949e-01 + <_> + + 0 -1 2375 -4.9088999629020691e-02 + + -1.0740849971771240e+00 -3.8940999656915665e-02 + <_> + + 0 -1 2376 -1.7436999827623367e-02 + + -5.7973802089691162e-01 1.8584500253200531e-01 + <_> + + 0 -1 2377 -1.4770000241696835e-02 + + -6.6150301694869995e-01 5.3119999356567860e-03 + <_> + + 0 -1 2378 -2.2905200719833374e-01 + + -4.8305100202560425e-01 1.2326399981975555e-01 + <_> + + 0 -1 2379 -1.2707099318504333e-01 + + 5.7452601194381714e-01 -1.9420400261878967e-01 + <_> + + 0 -1 2380 1.0339000262320042e-02 + + -5.4641999304294586e-02 2.4501800537109375e-01 + <_> + + 0 -1 2381 6.9010001607239246e-03 + + 1.2180600315332413e-01 -3.8797399401664734e-01 + <_> + + 0 -1 2382 2.9025399684906006e-01 + + 1.0966199636459351e-01 -30. + <_> + + 0 -1 2383 -2.3804999887943268e-01 + + -1.7352679967880249e+00 -6.3809998333454132e-02 + <_> + + 0 -1 2384 6.2481001019477844e-02 + + 1.3523000478744507e-01 -7.0301097631454468e-01 + <_> + + 0 -1 2385 4.7109997831285000e-03 + + -4.6984100341796875e-01 6.0341998934745789e-02 + <_> + + 0 -1 2386 -2.7815999463200569e-02 + + 6.9807600975036621e-01 1.3719999697059393e-03 + <_> + + 0 -1 2387 -1.7020000144839287e-02 + + 1.6870440244674683e+00 -1.4314800500869751e-01 + <_> + + 0 -1 2388 -4.9754999577999115e-02 + + 7.9497700929641724e-01 7.7199999941512942e-04 + <_> + + 0 -1 2389 -7.4732996523380280e-02 + + -1.0132360458374023e+00 -1.9388999789953232e-02 + <_> + + 0 -1 2390 3.2009001821279526e-02 + + 1.4412100613117218e-01 -4.2139101028442383e-01 + <_> + + 0 -1 2391 -9.4463996589183807e-02 + + 5.0682598352432251e-01 -2.0478899776935577e-01 + <_> + + 0 -1 2392 -1.5426999889314175e-02 + + -1.5811300277709961e-01 1.7806899547576904e-01 + <_> + + 0 -1 2393 -4.0540001355111599e-03 + + -5.4366701841354370e-01 3.1235000118613243e-02 + <_> + + 0 -1 2394 3.0080000869929790e-03 + + -1.7376799881458282e-01 3.0441701412200928e-01 + <_> + + 0 -1 2395 -1.0091999545693398e-02 + + 2.5103801488876343e-01 -2.6224100589752197e-01 + <_> + + 0 -1 2396 -3.8818001747131348e-02 + + 9.3226701021194458e-01 7.2659999132156372e-02 + <_> + + 0 -1 2397 3.4651998430490494e-02 + + -3.3934999257326126e-02 -8.5707902908325195e-01 + <_> + + 0 -1 2398 -4.6729999594390392e-03 + + 3.4969300031661987e-01 -4.8517998307943344e-02 + <_> + + 0 -1 2399 6.8499997723847628e-04 + + 6.6573001444339752e-02 -4.4973799586296082e-01 + <_> + + 0 -1 2400 3.5317000001668930e-02 + + 1.4275799691677094e-01 -4.6726399660110474e-01 + <_> + + 0 -1 2401 -2.3569999262690544e-02 + + -1.0286079645156860e+00 -4.5288000255823135e-02 + <_> + + 0 -1 2402 -1.9109999993816018e-03 + + -1.9652199745178223e-01 2.8661000728607178e-01 + <_> + + 0 -1 2403 -1.6659000888466835e-02 + + -7.7532202005386353e-01 -8.3280000835657120e-03 + <_> + + 0 -1 2404 6.6062200069427490e-01 + + 1.3232499361038208e-01 -3.5266680717468262e+00 + <_> + + 0 -1 2405 1.0970599949359894e-01 + + -1.5547199547290802e-01 1.4674140214920044e+00 + <_> + + 0 -1 2406 1.3500999659299850e-02 + + 1.5233400464057922e-01 -1.3020930290222168e+00 + <_> + + 0 -1 2407 -2.2871999070048332e-02 + + -7.1325999498367310e-01 -8.7040001526474953e-03 + <_> + + 0 -1 2408 -8.1821002066135406e-02 + + 1.1127580404281616e+00 8.3219997584819794e-02 + <_> + + 0 -1 2409 -5.2728001028299332e-02 + + 9.3165099620819092e-01 -1.7103999853134155e-01 + <_> + + 0 -1 2410 -2.5242000818252563e-02 + + -1.9733799993991852e-01 2.5359401106834412e-01 + <_> + + 0 -1 2411 -4.3818999081850052e-02 + + 4.1815200448036194e-01 -2.4585500359535217e-01 + <_> + + 0 -1 2412 -1.8188999965786934e-02 + + -5.1743197441101074e-01 2.0174199342727661e-01 + <_> + + 0 -1 2413 2.3466000333428383e-02 + + -4.3071001768112183e-02 -1.0636579990386963e+00 + <_> + + 0 -1 2414 3.4216001629829407e-02 + + 5.3780999034643173e-02 4.9707201123237610e-01 + <_> + + 0 -1 2415 2.5692999362945557e-02 + + -2.3800100386142731e-01 4.1651499271392822e-01 + <_> + + 0 -1 2416 -2.6565000414848328e-02 + + -8.8574802875518799e-01 1.3365900516510010e-01 + <_> + + 0 -1 2417 6.0942001640796661e-02 + + -2.0669700205326080e-01 5.8309000730514526e-01 + <_> + + 0 -1 2418 1.4474500715732574e-01 + + 1.3282300531864166e-01 -3.1449348926544189e+00 + <_> + + 0 -1 2419 5.3410999476909637e-02 + + -1.7325200140476227e-01 6.9190698862075806e-01 + <_> + + 0 -1 2420 1.1408000253140926e-02 + + 5.4822001606225967e-02 3.0240398645401001e-01 + <_> + + 0 -1 2421 -2.3179999552667141e-03 + + 1.5820899605751038e-01 -3.1973201036453247e-01 + <_> + + 0 -1 2422 -2.9695000499486923e-02 + + 7.1274799108505249e-01 5.8136001229286194e-02 + <_> + + 0 -1 2423 2.7249999344348907e-02 + + -1.5754100680351257e-01 9.2143797874450684e-01 + <_> + + 0 -1 2424 -3.6200000904500484e-03 + + -3.4548398852348328e-01 2.0220999419689178e-01 + <_> + + 0 -1 2425 -1.2578999623656273e-02 + + -5.5650299787521362e-01 2.0388999953866005e-02 + <_> + + 0 -1 2426 -8.8849000632762909e-02 + + -3.6100010871887207e+00 1.3164199888706207e-01 + <_> + + 0 -1 2427 -1.9256999716162682e-02 + + 5.1908999681472778e-01 -1.9284300506114960e-01 + <_> + + 0 -1 2428 -1.6666999086737633e-02 + + -8.7499998509883881e-02 1.5812499821186066e-01 + <_> + + 0 -1 2429 1.2931999750435352e-02 + + 2.7405999600887299e-02 -5.5123901367187500e-01 + <_> + + 0 -1 2430 -1.3431999832391739e-02 + + 2.3457799851894379e-01 -4.3235000222921371e-02 + <_> + + 0 -1 2431 1.8810000270605087e-02 + + -3.9680998772382736e-02 -9.4373297691345215e-01 + <_> + + 0 -1 2432 -6.4349998719990253e-03 + + 4.5703700184822083e-01 -4.0520001202821732e-03 + <_> + + 0 -1 2433 -2.4249000474810600e-02 + + -7.6248002052307129e-01 -1.9857000559568405e-02 + <_> + + 0 -1 2434 -2.9667999595403671e-02 + + -3.7412509918212891e+00 1.1250600218772888e-01 + <_> + + 0 -1 2435 5.1150000654160976e-03 + + -6.3781797885894775e-01 1.1223999783396721e-02 + <_> + + 0 -1 2436 -5.7819997891783714e-03 + + 1.9374400377273560e-01 -8.2042001187801361e-02 + <_> + + 0 -1 2437 1.6606999561190605e-02 + + -1.6192099452018738e-01 1.1334990262985229e+00 + <_> + + 0 -1 2438 3.8228001445531845e-02 + + 2.1105000749230385e-02 7.6264202594757080e-01 + <_> + + 0 -1 2439 -5.7094000279903412e-02 + + -1.6974929571151733e+00 -5.9762001037597656e-02 + <_> + + 0 -1 2440 -5.3883001208305359e-02 + + 1.1850190162658691e+00 9.0966999530792236e-02 + <_> + + 0 -1 2441 -2.6110000908374786e-03 + + -4.0941199660301208e-01 8.3820998668670654e-02 + <_> + + 0 -1 2442 2.9714399576187134e-01 + + 1.5529899299144745e-01 -1.0995409488677979e+00 + <_> + + 0 -1 2443 -8.9063003659248352e-02 + + 4.8947200179100037e-01 -2.0041200518608093e-01 + <_> + + 0 -1 2444 -5.6193001568317413e-02 + + -2.4581399559974670e-01 1.4365500211715698e-01 + <_> + + 0 -1 2445 3.7004999816417694e-02 + + -4.8168998211622238e-02 -1.2310709953308105e+00 + <_> + + 0 -1 2446 -8.4840003401041031e-03 + + 4.3372601270675659e-01 1.3779999688267708e-02 + <_> + + 0 -1 2447 -2.4379999376833439e-03 + + 1.8949699401855469e-01 -3.2294198870658875e-01 + <_> + + 0 -1 2448 -7.1639999747276306e-02 + + -4.3979001045227051e-01 2.2730199992656708e-01 + <_> + + 0 -1 2449 5.2260002121329308e-03 + + -2.0548400282859802e-01 5.0933301448822021e-01 + <_> + + 0 -1 2450 -6.1360001564025879e-03 + + 3.1157198548316956e-01 7.0680998265743256e-02 + <_> + + 0 -1 2451 1.5595000237226486e-02 + + -3.0934798717498779e-01 1.5627700090408325e-01 + <_> + + 0 -1 2452 2.5995999574661255e-02 + + 1.3821600377559662e-01 -1.7616599798202515e-01 + <_> + + 0 -1 2453 -1.2085000053048134e-02 + + -5.1070201396942139e-01 5.8440998196601868e-02 + <_> + + 0 -1 2454 -6.7836001515388489e-02 + + 4.7757101058959961e-01 -7.1446001529693604e-02 + <_> + + 0 -1 2455 -1.4715000055730343e-02 + + 4.5238900184631348e-01 -1.9861400127410889e-01 + <_> + + 0 -1 2456 2.5118999183177948e-02 + + 1.2954899668693542e-01 -8.6266398429870605e-01 + <_> + + 0 -1 2457 1.8826000392436981e-02 + + -4.1570000350475311e-02 -1.1354700326919556e+00 + <_> + + 0 -1 2458 -2.1263999864459038e-02 + + -3.4738001227378845e-01 1.5779499709606171e-01 + <_> + + 0 -1 2459 9.4609996303915977e-03 + + 4.8639997839927673e-03 -6.1654800176620483e-01 + <_> + + 0 -1 2460 2.2957700490951538e-01 + + 8.1372998654842377e-02 6.9841402769088745e-01 + <_> + + 0 -1 2461 -3.8061998784542084e-02 + + 1.1616369485855103e+00 -1.4976699650287628e-01 + <_> + + 0 -1 2462 -1.3484999537467957e-02 + + -3.2036399841308594e-01 1.7365099489688873e-01 + <_> + + 0 -1 2463 3.6238998174667358e-02 + + -1.8158499896526337e-01 6.1956697702407837e-01 + <_> + + 0 -1 2464 6.7210001870989799e-03 + + 7.9600000753998756e-04 4.2441400885581970e-01 + <_> + + 0 -1 2465 9.6525996923446655e-02 + + -1.4696800708770752e-01 1.2525680065155029e+00 + <_> + + 0 -1 2466 -3.5656999796628952e-02 + + -3.9781698584556580e-01 1.4191399514675140e-01 + <_> + + 0 -1 2467 1.0772000066936016e-02 + + -1.8194000422954559e-01 5.9762197732925415e-01 + <_> + + 0 -1 2468 7.9279996454715729e-02 + + 1.4642499387264252e-01 -7.8836899995803833e-01 + <_> + + 0 -1 2469 3.2841000705957413e-02 + + -6.2408000230789185e-02 -1.4227490425109863e+00 + <_> + + 0 -1 2470 -2.7781000360846519e-02 + + 3.4033098816871643e-01 3.0670000240206718e-02 + <_> + + 0 -1 2471 -4.0339999832212925e-03 + + 3.1084701418876648e-01 -2.2595700621604919e-01 + <_> + + 0 -1 2472 7.4260002002120018e-03 + + -3.8936998695135117e-02 3.1702101230621338e-01 + <_> + + 0 -1 2473 1.1213999986648560e-01 + + -1.7578299343585968e-01 6.5056598186492920e-01 + <_> + + 0 -1 2474 -1.1878100037574768e-01 + + -1.0092990398406982e+00 1.1069700121879578e-01 + <_> + + 0 -1 2475 -4.1584998369216919e-02 + + -5.3806400299072266e-01 1.9905000925064087e-02 + <_> + + 0 -1 2476 -2.7966000139713287e-02 + + 4.8143199086189270e-01 3.3590998500585556e-02 + <_> + + 0 -1 2477 -1.2506400048732758e-01 + + 2.6352199912071228e-01 -2.5737899541854858e-01 + <_> + + 0 -1 2478 2.3666900396347046e-01 + + 3.6508001387119293e-02 9.0655601024627686e-01 + <_> + + 0 -1 2479 -2.9475999996066093e-02 + + -6.0048800706863403e-01 9.5880003646016121e-03 + <_> + + 0 -1 2480 3.7792999297380447e-02 + + 1.5506200492382050e-01 -9.5733499526977539e-01 + <_> + + 0 -1 2481 7.2044000029563904e-02 + + -1.4525899291038513e-01 1.3676730394363403e+00 + <_> + + 0 -1 2482 9.7759999334812164e-03 + + 1.2915999628603458e-02 2.1640899777412415e-01 + <_> + + 0 -1 2483 5.2154000848531723e-02 + + -1.6359999775886536e-02 -8.8356298208236694e-01 + <_> + + 0 -1 2484 -4.3790999799966812e-02 + + 3.5829600691795349e-01 6.5131001174449921e-02 + <_> + + 0 -1 2485 -3.8378998637199402e-02 + + 1.1961040496826172e+00 -1.4971500635147095e-01 + <_> + + 0 -1 2486 -9.8838999867439270e-02 + + -6.1834001541137695e-01 1.2786200642585754e-01 + <_> + + 0 -1 2487 -1.2190700322389603e-01 + + -1.8276120424270630e+00 -6.4862996339797974e-02 + <_> + + 0 -1 2488 -1.1981700360774994e-01 + + -30. 1.1323300004005432e-01 + <_> + + 0 -1 2489 3.0910000205039978e-02 + + -2.3934000730514526e-01 3.6332899332046509e-01 + <_> + + 0 -1 2490 1.0800999589264393e-02 + + -3.5140000283718109e-02 2.7707898616790771e-01 + <_> + + 0 -1 2491 5.6844998151063919e-02 + + -1.5524299442768097e-01 1.0802700519561768e+00 + <_> + + 0 -1 2492 1.0280000278726220e-03 + + -6.1202999204397202e-02 2.0508000254631042e-01 + <_> + + 0 -1 2493 -2.8273999691009521e-02 + + -6.4778000116348267e-01 2.3917000740766525e-02 + <_> + + 0 -1 2494 -1.6013599932193756e-01 + + 1.0892050266265869e+00 5.8389000594615936e-02 + <_> + + 0 -1 2495 4.9629998393356800e-03 + + -2.5806298851966858e-01 2.0834599435329437e-01 + <_> + + 0 -1 2496 4.6937000006437302e-02 + + 1.3886299729347229e-01 -1.5662620067596436e+00 + <_> + + 0 -1 2497 2.4286000058054924e-02 + + -2.0728300511837006e-01 5.2430999279022217e-01 + <_> + + 0 -1 2498 7.0202000439167023e-02 + + 1.4796899259090424e-01 -1.3095090389251709e+00 + <_> + + 0 -1 2499 9.8120002076029778e-03 + + 2.7906000614166260e-02 -5.0864601135253906e-01 + <_> + + 0 -1 2500 -5.6200999766588211e-02 + + 1.2618130445480347e+00 6.3801996409893036e-02 + <_> + + 0 -1 2501 1.0982800275087357e-01 + + -1.2850099802017212e-01 3.0776169300079346e+00 + <_> + 211 + -3.3703000545501709e+00 + + <_> + + 0 -1 2502 2.0910000428557396e-02 + + -6.8559402227401733e-01 3.8984298706054688e-01 + <_> + + 0 -1 2503 3.5032000392675400e-02 + + -4.7724398970603943e-01 4.5027199387550354e-01 + <_> + + 0 -1 2504 3.9799001067876816e-02 + + -4.7011101245880127e-01 4.2702499032020569e-01 + <_> + + 0 -1 2505 -4.8409998416900635e-03 + + 2.5614300370216370e-01 -6.6556298732757568e-01 + <_> + + 0 -1 2506 2.3439999204128981e-03 + + -4.8083499073982239e-01 2.8013798594474792e-01 + <_> + + 0 -1 2507 2.5312999263405800e-02 + + -2.3948200047016144e-01 4.4191798567771912e-01 + <_> + + 0 -1 2508 -3.2193001359701157e-02 + + 7.6086699962615967e-01 -2.5059100985527039e-01 + <_> + + 0 -1 2509 7.5409002602100372e-02 + + -3.4974598884582520e-01 3.4380298852920532e-01 + <_> + + 0 -1 2510 -1.8469000235199928e-02 + + -7.9085600376129150e-01 3.4788001328706741e-02 + <_> + + 0 -1 2511 -1.2802000157535076e-02 + + 4.7107800841331482e-01 -6.0006000101566315e-02 + <_> + + 0 -1 2512 -2.6598000898957253e-02 + + 6.7116099596023560e-01 -2.4257500469684601e-01 + <_> + + 0 -1 2513 2.1988999098539352e-02 + + 2.4717499315738678e-01 -4.8301699757575989e-01 + <_> + + 0 -1 2514 1.4654099941253662e-01 + + -2.1504099667072296e-01 7.2055900096893311e-01 + <_> + + 0 -1 2515 3.5310001112520695e-03 + + 2.7930998802185059e-01 -3.4339898824691772e-01 + <_> + + 0 -1 2516 9.4010001048445702e-03 + + 5.5861998349428177e-02 -8.2143598794937134e-01 + <_> + + 0 -1 2517 -8.6390003561973572e-03 + + -9.9620598554611206e-01 1.8874999880790710e-01 + <_> + + 0 -1 2518 -3.9193000644445419e-02 + + -1.1945559978485107e+00 -2.9198000207543373e-02 + <_> + + 0 -1 2519 2.4855000898241997e-02 + + 1.4987599849700928e-01 -5.4137802124023438e-01 + <_> + + 0 -1 2520 -3.4995000809431076e-02 + + -1.4210180044174194e+00 -4.2314000427722931e-02 + <_> + + 0 -1 2521 -1.8378999084234238e-02 + + -2.8242599964141846e-01 1.5581800043582916e-01 + <_> + + 0 -1 2522 -1.3592000119388103e-02 + + 4.7317099571228027e-01 -2.1937200427055359e-01 + <_> + + 0 -1 2523 6.2629999592900276e-03 + + -5.9714000672101974e-02 6.0625898838043213e-01 + <_> + + 0 -1 2524 -1.8478000536561012e-02 + + -8.5647201538085938e-01 -1.3783999718725681e-02 + <_> + + 0 -1 2525 1.4236000366508961e-02 + + 1.6654799878597260e-01 -2.7713999152183533e-01 + <_> + + 0 -1 2526 -3.2547000795602798e-02 + + -1.1728240251541138e+00 -4.0185000747442245e-02 + <_> + + 0 -1 2527 -2.6410000864416361e-03 + + 2.6514300704002380e-01 -5.6343000382184982e-02 + <_> + + 0 -1 2528 -8.7799999164417386e-04 + + 3.6556001752614975e-02 -5.5075198411941528e-01 + <_> + + 0 -1 2529 4.7371998429298401e-02 + + -4.2614001780748367e-02 4.8194900155067444e-01 + <_> + + 0 -1 2530 -7.0790001191198826e-03 + + 2.8698998689651489e-01 -3.2923001050949097e-01 + <_> + + 0 -1 2531 -4.3145999312400818e-02 + + -1.4065419435501099e+00 1.2836399674415588e-01 + <_> + + 0 -1 2532 2.0592000335454941e-02 + + -2.1435299515724182e-01 5.3981798887252808e-01 + <_> + + 0 -1 2533 -2.2367000579833984e-02 + + 3.3718299865722656e-01 4.5212000608444214e-02 + <_> + + 0 -1 2534 5.0039999186992645e-02 + + -2.5121700763702393e-01 4.1750499606132507e-01 + <_> + + 0 -1 2535 6.1794999986886978e-02 + + 4.0084999054670334e-02 6.8779802322387695e-01 + <_> + + 0 -1 2536 -4.1861999779939651e-02 + + 5.3027397394180298e-01 -2.2901999950408936e-01 + <_> + + 0 -1 2537 -3.1959998887032270e-03 + + 2.5161498785018921e-01 -2.1514600515365601e-01 + <_> + + 0 -1 2538 2.4255000054836273e-02 + + 7.2320001199841499e-03 -7.2519099712371826e-01 + <_> + + 0 -1 2539 -1.7303999513387680e-02 + + -4.9958199262619019e-01 1.8394500017166138e-01 + <_> + + 0 -1 2540 -4.1470001451671124e-03 + + 8.5211999714374542e-02 -4.6364700794219971e-01 + <_> + + 0 -1 2541 -1.4369999989867210e-02 + + -5.2258902788162231e-01 2.3892599344253540e-01 + <_> + + 0 -1 2542 -9.0399999171495438e-03 + + -6.3250398635864258e-01 3.2551001757383347e-02 + <_> + + 0 -1 2543 -1.2373100221157074e-01 + + 1.2856210470199585e+00 7.6545000076293945e-02 + <_> + + 0 -1 2544 -8.2221999764442444e-02 + + 8.3208197355270386e-01 -1.8590599298477173e-01 + <_> + + 0 -1 2545 6.5659001469612122e-02 + + 1.1298800259828568e-01 -30. + <_> + + 0 -1 2546 -3.1582999974489212e-02 + + -1.3485900163650513e+00 -4.7097001224756241e-02 + <_> + + 0 -1 2547 -7.9636000096797943e-02 + + -1.3533639907836914e+00 1.5668800473213196e-01 + <_> + + 0 -1 2548 -1.8880000337958336e-02 + + 4.0300300717353821e-01 -2.5148901343345642e-01 + <_> + + 0 -1 2549 -5.0149997696280479e-03 + + -2.6287099719047546e-01 1.8582500517368317e-01 + <_> + + 0 -1 2550 -1.2218000367283821e-02 + + 5.8692401647567749e-01 -1.9427700340747833e-01 + <_> + + 0 -1 2551 1.2710000155493617e-03 + + -1.6688999533653259e-01 2.3006899654865265e-01 + <_> + + 0 -1 2552 2.9743999242782593e-02 + + 1.2520000338554382e-02 -6.6723597049713135e-01 + <_> + + 0 -1 2553 2.8175000101327896e-02 + + -1.7060000449419022e-02 6.4579397439956665e-01 + <_> + + 0 -1 2554 3.0345000326633453e-02 + + -2.4178700149059296e-01 3.4878900647163391e-01 + <_> + + 0 -1 2555 -1.7325999215245247e-02 + + -5.3599399328231812e-01 2.0995999872684479e-01 + <_> + + 0 -1 2556 -8.4178000688552856e-02 + + 7.5093299150466919e-01 -1.7593200504779816e-01 + <_> + + 0 -1 2557 7.4950000271201134e-03 + + -1.6188099980354309e-01 3.0657500028610229e-01 + <_> + + 0 -1 2558 5.6494999676942825e-02 + + -1.7318800091743469e-01 1.0016150474548340e+00 + <_> + + 0 -1 2559 -5.2939997985959053e-03 + + 2.3417599499225616e-01 -6.5347000956535339e-02 + <_> + + 0 -1 2560 -1.4945000410079956e-02 + + 2.5018900632858276e-01 -3.0591198801994324e-01 + <_> + + 0 -1 2561 5.4919000715017319e-02 + + 1.3121999800205231e-01 -9.3765097856521606e-01 + <_> + + 0 -1 2562 -1.9721999764442444e-02 + + -8.3978497982025146e-01 -2.3473000153899193e-02 + <_> + + 0 -1 2563 -6.7158997058868408e-02 + + 2.3586840629577637e+00 8.2970999181270599e-02 + <_> + + 0 -1 2564 -1.4325999654829502e-02 + + 1.8814499676227570e-01 -3.1221601366996765e-01 + <_> + + 0 -1 2565 2.9841000214219093e-02 + + 1.4825099706649780e-01 -8.4681701660156250e-01 + <_> + + 0 -1 2566 5.1883000880479813e-02 + + -4.3731000274419785e-02 -1.3366169929504395e+00 + <_> + + 0 -1 2567 4.1127000004053116e-02 + + 1.7660099267959595e-01 -6.0904097557067871e-01 + <_> + + 0 -1 2568 -1.2865099310874939e-01 + + -9.8701000213623047e-01 -3.7785001099109650e-02 + <_> + + 0 -1 2569 2.4170000106096268e-03 + + -1.6119599342346191e-01 3.2675701379776001e-01 + <_> + + 0 -1 2570 7.7030002139508724e-03 + + -2.3841500282287598e-01 2.9319399595260620e-01 + <_> + + 0 -1 2571 4.5520000159740448e-02 + + 1.4424599707126617e-01 -1.5010160207748413e+00 + <_> + + 0 -1 2572 -7.8700996935367584e-02 + + -1.0394560098648071e+00 -4.5375999063253403e-02 + <_> + + 0 -1 2573 7.8619997948408127e-03 + + 1.9633600115776062e-01 -1.4472399652004242e-01 + <_> + + 0 -1 2574 -1.3458999805152416e-02 + + -9.0634697675704956e-01 -3.8049001246690750e-02 + <_> + + 0 -1 2575 2.8827000409364700e-02 + + -2.9473999515175819e-02 6.0058397054672241e-01 + <_> + + 0 -1 2576 -2.7365999296307564e-02 + + -9.9804002046585083e-01 -3.8653001189231873e-02 + <_> + + 0 -1 2577 -7.2917997837066650e-02 + + 7.3361498117446899e-01 5.7440001517534256e-02 + <_> + + 0 -1 2578 -1.3988999649882317e-02 + + 2.7892601490020752e-01 -2.6516300439834595e-01 + <_> + + 0 -1 2579 4.3242998421192169e-02 + + 4.7760000452399254e-03 3.5925900936126709e-01 + <_> + + 0 -1 2580 2.9533000662922859e-02 + + -2.0083999633789062e-01 5.1202899217605591e-01 + <_> + + 0 -1 2581 -3.1897000968456268e-02 + + 6.4721697568893433e-01 -1.3760000001639128e-03 + <_> + + 0 -1 2582 3.7868998944759369e-02 + + -1.8363800644874573e-01 6.1343097686767578e-01 + <_> + + 0 -1 2583 -2.2417999804019928e-02 + + -2.9187899827957153e-01 1.8194800615310669e-01 + <_> + + 0 -1 2584 5.8958999812602997e-02 + + -6.6451996564865112e-02 -1.9290030002593994e+00 + <_> + + 0 -1 2585 3.1222999095916748e-02 + + -1.2732000090181828e-02 6.1560797691345215e-01 + <_> + + 0 -1 2586 3.7484999746084213e-02 + + -2.0856900513172150e-01 4.4363999366760254e-01 + <_> + + 0 -1 2587 -2.0966000854969025e-02 + + -3.5712799429893494e-01 2.4252200126647949e-01 + <_> + + 0 -1 2588 -2.5477999821305275e-02 + + 1.0846560001373291e+00 -1.5054400265216827e-01 + <_> + + 0 -1 2589 -7.2570000775158405e-03 + + 2.1302600204944611e-01 -1.8308199942111969e-01 + <_> + + 0 -1 2590 -5.0983000546693802e-02 + + 5.1736801862716675e-01 -1.8833099305629730e-01 + <_> + + 0 -1 2591 -2.0640000700950623e-02 + + -4.4030201435089111e-01 2.2745999693870544e-01 + <_> + + 0 -1 2592 1.0672999545931816e-02 + + 3.5059999674558640e-02 -5.1665002107620239e-01 + <_> + + 0 -1 2593 3.1895998865365982e-02 + + 1.3228000141680241e-02 3.4915199875831604e-01 + <_> + + 0 -1 2594 -2.3824999108910561e-02 + + 3.4118801355361938e-01 -2.1510200202465057e-01 + <_> + + 0 -1 2595 -6.0680001042783260e-03 + + 3.2937398552894592e-01 -2.8523799777030945e-01 + <_> + + 0 -1 2596 2.3881999775767326e-02 + + -2.5333800911903381e-01 2.6296100020408630e-01 + <_> + + 0 -1 2597 2.7966000139713287e-02 + + 1.4049099385738373e-01 -4.9887099862098694e-01 + <_> + + 0 -1 2598 1.4603000134229660e-02 + + -1.5395999886095524e-02 -7.6958000659942627e-01 + <_> + + 0 -1 2599 1.0872399806976318e-01 + + 1.9069600105285645e-01 -3.2393100857734680e-01 + <_> + + 0 -1 2600 -1.4038000255823135e-02 + + 3.4924700856208801e-01 -2.2358700633049011e-01 + <_> + + 0 -1 2601 4.0440000593662262e-03 + + -3.8329001516103745e-02 5.1177299022674561e-01 + <_> + + 0 -1 2602 -4.9769999459385872e-03 + + -4.2888298630714417e-01 4.9173999577760696e-02 + <_> + + 0 -1 2603 -8.5183002054691315e-02 + + 6.6624599695205688e-01 7.8079998493194580e-03 + <_> + + 0 -1 2604 2.1559998858720064e-03 + + -4.9135199189186096e-01 6.9555997848510742e-02 + <_> + + 0 -1 2605 3.6384499073028564e-01 + + 1.2997099757194519e-01 -1.8949509859085083e+00 + <_> + + 0 -1 2606 2.2082500159740448e-01 + + -5.7211998850107193e-02 -1.4281120300292969e+00 + <_> + + 0 -1 2607 -1.6140000894665718e-02 + + -5.7589399814605713e-01 1.8062500655651093e-01 + <_> + + 0 -1 2608 -4.8330001533031464e-02 + + 9.7308498620986938e-01 -1.6513000428676605e-01 + <_> + + 0 -1 2609 1.7529999837279320e-02 + + 1.7932699620723724e-01 -2.7948901057243347e-01 + <_> + + 0 -1 2610 -3.4309998154640198e-02 + + -8.1072497367858887e-01 -1.6596000641584396e-02 + <_> + + 0 -1 2611 -4.5830002054572105e-03 + + 2.7908998727798462e-01 -7.4519999325275421e-03 + <_> + + 0 -1 2612 1.2896400690078735e-01 + + -1.3508500158786774e-01 2.5411539077758789e+00 + <_> + + 0 -1 2613 3.0361000448465347e-02 + + -6.8419001996517181e-02 2.8734099864959717e-01 + <_> + + 0 -1 2614 4.4086001813411713e-02 + + -1.8135899305343628e-01 6.5413200855255127e-01 + <_> + + 0 -1 2615 3.0159999150782824e-03 + + -1.5690499544143677e-01 2.6963800191879272e-01 + <_> + + 0 -1 2616 -2.6336999610066414e-02 + + 2.9175600409507751e-01 -2.5274100899696350e-01 + <_> + + 0 -1 2617 -2.7866000309586525e-02 + + 4.4387501478195190e-01 5.5038001388311386e-02 + <_> + + 0 -1 2618 1.1725000105798244e-02 + + -1.9346499443054199e-01 4.6656700968742371e-01 + <_> + + 0 -1 2619 1.5689999563619494e-03 + + -8.2360003143548965e-03 2.5700899958610535e-01 + <_> + + 0 -1 2620 -3.5550000611692667e-03 + + -4.2430898547172546e-01 7.1174003183841705e-02 + <_> + + 0 -1 2621 -3.1695000827312469e-02 + + -8.5393500328063965e-01 1.6916200518608093e-01 + <_> + + 0 -1 2622 -3.2097000628709793e-02 + + 8.3784902095794678e-01 -1.7597299814224243e-01 + <_> + + 0 -1 2623 1.5544199943542480e-01 + + 9.9550001323223114e-02 2.3873300552368164e+00 + <_> + + 0 -1 2624 8.8045999407768250e-02 + + -1.8725299835205078e-01 6.2384301424026489e-01 + <_> + + 0 -1 2625 -1.6720000421628356e-03 + + 2.5008699297904968e-01 -6.5118998289108276e-02 + <_> + + 0 -1 2626 9.3409996479749680e-03 + + -3.5378900170326233e-01 1.0715000331401825e-01 + <_> + + 0 -1 2627 3.7138000130653381e-02 + + 1.6387000679969788e-01 -9.1718399524688721e-01 + <_> + + 0 -1 2628 8.0183997750282288e-02 + + -1.4812999963760376e-01 1.4895190000534058e+00 + <_> + + 0 -1 2629 -7.9100002767518163e-04 + + -2.1326899528503418e-01 1.9676400721073151e-01 + <_> + + 0 -1 2630 -5.0400001928210258e-03 + + -7.1318697929382324e-01 1.8240000354126096e-03 + <_> + + 0 -1 2631 1.1962399631738663e-01 + + 3.3098999410867691e-02 1.0441709756851196e+00 + <_> + + 0 -1 2632 -4.5280000194907188e-03 + + -2.7308499813079834e-01 2.7229800820350647e-01 + <_> + + 0 -1 2633 -2.9639000073075294e-02 + + 3.6225798726081848e-01 5.6795001029968262e-02 + <_> + + 0 -1 2634 2.6650000363588333e-02 + + -4.8041000962257385e-02 -9.6723502874374390e-01 + <_> + + 0 -1 2635 4.4422000646591187e-02 + + 1.3052900135517120e-01 -3.5077300667762756e-01 + <_> + + 0 -1 2636 -2.4359999224543571e-02 + + -1.0766899585723877e+00 -5.1222998648881912e-02 + <_> + + 0 -1 2637 1.9734999164938927e-02 + + 2.6238000020384789e-02 2.8070500493049622e-01 + <_> + + 0 -1 2638 5.4930001497268677e-03 + + -2.6111298799514771e-01 2.1011400222778320e-01 + <_> + + 0 -1 2639 -2.3200300335884094e-01 + + -1.7748440504074097e+00 1.1482600122690201e-01 + <_> + + 0 -1 2640 -2.5614000856876373e-02 + + 2.9900801181793213e-01 -2.2502499818801880e-01 + <_> + + 0 -1 2641 -6.4949998632073402e-03 + + 1.9563800096511841e-01 -9.9762998521327972e-02 + <_> + + 0 -1 2642 3.9840000681579113e-03 + + -4.3021500110626221e-01 8.1261001527309418e-02 + <_> + + 0 -1 2643 -3.5813000053167343e-02 + + -5.0987398624420166e-01 1.6345900297164917e-01 + <_> + + 0 -1 2644 -1.4169000089168549e-02 + + 7.7978098392486572e-01 -1.7476299405097961e-01 + <_> + + 0 -1 2645 -1.2642100453376770e-01 + + -6.3047897815704346e-01 1.2728300690650940e-01 + <_> + + 0 -1 2646 6.8677999079227448e-02 + + -4.6447999775409698e-02 -1.1128979921340942e+00 + <_> + + 0 -1 2647 8.5864998400211334e-02 + + 1.1835400015115738e-01 -4.8235158920288086e+00 + <_> + + 0 -1 2648 1.5511999838054180e-02 + + -1.7467999830842018e-02 -6.3693398237228394e-01 + <_> + + 0 -1 2649 8.1091001629829407e-02 + + 8.6133003234863281e-02 2.4559431076049805e+00 + <_> + + 0 -1 2650 1.8495000898838043e-02 + + 4.0229000151157379e-02 -5.0858199596405029e-01 + <_> + + 0 -1 2651 -8.6320996284484863e-02 + + -1.9006760120391846e+00 1.1019100248813629e-01 + <_> + + 0 -1 2652 7.2355002164840698e-02 + + -6.2111999839544296e-02 -1.4165179729461670e+00 + <_> + + 0 -1 2653 -7.8179001808166504e-02 + + 8.8849300146102905e-01 4.2369998991489410e-02 + <_> + + 0 -1 2654 9.6681997179985046e-02 + + -2.2094200551509857e-01 3.3575099706649780e-01 + <_> + + 0 -1 2655 -3.9875999093055725e-02 + + 5.7804799079895020e-01 4.5347999781370163e-02 + <_> + + 0 -1 2656 -9.5349997282028198e-03 + + -5.4175698757171631e-01 3.2399999909102917e-03 + <_> + + 0 -1 2657 4.0600000647827983e-04 + + -8.1549003720283508e-02 3.5837900638580322e-01 + <_> + + 0 -1 2658 1.2107999995350838e-02 + + -2.0280399918556213e-01 4.3768000602722168e-01 + <_> + + 0 -1 2659 -2.0873999223113060e-02 + + 4.1469898819923401e-01 -4.5568000525236130e-02 + <_> + + 0 -1 2660 5.7888001203536987e-02 + + -2.9009999707341194e-02 -9.1822302341461182e-01 + <_> + + 0 -1 2661 1.3200000103097409e-04 + + -1.1772400140762329e-01 2.0000000298023224e-01 + <_> + + 0 -1 2662 -1.7137000337243080e-02 + + 3.3004799485206604e-01 -2.3055200278759003e-01 + <_> + + 0 -1 2663 3.0655000358819962e-02 + + -2.1545000374317169e-02 2.6878198981285095e-01 + <_> + + 0 -1 2664 -7.8699999721720815e-04 + + -4.4100698828697205e-01 4.9157999455928802e-02 + <_> + + 0 -1 2665 8.8036999106407166e-02 + + 1.1782000213861465e-01 -2.8293309211730957e+00 + <_> + + 0 -1 2666 -3.9028998464345932e-02 + + 9.1777199506759644e-01 -1.5827399492263794e-01 + <_> + + 0 -1 2667 8.0105997622013092e-02 + + 1.1289200186729431e-01 -1.9937280416488647e+00 + <_> + + 0 -1 2668 3.9538998156785965e-02 + + -1.4357399940490723e-01 1.3085240125656128e+00 + <_> + + 0 -1 2669 2.0684000104665756e-02 + + 2.0048099756240845e-01 -4.4186998158693314e-02 + <_> + + 0 -1 2670 -6.7037999629974365e-02 + + 3.2618600130081177e-01 -2.0550400018692017e-01 + <_> + + 0 -1 2671 4.6815000474452972e-02 + + 1.5825299918651581e-01 -9.5535099506378174e-01 + <_> + + 0 -1 2672 7.8443996608257294e-02 + + -7.4651002883911133e-02 -2.1161499023437500e+00 + <_> + + 0 -1 2673 6.6380001604557037e-02 + + 1.1641900241374969e-01 -1.6113519668579102e+00 + <_> + + 0 -1 2674 3.0053999274969101e-02 + + -1.6562600433826447e-01 7.0025402307510376e-01 + <_> + + 0 -1 2675 1.7119999974966049e-02 + + 2.2627699375152588e-01 -4.0114998817443848e-01 + <_> + + 0 -1 2676 2.0073000341653824e-02 + + -1.9389699399471283e-01 4.4420298933982849e-01 + <_> + + 0 -1 2677 3.3101998269557953e-02 + + 1.1637499928474426e-01 -1.5771679878234863e+00 + <_> + + 0 -1 2678 -1.4882000163197517e-02 + + -8.9680302143096924e-01 -4.2010001838207245e-02 + <_> + + 0 -1 2679 -1.0281000286340714e-02 + + 3.5602998733520508e-01 -1.3124000281095505e-02 + <_> + + 0 -1 2680 -2.8695000335574150e-02 + + -4.6039599180221558e-01 2.6801999658346176e-02 + <_> + + 0 -1 2681 -4.7189998440444469e-03 + + 2.3788799345493317e-01 -6.5518997609615326e-02 + <_> + + 0 -1 2682 3.2201600074768066e-01 + + -2.8489999473094940e-02 -8.4234601259231567e-01 + <_> + + 0 -1 2683 -1.7045000568032265e-02 + + -5.0938802957534790e-01 1.6057600080966949e-01 + <_> + + 0 -1 2684 -7.3469998314976692e-03 + + -5.4154998064041138e-01 4.7320001758635044e-03 + <_> + + 0 -1 2685 -3.0001999810338020e-02 + + -8.8785797357559204e-01 1.3621799647808075e-01 + <_> + + 0 -1 2686 -1.1292999610304832e-02 + + 8.0615198612213135e-01 -1.6159500181674957e-01 + <_> + + 0 -1 2687 4.7749998047947884e-03 + + 1.2968000024557114e-02 5.5079901218414307e-01 + <_> + + 0 -1 2688 5.0710001960396767e-03 + + -4.5728001743555069e-02 -1.0766259431838989e+00 + <_> + + 0 -1 2689 1.9344100356101990e-01 + + 7.1262001991271973e-02 1.1694519519805908e+00 + <_> + + 0 -1 2690 5.3750001825392246e-03 + + -1.9736200571060181e-01 3.8206899166107178e-01 + <_> + + 0 -1 2691 -6.8276003003120422e-02 + + -5.4372339248657227e+00 1.1151900142431259e-01 + <_> + + 0 -1 2692 -3.4933000802993774e-02 + + 4.4793400168418884e-01 -1.8657900393009186e-01 + <_> + + 0 -1 2693 5.1219998858869076e-03 + + -1.4871999621391296e-02 1.8413899838924408e-01 + <_> + + 0 -1 2694 9.5311999320983887e-02 + + -1.5117099881172180e-01 9.4991499185562134e-01 + <_> + + 0 -1 2695 -6.2849000096321106e-02 + + 4.6473601460456848e-01 3.8405001163482666e-02 + <_> + + 0 -1 2696 -1.7040699720382690e-01 + + -1.6499999761581421e+00 -6.3236996531486511e-02 + <_> + + 0 -1 2697 1.0583999566733837e-02 + + -3.8348998874425888e-02 4.1913801431655884e-01 + <_> + + 0 -1 2698 -4.1579000651836395e-02 + + 3.4461900591850281e-01 -2.1187700331211090e-01 + <_> + + 0 -1 2699 1.2718600034713745e-01 + + 1.2398199737071991e-01 -2.1254889965057373e+00 + <_> + + 0 -1 2700 8.2557000219821930e-02 + + -6.2024001032114029e-02 -1.4875819683074951e+00 + <_> + + 0 -1 2701 8.5293002426624298e-02 + + 1.7087999731302261e-02 3.2076600193977356e-01 + <_> + + 0 -1 2702 5.5544000118970871e-02 + + -2.7414000034332275e-01 1.8976399302482605e-01 + <_> + + 0 -1 2703 4.5650000683963299e-03 + + -1.7920200526714325e-01 2.7967301011085510e-01 + <_> + + 0 -1 2704 1.2997999787330627e-02 + + -3.2297500967979431e-01 2.6941800117492676e-01 + <_> + + 0 -1 2705 5.7891998440027237e-02 + + 1.2644399702548981e-01 -6.0713499784469604e-01 + <_> + + 0 -1 2706 -2.2824000567197800e-02 + + -4.9682098627090454e-01 2.2376999258995056e-02 + <_> + + 0 -1 2707 4.8312000930309296e-02 + + 4.3607000261545181e-02 4.8537799715995789e-01 + <_> + + 0 -1 2708 2.5714000687003136e-02 + + -4.2950998991727829e-02 -9.3023502826690674e-01 + <_> + + 0 -1 2709 6.9269998930394650e-03 + + -2.9680000152438879e-03 3.4296301007270813e-01 + <_> + + 0 -1 2710 -3.4446999430656433e-02 + + -1.5299769639968872e+00 -6.1014998704195023e-02 + <_> + + 0 -1 2711 2.9387999325990677e-02 + + 3.7595998495817184e-02 6.4172399044036865e-01 + <_> + + 0 -1 2712 -2.4319998919963837e-03 + + 9.9088996648788452e-02 -3.9688101410865784e-01 + <_> + 200 + -2.9928278923034668e+00 + + <_> + + 0 -1 2713 -9.5944002270698547e-02 + + 6.2419098615646362e-01 -4.5875200629234314e-01 + <_> + + 0 -1 2714 1.6834000125527382e-02 + + -9.3072801828384399e-01 2.1563600003719330e-01 + <_> + + 0 -1 2715 2.6049999520182610e-02 + + -4.0532299876213074e-01 4.2256599664688110e-01 + <_> + + 0 -1 2716 3.6500001442618668e-04 + + 9.5288001000881195e-02 -6.3298100233078003e-01 + <_> + + 0 -1 2717 -6.6940002143383026e-03 + + 3.7243801355361938e-01 -3.0332401394844055e-01 + <_> + + 0 -1 2718 1.8874000757932663e-02 + + -2.3357200622558594e-01 4.0330699086189270e-01 + <_> + + 0 -1 2719 -1.6300000424962491e-04 + + 4.2886998504400253e-02 -7.7796798944473267e-01 + <_> + + 0 -1 2720 -7.6259002089500427e-02 + + -4.9628499150276184e-01 1.6335399448871613e-01 + <_> + + 0 -1 2721 5.0149001181125641e-02 + + 3.2747000455856323e-02 -8.0047899484634399e-01 + <_> + + 0 -1 2722 -2.9239999130368233e-03 + + -5.0002801418304443e-01 2.5480601191520691e-01 + <_> + + 0 -1 2723 1.6243999823927879e-02 + + 3.8913000375032425e-02 -7.0724898576736450e-01 + <_> + + 0 -1 2724 3.7811998277902603e-02 + + -6.6267997026443481e-02 7.3868799209594727e-01 + <_> + + 0 -1 2725 -1.2319999746978283e-02 + + 4.8696398735046387e-01 -2.4485599994659424e-01 + <_> + + 0 -1 2726 5.8003999292850494e-02 + + 1.3459099829196930e-01 -1.3232100009918213e-01 + <_> + + 0 -1 2727 4.8630000092089176e-03 + + -4.4172900915145874e-01 1.4005599915981293e-01 + <_> + + 0 -1 2728 4.5690998435020447e-02 + + 3.1217999756336212e-02 8.9818298816680908e-01 + <_> + + 0 -1 2729 2.1321000531315804e-02 + + 1.2008000165224075e-02 -8.6066198348999023e-01 + <_> + + 0 -1 2730 1.5679100155830383e-01 + + 1.4055999927222729e-02 8.5332900285720825e-01 + <_> + + 0 -1 2731 -1.0328999720513821e-02 + + 2.9022800922393799e-01 -2.9478800296783447e-01 + <_> + + 0 -1 2732 2.4290001019835472e-03 + + -4.0439900755882263e-01 1.9400200247764587e-01 + <_> + + 0 -1 2733 -2.3338999599218369e-02 + + 3.2945200800895691e-01 -2.5712698698043823e-01 + <_> + + 0 -1 2734 -6.8970001302659512e-03 + + -5.3352999687194824e-01 2.1635200083255768e-01 + <_> + + 0 -1 2735 -3.4403000026941299e-02 + + -1.4425489902496338e+00 -4.4682998210191727e-02 + <_> + + 0 -1 2736 -2.1235000342130661e-02 + + -7.9017502069473267e-01 1.9084100425243378e-01 + <_> + + 0 -1 2737 2.0620001014322042e-03 + + -2.6931199431419373e-01 3.1488001346588135e-01 + <_> + + 0 -1 2738 -4.2190002277493477e-03 + + -5.4464399814605713e-01 1.6574600338935852e-01 + <_> + + 0 -1 2739 -1.4334999956190586e-02 + + 2.2105000913143158e-02 -6.2342500686645508e-01 + <_> + + 0 -1 2740 -8.2120001316070557e-03 + + -4.9884998798370361e-01 1.9237099587917328e-01 + <_> + + 0 -1 2741 -9.3350000679492950e-03 + + -7.9131197929382324e-01 -1.4143999665975571e-02 + <_> + + 0 -1 2742 -3.7937998771667480e-02 + + 7.9841297864913940e-01 -3.3799000084400177e-02 + <_> + + 0 -1 2743 4.7059999778866768e-03 + + -3.3163401484489441e-01 2.0726299285888672e-01 + <_> + + 0 -1 2744 -4.4499998912215233e-03 + + -2.7256301045417786e-01 1.8402199447154999e-01 + <_> + + 0 -1 2745 5.2189999260008335e-03 + + -5.3096002340316772e-01 5.2607998251914978e-02 + <_> + + 0 -1 2746 -9.5399999991059303e-03 + + -5.6485402584075928e-01 1.9269399344921112e-01 + <_> + + 0 -1 2747 4.4969998300075531e-02 + + -1.7411500215530396e-01 9.5382601022720337e-01 + <_> + + 0 -1 2748 1.4209000393748283e-02 + + -9.1949000954627991e-02 2.4836100637912750e-01 + <_> + + 0 -1 2749 1.6380199790000916e-01 + + -5.8497000485658646e-02 -1.6404409408569336e+00 + <_> + + 0 -1 2750 2.5579999200999737e-03 + + 2.3447999358177185e-01 -9.2734001576900482e-02 + <_> + + 0 -1 2751 -3.8499999791383743e-03 + + 1.7880700528621674e-01 -3.5844099521636963e-01 + <_> + + 0 -1 2752 -2.5221999734640121e-02 + + -4.2903000116348267e-01 2.0244500041007996e-01 + <_> + + 0 -1 2753 -1.9415000453591347e-02 + + 5.8016300201416016e-01 -1.8806399405002594e-01 + <_> + + 0 -1 2754 1.4419999904930592e-02 + + 3.2846998423337936e-02 8.1980502605438232e-01 + <_> + + 0 -1 2755 5.1582999527454376e-02 + + 6.9176003336906433e-02 -4.5866298675537109e-01 + <_> + + 0 -1 2756 -3.7960000336170197e-02 + + -1.2553000450134277e+00 1.4332899451255798e-01 + <_> + + 0 -1 2757 -2.9560999944806099e-02 + + 5.3151798248291016e-01 -2.0596499741077423e-01 + <_> + + 0 -1 2758 -3.9110999554395676e-02 + + 1.1658719778060913e+00 5.3897000849246979e-02 + <_> + + 0 -1 2759 -2.9159000143408775e-02 + + 3.9307600259780884e-01 -2.2184500098228455e-01 + <_> + + 0 -1 2760 -8.3617001771926880e-02 + + -7.3744499683380127e-01 1.4268200099468231e-01 + <_> + + 0 -1 2761 4.2004001140594482e-01 + + -1.4277400076389313e-01 1.7894840240478516e+00 + <_> + + 0 -1 2762 6.0005001723766327e-02 + + 1.1976700276136398e-01 -1.8886189460754395e+00 + <_> + + 0 -1 2763 -1.8981000408530235e-02 + + -1.4148449897766113e+00 -5.6522998958826065e-02 + <_> + + 0 -1 2764 -6.0049998573958874e-03 + + 4.4170799851417542e-01 -1.0200800001621246e-01 + <_> + + 0 -1 2765 -5.8214001357555389e-02 + + -1.3918470144271851e+00 -4.8268999904394150e-02 + <_> + + 0 -1 2766 -1.2271000072360039e-02 + + 5.1317697763442993e-01 -9.3696996569633484e-02 + <_> + + 0 -1 2767 4.6585999429225922e-02 + + -5.7484000921249390e-02 -1.4283169507980347e+00 + <_> + + 0 -1 2768 1.2110000243410468e-03 + + -8.0891996622085571e-02 3.2333201169967651e-01 + <_> + + 0 -1 2769 -8.8642001152038574e-02 + + -8.6449098587036133e-01 -3.3146999776363373e-02 + <_> + + 0 -1 2770 -2.3184999823570251e-02 + + 5.2162200212478638e-01 -1.6168000176548958e-02 + <_> + + 0 -1 2771 4.3090000748634338e-02 + + -1.6153800487518311e-01 1.0915000438690186e+00 + <_> + + 0 -1 2772 2.0599999697878957e-04 + + -1.7091499269008636e-01 3.1236699223518372e-01 + <_> + + 0 -1 2773 8.9159999042749405e-03 + + -6.7039998248219490e-03 -6.8810397386550903e-01 + <_> + + 0 -1 2774 -1.7752999439835548e-02 + + 6.3292801380157471e-01 -4.2360001243650913e-03 + <_> + + 0 -1 2775 6.2299999408423901e-03 + + -3.3637198805809021e-01 1.2790599465370178e-01 + <_> + + 0 -1 2776 2.2770000621676445e-02 + + -3.4703999757766724e-02 3.9141800999641418e-01 + <_> + + 0 -1 2777 -2.1534999832510948e-02 + + 6.4765101671218872e-01 -2.0097799599170685e-01 + <_> + + 0 -1 2778 6.1758998781442642e-02 + + 5.4297000169754028e-02 9.0700101852416992e-01 + <_> + + 0 -1 2779 -7.8069999814033508e-02 + + 6.5523397922515869e-01 -1.9754399359226227e-01 + <_> + + 0 -1 2780 1.1315000243484974e-02 + + 1.9385300576686859e-01 -5.1707297563552856e-01 + <_> + + 0 -1 2781 -2.5590000674128532e-02 + + -9.3096500635147095e-01 -3.1546998769044876e-02 + <_> + + 0 -1 2782 -3.8058999925851822e-02 + + -6.8326902389526367e-01 1.2709100544452667e-01 + <_> + + 0 -1 2783 9.7970003262162209e-03 + + 1.5523999929428101e-02 -6.3347899913787842e-01 + <_> + + 0 -1 2784 -1.3841999694705009e-02 + + 1.0060529708862305e+00 6.2812998890876770e-02 + <_> + + 0 -1 2785 8.3459997549653053e-03 + + -2.3383200168609619e-01 3.0982699990272522e-01 + <_> + + 0 -1 2786 -7.1439996361732483e-02 + + -7.2505402565002441e-01 1.7148299515247345e-01 + <_> + + 0 -1 2787 1.0006000287830830e-02 + + -2.2071999311447144e-01 3.5266199707984924e-01 + <_> + + 0 -1 2788 1.1005300283432007e-01 + + 1.6662000119686127e-01 -7.4318999052047729e-01 + <_> + + 0 -1 2789 3.5310998558998108e-02 + + -2.3982700705528259e-01 4.1435998678207397e-01 + <_> + + 0 -1 2790 -1.1174699664115906e-01 + + 5.1045399904251099e-01 2.2319999989122152e-03 + <_> + + 0 -1 2791 -1.1367800086736679e-01 + + 9.0475201606750488e-01 -1.6615299880504608e-01 + <_> + + 0 -1 2792 1.6667999327182770e-02 + + 1.4024500548839569e-01 -5.2178502082824707e-01 + <_> + + 0 -1 2793 -8.0340001732110977e-03 + + -6.6178399324417114e-01 3.7640000227838755e-03 + <_> + + 0 -1 2794 -3.3096998929977417e-02 + + 8.0185902118682861e-01 5.9385001659393311e-02 + <_> + + 0 -1 2795 1.2547999620437622e-02 + + -3.3545500040054321e-01 1.4578600227832794e-01 + <_> + + 0 -1 2796 -4.2073998600244522e-02 + + -5.5509102344512939e-01 1.3266600668430328e-01 + <_> + + 0 -1 2797 2.5221999734640121e-02 + + -6.1631999909877777e-02 -1.3678770065307617e+00 + <_> + + 0 -1 2798 -2.4268999695777893e-02 + + 3.4185099601745605e-01 -7.4160001240670681e-03 + <_> + + 0 -1 2799 -1.2280000373721123e-02 + + 2.7745801210403442e-01 -3.1033900380134583e-01 + <_> + + 0 -1 2800 -1.1377099901437759e-01 + + 1.1719540357589722e+00 8.3681002259254456e-02 + <_> + + 0 -1 2801 -8.4771998226642609e-02 + + 8.1694799661636353e-01 -1.7837500572204590e-01 + <_> + + 0 -1 2802 -2.4552000686526299e-02 + + -1.8627299368381500e-01 1.4340099692344666e-01 + <_> + + 0 -1 2803 -9.0269995853304863e-03 + + 3.2659199833869934e-01 -2.3541299998760223e-01 + <_> + + 0 -1 2804 1.1177999898791313e-02 + + 1.9761200249195099e-01 -2.1701000630855560e-02 + <_> + + 0 -1 2805 -2.9366999864578247e-02 + + -9.3414801359176636e-01 -2.1704999729990959e-02 + <_> + + 0 -1 2806 6.3640000298619270e-03 + + 2.5573000311851501e-02 4.6412798762321472e-01 + <_> + + 0 -1 2807 1.4026000164449215e-02 + + -2.1228599548339844e-01 4.0078800916671753e-01 + <_> + + 0 -1 2808 -1.3341999612748623e-02 + + 7.4202698469161987e-01 2.9001999646425247e-02 + <_> + + 0 -1 2809 2.8422799706459045e-01 + + -1.9243599474430084e-01 4.3631199002265930e-01 + <_> + + 0 -1 2810 -2.3724000155925751e-01 + + 6.9736397266387939e-01 6.9307997822761536e-02 + <_> + + 0 -1 2811 -1.1169700324535370e-01 + + 3.9147201180458069e-01 -2.0922000706195831e-01 + <_> + + 0 -1 2812 1.2787500023841858e-01 + + -7.2555996477603912e-02 3.6088201403617859e-01 + <_> + + 0 -1 2813 -6.2900997698307037e-02 + + 9.5424997806549072e-01 -1.5402799844741821e-01 + <_> + + 0 -1 2814 1.7439000308513641e-02 + + -5.1134999841451645e-02 2.7750301361083984e-01 + <_> + + 0 -1 2815 1.2319999514147639e-03 + + 7.5627997517585754e-02 -3.6456099152565002e-01 + <_> + + 0 -1 2816 2.7495000511407852e-02 + + 5.1844000816345215e-02 4.1562598943710327e-01 + <_> + + 0 -1 2817 -4.3543998152017593e-02 + + 7.1969997882843018e-01 -1.7132200300693512e-01 + <_> + + 0 -1 2818 1.1025999672710896e-02 + + 1.4354600012302399e-01 -6.5403002500534058e-01 + <_> + + 0 -1 2819 2.0865999162197113e-02 + + 4.0089000016450882e-02 -4.5743298530578613e-01 + <_> + + 0 -1 2820 -2.2304000332951546e-02 + + 5.3855001926422119e-01 7.1662999689579010e-02 + <_> + + 0 -1 2821 3.2492000609636307e-02 + + -4.5991998165845871e-02 -1.0047069787979126e+00 + <_> + + 0 -1 2822 1.2269999831914902e-02 + + 3.4334998577833176e-02 4.2431798577308655e-01 + <_> + + 0 -1 2823 8.3820000290870667e-03 + + -2.5850600004196167e-01 2.6263499259948730e-01 + <_> + + 0 -1 2824 3.7353999912738800e-02 + + 1.5692499279975891e-01 -1.0429090261459351e+00 + <_> + + 0 -1 2825 -1.4111000113189220e-02 + + -7.3177701234817505e-01 -2.0276999101042747e-02 + <_> + + 0 -1 2826 5.7066999375820160e-02 + + 8.3360001444816589e-02 1.5661499500274658e+00 + <_> + + 0 -1 2827 4.9680001102387905e-03 + + -3.5318198800086975e-01 1.4698399603366852e-01 + <_> + + 0 -1 2828 -2.4492999538779259e-02 + + 2.8325900435447693e-01 -3.4640000667423010e-03 + <_> + + 0 -1 2829 -1.1254999786615372e-02 + + -8.4017497301101685e-01 -3.6251999437808990e-02 + <_> + + 0 -1 2830 3.4533001482486725e-02 + + 1.4998500049114227e-01 -8.7367099523544312e-01 + <_> + + 0 -1 2831 2.4303000420331955e-02 + + -1.8787500262260437e-01 5.9483999013900757e-01 + <_> + + 0 -1 2832 -7.8790001571178436e-03 + + 4.4315698742866516e-01 -5.6570999324321747e-02 + <_> + + 0 -1 2833 3.5142000764608383e-02 + + -5.6494999676942825e-02 -1.3617190122604370e+00 + <_> + + 0 -1 2834 4.6259998343884945e-03 + + -3.1161698698997498e-01 2.5447699427604675e-01 + <_> + + 0 -1 2835 -8.3131000399589539e-02 + + 1.6424349546432495e+00 -1.4429399371147156e-01 + <_> + + 0 -1 2836 -1.4015999622642994e-02 + + -7.7819502353668213e-01 1.7173300683498383e-01 + <_> + + 0 -1 2837 1.2450000504031777e-03 + + -2.3191399872303009e-01 2.8527900576591492e-01 + <_> + + 0 -1 2838 -1.6803000122308731e-02 + + -3.5965099930763245e-01 2.0412999391555786e-01 + <_> + + 0 -1 2839 -7.6747998595237732e-02 + + 7.8050500154495239e-01 -1.5612800419330597e-01 + <_> + + 0 -1 2840 -2.3671999573707581e-01 + + 1.1813700199127197e+00 7.8111998736858368e-02 + <_> + + 0 -1 2841 -1.0057400166988373e-01 + + -4.7104099392890930e-01 7.9172998666763306e-02 + <_> + + 0 -1 2842 1.3239999534562230e-03 + + 2.2262699902057648e-01 -3.7099799513816833e-01 + <_> + + 0 -1 2843 2.2152999415993690e-02 + + -3.8649000227451324e-02 -9.2274999618530273e-01 + <_> + + 0 -1 2844 -1.1246199905872345e-01 + + 4.1899600625038147e-01 8.0411002039909363e-02 + <_> + + 0 -1 2845 1.6481000930070877e-02 + + -1.6756699979305267e-01 7.1842402219772339e-01 + <_> + + 0 -1 2846 6.8113997578620911e-02 + + 1.5719899535179138e-01 -8.7681102752685547e-01 + <_> + + 0 -1 2847 1.6011999920010567e-02 + + -4.1600000113248825e-03 -5.9327799081802368e-01 + <_> + + 0 -1 2848 4.6640001237392426e-03 + + -3.0153999105095863e-02 4.8345300555229187e-01 + <_> + + 0 -1 2849 6.7579997703433037e-03 + + -2.2667400538921356e-01 3.3662301301956177e-01 + <_> + + 0 -1 2850 4.7289999201893806e-03 + + -6.0373999178409576e-02 3.1458100676536560e-01 + <_> + + 0 -1 2851 2.5869999080896378e-03 + + -2.9872599244117737e-01 1.7787499725818634e-01 + <_> + + 0 -1 2852 2.8989999555051327e-03 + + 2.1890200674533844e-01 -2.9567098617553711e-01 + <_> + + 0 -1 2853 -3.0053999274969101e-02 + + 1.2150429487228394e+00 -1.4354999363422394e-01 + <_> + + 0 -1 2854 1.4181000180542469e-02 + + 1.2451999820768833e-02 5.5490100383758545e-01 + <_> + + 0 -1 2855 -6.0527000576257706e-02 + + -1.4933999776840210e+00 -6.5227001905441284e-02 + <_> + + 0 -1 2856 -1.9882999360561371e-02 + + -3.8526400923728943e-01 1.9761200249195099e-01 + <_> + + 0 -1 2857 3.1218999996781349e-02 + + -2.1281200647354126e-01 2.9446500539779663e-01 + <_> + + 0 -1 2858 1.8271999433636665e-02 + + 9.7200000891461968e-04 6.6814202070236206e-01 + <_> + + 0 -1 2859 1.1089999461546540e-03 + + -6.2467902898788452e-01 -1.6599999507889152e-03 + <_> + + 0 -1 2860 -3.6713998764753342e-02 + + -4.2333900928497314e-01 1.2084700167179108e-01 + <_> + + 0 -1 2861 1.2044000439345837e-02 + + 2.5882000103592873e-02 -5.0732398033142090e-01 + <_> + + 0 -1 2862 7.4749000370502472e-02 + + 1.3184699416160583e-01 -2.1739600598812103e-01 + <_> + + 0 -1 2863 -2.3473200201988220e-01 + + 1.1775610446929932e+00 -1.5114699304103851e-01 + <_> + + 0 -1 2864 1.4096499979496002e-01 + + 3.3991001546382904e-02 3.9923098683357239e-01 + <_> + + 0 -1 2865 6.1789997853338718e-03 + + -3.1806701421737671e-01 1.1681699752807617e-01 + <_> + + 0 -1 2866 -5.7216998189687729e-02 + + 8.4399098157882690e-01 8.3889000117778778e-02 + <_> + + 0 -1 2867 -5.5227000266313553e-02 + + 3.6888301372528076e-01 -1.8913400173187256e-01 + <_> + + 0 -1 2868 -2.1583000198006630e-02 + + -5.2161800861358643e-01 1.5772600471973419e-01 + <_> + + 0 -1 2869 2.5747999548912048e-02 + + -5.9921998530626297e-02 -1.0674990415573120e+00 + <_> + + 0 -1 2870 -1.3098999857902527e-02 + + 7.8958398103713989e-01 5.2099999040365219e-02 + <_> + + 0 -1 2871 2.2799998987466097e-03 + + -1.1704430580139160e+00 -5.9356998652219772e-02 + <_> + + 0 -1 2872 8.8060004636645317e-03 + + 4.1717998683452606e-02 6.6352599859237671e-01 + <_> + + 0 -1 2873 -8.9699998497962952e-03 + + -3.5862699151039124e-01 6.0458000749349594e-02 + <_> + + 0 -1 2874 4.0230001322925091e-03 + + 2.0979399979114532e-01 -2.4806000292301178e-01 + <_> + + 0 -1 2875 2.5017000734806061e-02 + + -1.8795900046825409e-01 3.9547100663185120e-01 + <_> + + 0 -1 2876 -5.9009999968111515e-03 + + 2.5663900375366211e-01 -9.4919003546237946e-02 + <_> + + 0 -1 2877 4.3850000947713852e-03 + + 3.3139001578092575e-02 -4.6075400710105896e-01 + <_> + + 0 -1 2878 -3.3771999180316925e-02 + + -9.8881602287292480e-01 1.4636899530887604e-01 + <_> + + 0 -1 2879 4.4523000717163086e-02 + + -1.3286699354648590e-01 1.5796790122985840e+00 + <_> + + 0 -1 2880 -4.0929000824689865e-02 + + 3.3877098560333252e-01 7.4970997869968414e-02 + <_> + + 0 -1 2881 3.9351999759674072e-02 + + -1.8327899277210236e-01 4.6980699896812439e-01 + <_> + + 0 -1 2882 -7.0322997868061066e-02 + + -9.8322701454162598e-01 1.1808100342750549e-01 + <_> + + 0 -1 2883 3.5743001848459244e-02 + + -3.3050999045372009e-02 -8.3610898256301880e-01 + <_> + + 0 -1 2884 -4.2961999773979187e-02 + + 1.1670809984207153e+00 8.0692000687122345e-02 + <_> + + 0 -1 2885 -2.1007999777793884e-02 + + 6.3869798183441162e-01 -1.7626300454139709e-01 + <_> + + 0 -1 2886 -1.5742200613021851e-01 + + -2.3302499949932098e-01 1.2517499923706055e-01 + <_> + + 0 -1 2887 7.8659998252987862e-03 + + -2.2037999331951141e-01 2.7196800708770752e-01 + <_> + + 0 -1 2888 2.3622000589966774e-02 + + 1.6127300262451172e-01 -4.3329000473022461e-01 + <_> + + 0 -1 2889 7.4692003428936005e-02 + + -1.6991999745368958e-01 5.8884900808334351e-01 + <_> + + 0 -1 2890 -6.4799998654052615e-04 + + 2.5842899084091187e-01 -3.5911999642848969e-02 + <_> + + 0 -1 2891 -1.6290999948978424e-02 + + -7.6764398813247681e-01 -2.0472999662160873e-02 + <_> + + 0 -1 2892 -3.3133998513221741e-02 + + -2.7180099487304688e-01 1.4325700700283051e-01 + <_> + + 0 -1 2893 4.8797998577356339e-02 + + 7.6408997178077698e-02 -4.1445198655128479e-01 + <_> + + 0 -1 2894 2.2869999520480633e-03 + + -3.8628999143838882e-02 2.0753799378871918e-01 + <_> + + 0 -1 2895 4.5304000377655029e-02 + + -1.7777900397777557e-01 6.3461399078369141e-01 + <_> + + 0 -1 2896 1.0705800354480743e-01 + + 1.8972299993038177e-01 -5.1236200332641602e-01 + <_> + + 0 -1 2897 -4.0525000542402267e-02 + + 7.0614999532699585e-01 -1.7803299427032471e-01 + <_> + + 0 -1 2898 3.1968999654054642e-02 + + 6.8149998784065247e-02 6.8733102083206177e-01 + <_> + + 0 -1 2899 -5.7617001235485077e-02 + + 7.5170499086380005e-01 -1.5764999389648438e-01 + <_> + + 0 -1 2900 1.3593999668955803e-02 + + 1.9411900639533997e-01 -2.4561899900436401e-01 + <_> + + 0 -1 2901 7.1396000683307648e-02 + + -4.6881001442670822e-02 -8.8198298215866089e-01 + <_> + + 0 -1 2902 -1.4895999804139137e-02 + + -4.4532400369644165e-01 1.7679899930953979e-01 + <_> + + 0 -1 2903 -1.0026000440120697e-02 + + 6.5122699737548828e-01 -1.6709999740123749e-01 + <_> + + 0 -1 2904 3.7589999847114086e-03 + + -5.8301001787185669e-02 3.4483298659324646e-01 + <_> + + 0 -1 2905 1.6263000667095184e-02 + + -1.5581500530242920e-01 8.6432701349258423e-01 + <_> + + 0 -1 2906 -4.0176000446081161e-02 + + -6.1028599739074707e-01 1.1796399950981140e-01 + <_> + + 0 -1 2907 2.7080999687314034e-02 + + -4.9601998180150986e-02 -8.9990001916885376e-01 + <_> + + 0 -1 2908 5.2420001477003098e-02 + + 1.1297199875116348e-01 -1.0833640098571777e+00 + <_> + + 0 -1 2909 -1.9160000607371330e-02 + + -7.9880100488662720e-01 -3.4079000353813171e-02 + <_> + + 0 -1 2910 -3.7730000913143158e-03 + + -1.9124099612236023e-01 2.1535199880599976e-01 + <_> + + 0 -1 2911 7.5762003660202026e-02 + + -1.3421699404716492e-01 1.6807060241699219e+00 + <_> + + 0 -1 2912 -2.2173000499606133e-02 + + 4.8600998520851135e-01 3.6160000599920750e-03 + + <_> + + <_> + 6 4 12 9 -1. + <_> + 6 7 12 3 3. + <_> + + <_> + 6 4 12 7 -1. + <_> + 10 4 4 7 3. + <_> + + <_> + 3 9 18 9 -1. + <_> + 3 12 18 3 3. + <_> + + <_> + 8 18 9 6 -1. + <_> + 8 20 9 2 3. + <_> + + <_> + 3 5 4 19 -1. + <_> + 5 5 2 19 2. + <_> + + <_> + 6 5 12 16 -1. + <_> + 6 13 12 8 2. + <_> + + <_> + 5 8 12 6 -1. + <_> + 5 11 12 3 2. + <_> + + <_> + 11 14 4 10 -1. + <_> + 11 19 4 5 2. + <_> + + <_> + 4 0 7 6 -1. + <_> + 4 3 7 3 2. + <_> + + <_> + 6 6 12 6 -1. + <_> + 6 8 12 2 3. + <_> + + <_> + 6 4 12 7 -1. + <_> + 10 4 4 7 3. + <_> + + <_> + 1 8 19 12 -1. + <_> + 1 12 19 4 3. + <_> + + <_> + 0 2 24 3 -1. + <_> + 8 2 8 3 3. + <_> + + <_> + 9 9 6 15 -1. + <_> + 9 14 6 5 3. + <_> + + <_> + 5 6 14 10 -1. + <_> + 5 11 14 5 2. + <_> + + <_> + 5 0 14 9 -1. + <_> + 5 3 14 3 3. + <_> + + <_> + 13 11 9 6 -1. + <_> + 16 11 3 6 3. + <_> + + <_> + 7 5 6 10 -1. + <_> + 9 5 2 10 3. + <_> + + <_> + 10 8 6 10 -1. + <_> + 12 8 2 10 3. + <_> + + <_> + 2 5 4 9 -1. + <_> + 4 5 2 9 2. + <_> + + <_> + 18 0 6 11 -1. + <_> + 20 0 2 11 3. + <_> + + <_> + 0 6 24 13 -1. + <_> + 8 6 8 13 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 7 18 10 6 -1. + <_> + 7 20 10 2 3. + <_> + + <_> + 5 7 14 12 -1. + <_> + 5 13 14 6 2. + <_> + + <_> + 0 3 24 3 -1. + <_> + 8 3 8 3 3. + <_> + + <_> + 5 8 15 6 -1. + <_> + 5 11 15 3 2. + <_> + + <_> + 9 6 5 14 -1. + <_> + 9 13 5 7 2. + <_> + + <_> + 9 5 6 10 -1. + <_> + 11 5 2 10 3. + <_> + + <_> + 6 6 3 12 -1. + <_> + 6 12 3 6 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 5 6 13 6 -1. + <_> + 5 8 13 2 3. + <_> + + <_> + 18 1 6 15 -1. + <_> + 18 1 3 15 2. + <_> + + <_> + 1 1 6 15 -1. + <_> + 4 1 3 15 2. + <_> + + <_> + 0 8 24 15 -1. + <_> + 8 8 8 15 3. + <_> + + <_> + 5 6 14 12 -1. + <_> + 5 6 7 6 2. + <_> + 12 12 7 6 2. + <_> + + <_> + 2 12 21 12 -1. + <_> + 2 16 21 4 3. + <_> + + <_> + 8 1 4 10 -1. + <_> + 10 1 2 10 2. + <_> + + <_> + 2 13 20 10 -1. + <_> + 2 13 10 10 2. + <_> + + <_> + 0 1 6 13 -1. + <_> + 2 1 2 13 3. + <_> + + <_> + 20 2 4 13 -1. + <_> + 20 2 2 13 2. + <_> + + <_> + 0 5 22 19 -1. + <_> + 11 5 11 19 2. + <_> + + <_> + 18 4 6 9 -1. + <_> + 20 4 2 9 3. + <_> + + <_> + 0 3 6 11 -1. + <_> + 2 3 2 11 3. + <_> + + <_> + 12 1 4 9 -1. + <_> + 12 1 2 9 2. + <_> + + <_> + 0 6 19 3 -1. + <_> + 0 7 19 1 3. + <_> + + <_> + 12 1 4 9 -1. + <_> + 12 1 2 9 2. + <_> + + <_> + 8 1 4 9 -1. + <_> + 10 1 2 9 2. + <_> + + <_> + 5 5 14 14 -1. + <_> + 12 5 7 7 2. + <_> + 5 12 7 7 2. + <_> + + <_> + 1 10 18 2 -1. + <_> + 1 11 18 1 2. + <_> + + <_> + 17 13 4 11 -1. + <_> + 17 13 2 11 2. + <_> + + <_> + 0 4 6 9 -1. + <_> + 0 7 6 3 3. + <_> + + <_> + 6 4 12 9 -1. + <_> + 6 7 12 3 3. + <_> + + <_> + 6 5 12 6 -1. + <_> + 10 5 4 6 3. + <_> + + <_> + 0 1 24 5 -1. + <_> + 8 1 8 5 3. + <_> + + <_> + 4 10 18 6 -1. + <_> + 4 12 18 2 3. + <_> + + <_> + 2 17 12 6 -1. + <_> + 2 17 6 3 2. + <_> + 8 20 6 3 2. + <_> + + <_> + 19 3 4 13 -1. + <_> + 19 3 2 13 2. + <_> + + <_> + 1 3 4 13 -1. + <_> + 3 3 2 13 2. + <_> + + <_> + 0 1 24 23 -1. + <_> + 8 1 8 23 3. + <_> + + <_> + 1 7 8 12 -1. + <_> + 1 11 8 4 3. + <_> + + <_> + 14 7 3 14 -1. + <_> + 14 14 3 7 2. + <_> + + <_> + 3 12 16 6 -1. + <_> + 3 12 8 3 2. + <_> + 11 15 8 3 2. + <_> + + <_> + 6 6 12 6 -1. + <_> + 6 8 12 2 3. + <_> + + <_> + 8 7 6 12 -1. + <_> + 8 13 6 6 2. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 1 17 18 3 -1. + <_> + 1 18 18 1 3. + <_> + + <_> + 4 4 16 12 -1. + <_> + 4 10 16 6 2. + <_> + + <_> + 0 1 4 20 -1. + <_> + 2 1 2 20 2. + <_> + + <_> + 3 0 18 2 -1. + <_> + 3 1 18 1 2. + <_> + + <_> + 1 5 20 14 -1. + <_> + 1 5 10 7 2. + <_> + 11 12 10 7 2. + <_> + + <_> + 5 8 14 12 -1. + <_> + 5 12 14 4 3. + <_> + + <_> + 3 14 7 9 -1. + <_> + 3 17 7 3 3. + <_> + + <_> + 14 15 9 6 -1. + <_> + 14 17 9 2 3. + <_> + + <_> + 1 15 9 6 -1. + <_> + 1 17 9 2 3. + <_> + + <_> + 11 6 8 10 -1. + <_> + 15 6 4 5 2. + <_> + 11 11 4 5 2. + <_> + + <_> + 5 5 14 14 -1. + <_> + 5 5 7 7 2. + <_> + 12 12 7 7 2. + <_> + + <_> + 6 0 12 5 -1. + <_> + 10 0 4 5 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 9 3 6 3 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 3 8 18 4 -1. + <_> + 9 8 6 4 3. + <_> + + <_> + 6 0 12 9 -1. + <_> + 6 3 12 3 3. + <_> + + <_> + 0 0 24 6 -1. + <_> + 8 0 8 6 3. + <_> + + <_> + 4 7 16 12 -1. + <_> + 4 11 16 4 3. + <_> + + <_> + 11 6 6 6 -1. + <_> + 11 6 3 6 2. + <_> + + <_> + 0 20 24 3 -1. + <_> + 8 20 8 3 3. + <_> + + <_> + 11 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 4 13 15 4 -1. + <_> + 9 13 5 4 3. + <_> + + <_> + 11 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 9 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 18 6 6 2. + <_> + + <_> + 1 22 18 2 -1. + <_> + 1 23 18 1 2. + <_> + + <_> + 10 7 4 10 -1. + <_> + 10 12 4 5 2. + <_> + + <_> + 6 7 8 10 -1. + <_> + 6 12 8 5 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 0 14 10 4 -1. + <_> + 0 16 10 2 2. + <_> + + <_> + 6 18 18 2 -1. + <_> + 6 19 18 1 2. + <_> + + <_> + 1 1 22 3 -1. + <_> + 1 2 22 1 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 2 4 6 15 -1. + <_> + 5 4 3 15 2. + <_> + + <_> + 20 4 4 10 -1. + <_> + 20 4 2 10 2. + <_> + + <_> + 0 4 4 10 -1. + <_> + 2 4 2 10 2. + <_> + + <_> + 2 16 20 6 -1. + <_> + 12 16 10 3 2. + <_> + 2 19 10 3 2. + <_> + + <_> + 0 12 8 9 -1. + <_> + 4 12 4 9 2. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 5 10 6 6 -1. + <_> + 8 10 3 6 2. + <_> + + <_> + 11 8 12 6 -1. + <_> + 17 8 6 3 2. + <_> + 11 11 6 3 2. + <_> + + <_> + 0 8 12 6 -1. + <_> + 0 8 6 3 2. + <_> + 6 11 6 3 2. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 8 14 9 6 -1. + <_> + 8 16 9 2 3. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 10 8 6 10 -1. + <_> + 12 8 2 10 3. + <_> + + <_> + 3 19 12 3 -1. + <_> + 9 19 6 3 2. + <_> + + <_> + 2 10 20 2 -1. + <_> + 2 11 20 1 2. + <_> + + <_> + 2 9 18 12 -1. + <_> + 2 9 9 6 2. + <_> + 11 15 9 6 2. + <_> + + <_> + 3 0 18 24 -1. + <_> + 3 0 9 24 2. + <_> + + <_> + 5 6 14 10 -1. + <_> + 5 6 7 5 2. + <_> + 12 11 7 5 2. + <_> + + <_> + 9 5 10 12 -1. + <_> + 14 5 5 6 2. + <_> + 9 11 5 6 2. + <_> + + <_> + 4 5 12 12 -1. + <_> + 4 5 6 6 2. + <_> + 10 11 6 6 2. + <_> + + <_> + 4 14 18 3 -1. + <_> + 4 15 18 1 3. + <_> + + <_> + 6 13 8 8 -1. + <_> + 6 17 8 4 2. + <_> + + <_> + 3 16 18 6 -1. + <_> + 3 19 18 3 2. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 6 6 12 18 -1. + <_> + 10 6 4 18 3. + <_> + + <_> + 6 1 4 14 -1. + <_> + 8 1 2 14 2. + <_> + + <_> + 3 2 19 2 -1. + <_> + 3 3 19 1 2. + <_> + + <_> + 1 8 22 13 -1. + <_> + 12 8 11 13 2. + <_> + + <_> + 8 9 11 4 -1. + <_> + 8 11 11 2 2. + <_> + + <_> + 0 12 15 10 -1. + <_> + 5 12 5 10 3. + <_> + + <_> + 12 16 12 6 -1. + <_> + 16 16 4 6 3. + <_> + + <_> + 0 16 12 6 -1. + <_> + 4 16 4 6 3. + <_> + + <_> + 19 1 5 12 -1. + <_> + 19 5 5 4 3. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 6 8 12 4 -1. + <_> + 6 10 12 2 2. + <_> + + <_> + 7 5 9 6 -1. + <_> + 10 5 3 6 3. + <_> + + <_> + 9 17 6 6 -1. + <_> + 9 20 6 3 2. + <_> + + <_> + 0 7 22 15 -1. + <_> + 0 12 22 5 3. + <_> + + <_> + 4 1 17 9 -1. + <_> + 4 4 17 3 3. + <_> + + <_> + 7 5 6 10 -1. + <_> + 9 5 2 10 3. + <_> + + <_> + 18 1 6 8 -1. + <_> + 18 1 3 8 2. + <_> + + <_> + 0 1 6 7 -1. + <_> + 3 1 3 7 2. + <_> + + <_> + 18 0 6 22 -1. + <_> + 18 0 3 22 2. + <_> + + <_> + 0 0 6 22 -1. + <_> + 3 0 3 22 2. + <_> + + <_> + 16 7 8 16 -1. + <_> + 16 7 4 16 2. + <_> + + <_> + 2 10 19 6 -1. + <_> + 2 12 19 2 3. + <_> + + <_> + 9 9 6 12 -1. + <_> + 9 13 6 4 3. + <_> + + <_> + 2 15 17 6 -1. + <_> + 2 17 17 2 3. + <_> + + <_> + 14 7 3 14 -1. + <_> + 14 14 3 7 2. + <_> + + <_> + 5 6 8 10 -1. + <_> + 5 6 4 5 2. + <_> + 9 11 4 5 2. + <_> + + <_> + 15 8 9 11 -1. + <_> + 18 8 3 11 3. + <_> + + <_> + 0 8 9 11 -1. + <_> + 3 8 3 11 3. + <_> + + <_> + 8 6 10 18 -1. + <_> + 8 15 10 9 2. + <_> + + <_> + 7 7 3 14 -1. + <_> + 7 14 3 7 2. + <_> + + <_> + 0 14 24 8 -1. + <_> + 8 14 8 8 3. + <_> + + <_> + 1 10 18 14 -1. + <_> + 10 10 9 14 2. + <_> + + <_> + 14 12 6 6 -1. + <_> + 14 15 6 3 2. + <_> + + <_> + 7 0 10 16 -1. + <_> + 7 0 5 8 2. + <_> + 12 8 5 8 2. + <_> + + <_> + 10 0 9 6 -1. + <_> + 13 0 3 6 3. + <_> + + <_> + 4 3 16 4 -1. + <_> + 12 3 8 4 2. + <_> + + <_> + 10 0 9 6 -1. + <_> + 13 0 3 6 3. + <_> + + <_> + 1 1 20 4 -1. + <_> + 1 1 10 2 2. + <_> + 11 3 10 2 2. + <_> + + <_> + 10 0 9 6 -1. + <_> + 13 0 3 6 3. + <_> + + <_> + 5 0 9 6 -1. + <_> + 8 0 3 6 3. + <_> + + <_> + 8 18 10 6 -1. + <_> + 8 20 10 2 3. + <_> + + <_> + 6 3 6 9 -1. + <_> + 8 3 2 9 3. + <_> + + <_> + 7 3 12 6 -1. + <_> + 7 5 12 2 3. + <_> + + <_> + 0 10 18 3 -1. + <_> + 0 11 18 1 3. + <_> + + <_> + 1 10 22 3 -1. + <_> + 1 11 22 1 3. + <_> + + <_> + 5 11 8 8 -1. + <_> + 9 11 4 8 2. + <_> + + <_> + 12 11 6 6 -1. + <_> + 12 11 3 6 2. + <_> + + <_> + 6 11 6 6 -1. + <_> + 9 11 3 6 2. + <_> + + <_> + 7 10 11 6 -1. + <_> + 7 12 11 2 3. + <_> + + <_> + 0 13 24 4 -1. + <_> + 0 13 12 2 2. + <_> + 12 15 12 2 2. + <_> + + <_> + 2 4 22 12 -1. + <_> + 13 4 11 6 2. + <_> + 2 10 11 6 2. + <_> + + <_> + 2 0 20 17 -1. + <_> + 12 0 10 17 2. + <_> + + <_> + 14 0 2 24 -1. + <_> + 14 0 1 24 2. + <_> + + <_> + 8 0 2 24 -1. + <_> + 9 0 1 24 2. + <_> + + <_> + 14 1 2 22 -1. + <_> + 14 1 1 22 2. + <_> + + <_> + 8 1 2 22 -1. + <_> + 9 1 1 22 2. + <_> + + <_> + 17 6 3 18 -1. + <_> + 18 6 1 18 3. + <_> + + <_> + 6 14 9 6 -1. + <_> + 6 16 9 2 3. + <_> + + <_> + 13 14 9 4 -1. + <_> + 13 16 9 2 2. + <_> + + <_> + 3 18 18 3 -1. + <_> + 3 19 18 1 3. + <_> + + <_> + 9 4 8 18 -1. + <_> + 13 4 4 9 2. + <_> + 9 13 4 9 2. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 0 2 12 4 -1. + <_> + 6 2 6 4 2. + <_> + + <_> + 6 8 14 6 -1. + <_> + 6 11 14 3 2. + <_> + + <_> + 7 5 6 6 -1. + <_> + 10 5 3 6 2. + <_> + + <_> + 10 5 6 16 -1. + <_> + 10 13 6 8 2. + <_> + + <_> + 1 4 9 16 -1. + <_> + 4 4 3 16 3. + <_> + + <_> + 5 0 18 9 -1. + <_> + 5 3 18 3 3. + <_> + + <_> + 9 15 5 8 -1. + <_> + 9 19 5 4 2. + <_> + + <_> + 20 0 4 9 -1. + <_> + 20 0 2 9 2. + <_> + + <_> + 2 0 18 3 -1. + <_> + 2 1 18 1 3. + <_> + + <_> + 5 22 19 2 -1. + <_> + 5 23 19 1 2. + <_> + + <_> + 0 0 4 9 -1. + <_> + 2 0 2 9 2. + <_> + + <_> + 5 6 19 18 -1. + <_> + 5 12 19 6 3. + <_> + + <_> + 0 1 6 9 -1. + <_> + 2 1 2 9 3. + <_> + + <_> + 6 5 14 12 -1. + <_> + 13 5 7 6 2. + <_> + 6 11 7 6 2. + <_> + + <_> + 0 1 20 2 -1. + <_> + 0 2 20 1 2. + <_> + + <_> + 1 2 22 3 -1. + <_> + 1 3 22 1 3. + <_> + + <_> + 2 8 7 9 -1. + <_> + 2 11 7 3 3. + <_> + + <_> + 2 12 22 4 -1. + <_> + 13 12 11 2 2. + <_> + 2 14 11 2 2. + <_> + + <_> + 0 12 22 4 -1. + <_> + 0 12 11 2 2. + <_> + 11 14 11 2 2. + <_> + + <_> + 9 7 6 11 -1. + <_> + 11 7 2 11 3. + <_> + + <_> + 7 1 9 6 -1. + <_> + 10 1 3 6 3. + <_> + + <_> + 11 2 4 10 -1. + <_> + 11 7 4 5 2. + <_> + + <_> + 6 4 12 12 -1. + <_> + 6 10 12 6 2. + <_> + + <_> + 18 1 6 15 -1. + <_> + 18 6 6 5 3. + <_> + + <_> + 3 15 18 3 -1. + <_> + 3 16 18 1 3. + <_> + + <_> + 18 5 6 9 -1. + <_> + 18 8 6 3 3. + <_> + + <_> + 1 5 16 6 -1. + <_> + 1 5 8 3 2. + <_> + 9 8 8 3 2. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 0 4 24 14 -1. + <_> + 0 4 12 7 2. + <_> + 12 11 12 7 2. + <_> + + <_> + 13 0 4 13 -1. + <_> + 13 0 2 13 2. + <_> + + <_> + 7 0 4 13 -1. + <_> + 9 0 2 13 2. + <_> + + <_> + 11 6 6 9 -1. + <_> + 13 6 2 9 3. + <_> + + <_> + 8 7 6 9 -1. + <_> + 10 7 2 9 3. + <_> + + <_> + 13 17 9 6 -1. + <_> + 13 19 9 2 3. + <_> + + <_> + 2 18 14 6 -1. + <_> + 2 18 7 3 2. + <_> + 9 21 7 3 2. + <_> + + <_> + 3 18 18 4 -1. + <_> + 12 18 9 2 2. + <_> + 3 20 9 2 2. + <_> + + <_> + 0 20 15 4 -1. + <_> + 5 20 5 4 3. + <_> + + <_> + 9 15 15 9 -1. + <_> + 14 15 5 9 3. + <_> + + <_> + 4 4 16 4 -1. + <_> + 4 6 16 2 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 0 14 15 10 -1. + <_> + 5 14 5 10 3. + <_> + + <_> + 7 9 10 14 -1. + <_> + 12 9 5 7 2. + <_> + 7 16 5 7 2. + <_> + + <_> + 7 6 6 9 -1. + <_> + 9 6 2 9 3. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 0 10 18 3 -1. + <_> + 0 11 18 1 3. + <_> + + <_> + 3 16 18 4 -1. + <_> + 12 16 9 2 2. + <_> + 3 18 9 2 2. + <_> + + <_> + 4 6 14 6 -1. + <_> + 4 6 7 3 2. + <_> + 11 9 7 3 2. + <_> + + <_> + 13 0 2 18 -1. + <_> + 13 0 1 18 2. + <_> + + <_> + 9 0 2 18 -1. + <_> + 10 0 1 18 2. + <_> + + <_> + 5 7 15 10 -1. + <_> + 10 7 5 10 3. + <_> + + <_> + 1 20 21 4 -1. + <_> + 8 20 7 4 3. + <_> + + <_> + 10 5 5 18 -1. + <_> + 10 14 5 9 2. + <_> + + <_> + 0 2 24 6 -1. + <_> + 0 2 12 3 2. + <_> + 12 5 12 3 2. + <_> + + <_> + 1 1 22 8 -1. + <_> + 12 1 11 4 2. + <_> + 1 5 11 4 2. + <_> + + <_> + 4 0 15 9 -1. + <_> + 4 3 15 3 3. + <_> + + <_> + 0 0 24 19 -1. + <_> + 8 0 8 19 3. + <_> + + <_> + 2 21 18 3 -1. + <_> + 11 21 9 3 2. + <_> + + <_> + 9 7 10 4 -1. + <_> + 9 7 5 4 2. + <_> + + <_> + 5 7 10 4 -1. + <_> + 10 7 5 4 2. + <_> + + <_> + 17 8 6 16 -1. + <_> + 20 8 3 8 2. + <_> + 17 16 3 8 2. + <_> + + <_> + 1 15 20 4 -1. + <_> + 1 15 10 2 2. + <_> + 11 17 10 2 2. + <_> + + <_> + 14 15 10 6 -1. + <_> + 14 17 10 2 3. + <_> + + <_> + 3 0 16 9 -1. + <_> + 3 3 16 3 3. + <_> + + <_> + 15 6 7 15 -1. + <_> + 15 11 7 5 3. + <_> + + <_> + 9 1 6 13 -1. + <_> + 11 1 2 13 3. + <_> + + <_> + 17 2 6 14 -1. + <_> + 17 2 3 14 2. + <_> + + <_> + 3 14 12 10 -1. + <_> + 3 14 6 5 2. + <_> + 9 19 6 5 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 1 2 6 14 -1. + <_> + 4 2 3 14 2. + <_> + + <_> + 10 4 5 12 -1. + <_> + 10 8 5 4 3. + <_> + + <_> + 0 17 24 5 -1. + <_> + 8 17 8 5 3. + <_> + + <_> + 15 7 5 12 -1. + <_> + 15 11 5 4 3. + <_> + + <_> + 3 1 6 12 -1. + <_> + 3 1 3 6 2. + <_> + 6 7 3 6 2. + <_> + + <_> + 12 13 6 6 -1. + <_> + 12 16 6 3 2. + <_> + + <_> + 6 13 6 6 -1. + <_> + 6 16 6 3 2. + <_> + + <_> + 14 6 3 16 -1. + <_> + 14 14 3 8 2. + <_> + + <_> + 1 12 13 6 -1. + <_> + 1 14 13 2 3. + <_> + + <_> + 13 1 4 9 -1. + <_> + 13 1 2 9 2. + <_> + + <_> + 7 0 9 6 -1. + <_> + 10 0 3 6 3. + <_> + + <_> + 12 2 6 9 -1. + <_> + 12 2 3 9 2. + <_> + + <_> + 6 2 6 9 -1. + <_> + 9 2 3 9 2. + <_> + + <_> + 6 18 12 6 -1. + <_> + 6 20 12 2 3. + <_> + + <_> + 7 6 6 9 -1. + <_> + 9 6 2 9 3. + <_> + + <_> + 7 7 12 3 -1. + <_> + 7 7 6 3 2. + <_> + + <_> + 8 3 8 21 -1. + <_> + 8 10 8 7 3. + <_> + + <_> + 7 4 10 12 -1. + <_> + 7 8 10 4 3. + <_> + + <_> + 0 1 6 9 -1. + <_> + 0 4 6 3 3. + <_> + + <_> + 15 2 2 20 -1. + <_> + 15 2 1 20 2. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 15 3 2 21 -1. + <_> + 15 3 1 21 2. + <_> + + <_> + 7 0 2 23 -1. + <_> + 8 0 1 23 2. + <_> + + <_> + 15 8 9 4 -1. + <_> + 15 10 9 2 2. + <_> + + <_> + 0 8 9 4 -1. + <_> + 0 10 9 2 2. + <_> + + <_> + 8 14 9 6 -1. + <_> + 8 16 9 2 3. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 3 10 18 4 -1. + <_> + 9 10 6 4 3. + <_> + + <_> + 0 0 24 19 -1. + <_> + 8 0 8 19 3. + <_> + + <_> + 9 1 8 12 -1. + <_> + 9 7 8 6 2. + <_> + + <_> + 10 6 4 10 -1. + <_> + 12 6 2 10 2. + <_> + + <_> + 7 9 10 12 -1. + <_> + 12 9 5 6 2. + <_> + 7 15 5 6 2. + <_> + + <_> + 5 0 3 19 -1. + <_> + 6 0 1 19 3. + <_> + + <_> + 14 0 6 10 -1. + <_> + 16 0 2 10 3. + <_> + + <_> + 2 0 6 12 -1. + <_> + 2 0 3 6 2. + <_> + 5 6 3 6 2. + <_> + + <_> + 0 11 24 2 -1. + <_> + 0 12 24 1 2. + <_> + + <_> + 4 9 13 4 -1. + <_> + 4 11 13 2 2. + <_> + + <_> + 9 8 6 9 -1. + <_> + 9 11 6 3 3. + <_> + + <_> + 0 12 16 4 -1. + <_> + 0 14 16 2 2. + <_> + + <_> + 18 12 6 9 -1. + <_> + 18 15 6 3 3. + <_> + + <_> + 0 12 6 9 -1. + <_> + 0 15 6 3 3. + <_> + + <_> + 8 7 10 4 -1. + <_> + 8 7 5 4 2. + <_> + + <_> + 8 7 6 9 -1. + <_> + 10 7 2 9 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 12 3 6 15 -1. + <_> + 14 3 2 15 3. + <_> + + <_> + 6 3 6 15 -1. + <_> + 8 3 2 15 3. + <_> + + <_> + 15 2 9 4 -1. + <_> + 15 4 9 2 2. + <_> + + <_> + 5 10 6 7 -1. + <_> + 8 10 3 7 2. + <_> + + <_> + 9 14 6 10 -1. + <_> + 9 19 6 5 2. + <_> + + <_> + 7 13 5 8 -1. + <_> + 7 17 5 4 2. + <_> + + <_> + 14 5 3 16 -1. + <_> + 14 13 3 8 2. + <_> + + <_> + 2 17 18 3 -1. + <_> + 2 18 18 1 3. + <_> + + <_> + 5 18 19 3 -1. + <_> + 5 19 19 1 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 12 4 3 18 -1. + <_> + 13 4 1 18 3. + <_> + + <_> + 9 4 3 18 -1. + <_> + 10 4 1 18 3. + <_> + + <_> + 3 3 18 9 -1. + <_> + 9 3 6 9 3. + <_> + + <_> + 6 1 6 14 -1. + <_> + 8 1 2 14 3. + <_> + + <_> + 12 16 9 6 -1. + <_> + 12 19 9 3 2. + <_> + + <_> + 1 3 20 16 -1. + <_> + 1 3 10 8 2. + <_> + 11 11 10 8 2. + <_> + + <_> + 12 5 6 12 -1. + <_> + 15 5 3 6 2. + <_> + 12 11 3 6 2. + <_> + + <_> + 1 2 22 16 -1. + <_> + 1 2 11 8 2. + <_> + 12 10 11 8 2. + <_> + + <_> + 10 14 5 10 -1. + <_> + 10 19 5 5 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 3 22 18 1 3. + <_> + + <_> + 10 14 6 10 -1. + <_> + 12 14 2 10 3. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 6 4 12 9 -1. + <_> + 6 7 12 3 3. + <_> + + <_> + 6 6 12 5 -1. + <_> + 10 6 4 5 3. + <_> + + <_> + 5 8 14 12 -1. + <_> + 5 12 14 4 3. + <_> + + <_> + 4 14 8 10 -1. + <_> + 4 14 4 5 2. + <_> + 8 19 4 5 2. + <_> + + <_> + 11 6 5 14 -1. + <_> + 11 13 5 7 2. + <_> + + <_> + 7 6 3 16 -1. + <_> + 7 14 3 8 2. + <_> + + <_> + 3 7 18 8 -1. + <_> + 9 7 6 8 3. + <_> + + <_> + 2 3 20 2 -1. + <_> + 2 4 20 1 2. + <_> + + <_> + 3 12 19 6 -1. + <_> + 3 14 19 2 3. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 16 6 6 14 -1. + <_> + 16 6 3 14 2. + <_> + + <_> + 7 9 6 12 -1. + <_> + 9 9 2 12 3. + <_> + + <_> + 18 6 6 18 -1. + <_> + 21 6 3 9 2. + <_> + 18 15 3 9 2. + <_> + + <_> + 0 6 6 18 -1. + <_> + 0 6 3 9 2. + <_> + 3 15 3 9 2. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 3 18 15 6 -1. + <_> + 3 20 15 2 3. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 0 5 6 3 3. + <_> + + <_> + 5 10 18 2 -1. + <_> + 5 11 18 1 2. + <_> + + <_> + 6 0 12 6 -1. + <_> + 6 2 12 2 3. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 8 0 6 9 -1. + <_> + 10 0 2 9 3. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 3 6 13 6 -1. + <_> + 3 8 13 2 3. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 2 5 6 15 -1. + <_> + 5 5 3 15 2. + <_> + + <_> + 8 8 9 6 -1. + <_> + 11 8 3 6 3. + <_> + + <_> + 8 6 3 14 -1. + <_> + 8 13 3 7 2. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 4 12 10 4 -1. + <_> + 9 12 5 4 2. + <_> + + <_> + 13 1 4 19 -1. + <_> + 13 1 2 19 2. + <_> + + <_> + 7 1 4 19 -1. + <_> + 9 1 2 19 2. + <_> + + <_> + 18 9 6 9 -1. + <_> + 18 12 6 3 3. + <_> + + <_> + 1 21 18 3 -1. + <_> + 1 22 18 1 3. + <_> + + <_> + 14 13 10 9 -1. + <_> + 14 16 10 3 3. + <_> + + <_> + 1 13 22 4 -1. + <_> + 1 13 11 2 2. + <_> + 12 15 11 2 2. + <_> + + <_> + 4 6 16 6 -1. + <_> + 12 6 8 3 2. + <_> + 4 9 8 3 2. + <_> + + <_> + 1 0 18 22 -1. + <_> + 1 0 9 11 2. + <_> + 10 11 9 11 2. + <_> + + <_> + 10 7 8 14 -1. + <_> + 14 7 4 7 2. + <_> + 10 14 4 7 2. + <_> + + <_> + 0 4 6 20 -1. + <_> + 0 4 3 10 2. + <_> + 3 14 3 10 2. + <_> + + <_> + 15 0 6 9 -1. + <_> + 17 0 2 9 3. + <_> + + <_> + 3 0 6 9 -1. + <_> + 5 0 2 9 3. + <_> + + <_> + 15 12 6 12 -1. + <_> + 18 12 3 6 2. + <_> + 15 18 3 6 2. + <_> + + <_> + 3 12 6 12 -1. + <_> + 3 12 3 6 2. + <_> + 6 18 3 6 2. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 0 12 9 6 -1. + <_> + 0 14 9 2 3. + <_> + + <_> + 4 14 19 3 -1. + <_> + 4 15 19 1 3. + <_> + + <_> + 2 13 19 3 -1. + <_> + 2 14 19 1 3. + <_> + + <_> + 14 15 10 6 -1. + <_> + 14 17 10 2 3. + <_> + + <_> + 6 0 10 12 -1. + <_> + 6 0 5 6 2. + <_> + 11 6 5 6 2. + <_> + + <_> + 17 1 6 12 -1. + <_> + 20 1 3 6 2. + <_> + 17 7 3 6 2. + <_> + + <_> + 1 1 6 12 -1. + <_> + 1 1 3 6 2. + <_> + 4 7 3 6 2. + <_> + + <_> + 16 14 6 9 -1. + <_> + 16 17 6 3 3. + <_> + + <_> + 7 3 9 12 -1. + <_> + 7 9 9 6 2. + <_> + + <_> + 12 1 4 12 -1. + <_> + 12 7 4 6 2. + <_> + + <_> + 4 0 14 8 -1. + <_> + 4 4 14 4 2. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 2 10 18 3 -1. + <_> + 8 10 6 3 3. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 1 21 23 -1. + <_> + 7 1 7 23 3. + <_> + + <_> + 6 9 17 4 -1. + <_> + 6 11 17 2 2. + <_> + + <_> + 1 0 11 18 -1. + <_> + 1 6 11 6 3. + <_> + + <_> + 6 15 13 6 -1. + <_> + 6 17 13 2 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 8 7 15 4 -1. + <_> + 13 7 5 4 3. + <_> + + <_> + 9 12 6 9 -1. + <_> + 9 15 6 3 3. + <_> + + <_> + 6 8 18 3 -1. + <_> + 12 8 6 3 3. + <_> + + <_> + 0 14 24 4 -1. + <_> + 8 14 8 4 3. + <_> + + <_> + 16 10 3 12 -1. + <_> + 16 16 3 6 2. + <_> + + <_> + 0 3 24 3 -1. + <_> + 0 4 24 1 3. + <_> + + <_> + 14 17 10 6 -1. + <_> + 14 19 10 2 3. + <_> + + <_> + 1 13 18 3 -1. + <_> + 7 13 6 3 3. + <_> + + <_> + 5 0 18 9 -1. + <_> + 5 3 18 3 3. + <_> + + <_> + 4 3 16 9 -1. + <_> + 4 6 16 3 3. + <_> + + <_> + 16 5 3 12 -1. + <_> + 16 11 3 6 2. + <_> + + <_> + 0 7 18 4 -1. + <_> + 6 7 6 4 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 9 8 6 10 -1. + <_> + 11 8 2 10 3. + <_> + + <_> + 9 15 6 9 -1. + <_> + 11 15 2 9 3. + <_> + + <_> + 3 1 18 21 -1. + <_> + 12 1 9 21 2. + <_> + + <_> + 6 8 12 7 -1. + <_> + 6 8 6 7 2. + <_> + + <_> + 8 5 6 9 -1. + <_> + 10 5 2 9 3. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 14 7 5 12 -1. + <_> + 14 11 5 4 3. + <_> + + <_> + 5 7 5 12 -1. + <_> + 5 11 5 4 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 0 1 6 17 -1. + <_> + 3 1 3 17 2. + <_> + + <_> + 3 1 19 9 -1. + <_> + 3 4 19 3 3. + <_> + + <_> + 3 18 12 6 -1. + <_> + 3 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 20 4 4 19 -1. + <_> + 20 4 2 19 2. + <_> + + <_> + 0 16 10 7 -1. + <_> + 5 16 5 7 2. + <_> + + <_> + 8 7 10 12 -1. + <_> + 13 7 5 6 2. + <_> + 8 13 5 6 2. + <_> + + <_> + 6 7 10 12 -1. + <_> + 6 7 5 6 2. + <_> + 11 13 5 6 2. + <_> + + <_> + 9 2 9 6 -1. + <_> + 12 2 3 6 3. + <_> + + <_> + 1 20 21 4 -1. + <_> + 8 20 7 4 3. + <_> + + <_> + 9 12 9 6 -1. + <_> + 9 14 9 2 3. + <_> + + <_> + 7 2 9 6 -1. + <_> + 10 2 3 6 3. + <_> + + <_> + 13 0 4 14 -1. + <_> + 13 0 2 14 2. + <_> + + <_> + 7 0 4 14 -1. + <_> + 9 0 2 14 2. + <_> + + <_> + 14 15 9 6 -1. + <_> + 14 17 9 2 3. + <_> + + <_> + 2 8 18 5 -1. + <_> + 8 8 6 5 3. + <_> + + <_> + 18 3 6 11 -1. + <_> + 20 3 2 11 3. + <_> + + <_> + 6 5 11 14 -1. + <_> + 6 12 11 7 2. + <_> + + <_> + 18 4 6 9 -1. + <_> + 18 7 6 3 3. + <_> + + <_> + 7 6 9 6 -1. + <_> + 7 8 9 2 3. + <_> + + <_> + 18 4 6 9 -1. + <_> + 18 7 6 3 3. + <_> + + <_> + 0 4 6 9 -1. + <_> + 0 7 6 3 3. + <_> + + <_> + 9 4 9 4 -1. + <_> + 9 6 9 2 2. + <_> + + <_> + 0 22 19 2 -1. + <_> + 0 23 19 1 2. + <_> + + <_> + 17 14 6 9 -1. + <_> + 17 17 6 3 3. + <_> + + <_> + 1 14 6 9 -1. + <_> + 1 17 6 3 3. + <_> + + <_> + 14 11 4 9 -1. + <_> + 14 11 2 9 2. + <_> + + <_> + 6 11 4 9 -1. + <_> + 8 11 2 9 2. + <_> + + <_> + 3 9 18 7 -1. + <_> + 9 9 6 7 3. + <_> + + <_> + 9 12 6 10 -1. + <_> + 9 17 6 5 2. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 6 17 18 3 -1. + <_> + 6 18 18 1 3. + <_> + + <_> + 1 17 18 3 -1. + <_> + 1 18 18 1 3. + <_> + + <_> + 10 6 11 12 -1. + <_> + 10 12 11 6 2. + <_> + + <_> + 5 6 14 6 -1. + <_> + 5 6 7 3 2. + <_> + 12 9 7 3 2. + <_> + + <_> + 5 4 15 4 -1. + <_> + 5 6 15 2 2. + <_> + + <_> + 0 0 22 2 -1. + <_> + 0 1 22 1 2. + <_> + + <_> + 0 0 24 24 -1. + <_> + 8 0 8 24 3. + <_> + + <_> + 1 15 18 4 -1. + <_> + 10 15 9 4 2. + <_> + + <_> + 6 8 12 9 -1. + <_> + 6 11 12 3 3. + <_> + + <_> + 4 12 7 12 -1. + <_> + 4 16 7 4 3. + <_> + + <_> + 1 2 22 6 -1. + <_> + 12 2 11 3 2. + <_> + 1 5 11 3 2. + <_> + + <_> + 5 20 14 3 -1. + <_> + 12 20 7 3 2. + <_> + + <_> + 0 0 24 16 -1. + <_> + 12 0 12 8 2. + <_> + 0 8 12 8 2. + <_> + + <_> + 3 13 18 4 -1. + <_> + 3 13 9 2 2. + <_> + 12 15 9 2 2. + <_> + + <_> + 2 10 22 2 -1. + <_> + 2 11 22 1 2. + <_> + + <_> + 6 3 11 8 -1. + <_> + 6 7 11 4 2. + <_> + + <_> + 14 5 6 6 -1. + <_> + 14 8 6 3 2. + <_> + + <_> + 0 7 24 6 -1. + <_> + 0 9 24 2 3. + <_> + + <_> + 14 0 10 10 -1. + <_> + 19 0 5 5 2. + <_> + 14 5 5 5 2. + <_> + + <_> + 0 0 10 10 -1. + <_> + 0 0 5 5 2. + <_> + 5 5 5 5 2. + <_> + + <_> + 0 1 24 4 -1. + <_> + 12 1 12 2 2. + <_> + 0 3 12 2 2. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 5 15 16 6 -1. + <_> + 13 15 8 3 2. + <_> + 5 18 8 3 2. + <_> + + <_> + 3 15 16 6 -1. + <_> + 3 15 8 3 2. + <_> + 11 18 8 3 2. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 0 13 21 10 -1. + <_> + 0 18 21 5 2. + <_> + + <_> + 13 0 6 24 -1. + <_> + 15 0 2 24 3. + <_> + + <_> + 7 4 6 11 -1. + <_> + 9 4 2 11 3. + <_> + + <_> + 9 5 9 6 -1. + <_> + 12 5 3 6 3. + <_> + + <_> + 1 4 2 20 -1. + <_> + 1 14 2 10 2. + <_> + + <_> + 13 0 6 24 -1. + <_> + 15 0 2 24 3. + <_> + + <_> + 5 0 6 24 -1. + <_> + 7 0 2 24 3. + <_> + + <_> + 16 7 6 14 -1. + <_> + 19 7 3 7 2. + <_> + 16 14 3 7 2. + <_> + + <_> + 4 7 4 12 -1. + <_> + 6 7 2 12 2. + <_> + + <_> + 0 5 24 14 -1. + <_> + 8 5 8 14 3. + <_> + + <_> + 5 13 10 6 -1. + <_> + 5 15 10 2 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 2 7 6 14 -1. + <_> + 2 7 3 7 2. + <_> + 5 14 3 7 2. + <_> + + <_> + 15 2 9 15 -1. + <_> + 18 2 3 15 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 2 2 2 9 3. + <_> + + <_> + 12 2 10 14 -1. + <_> + 17 2 5 7 2. + <_> + 12 9 5 7 2. + <_> + + <_> + 11 6 2 18 -1. + <_> + 12 6 1 18 2. + <_> + + <_> + 9 5 15 6 -1. + <_> + 14 5 5 6 3. + <_> + + <_> + 8 6 6 10 -1. + <_> + 10 6 2 10 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 3 3 9 7 -1. + <_> + 6 3 3 7 3. + <_> + + <_> + 6 7 14 3 -1. + <_> + 6 7 7 3 2. + <_> + + <_> + 7 7 8 6 -1. + <_> + 11 7 4 6 2. + <_> + + <_> + 12 7 7 12 -1. + <_> + 12 13 7 6 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 10 6 2 9 2. + <_> + 12 15 2 9 2. + <_> + + <_> + 16 14 6 9 -1. + <_> + 16 17 6 3 3. + <_> + + <_> + 4 0 6 13 -1. + <_> + 6 0 2 13 3. + <_> + + <_> + 2 2 21 3 -1. + <_> + 9 2 7 3 3. + <_> + + <_> + 5 4 5 12 -1. + <_> + 5 8 5 4 3. + <_> + + <_> + 10 3 4 10 -1. + <_> + 10 8 4 5 2. + <_> + + <_> + 8 4 5 8 -1. + <_> + 8 8 5 4 2. + <_> + + <_> + 6 0 11 9 -1. + <_> + 6 3 11 3 3. + <_> + + <_> + 6 6 12 5 -1. + <_> + 10 6 4 5 3. + <_> + + <_> + 0 0 24 5 -1. + <_> + 8 0 8 5 3. + <_> + + <_> + 1 10 23 6 -1. + <_> + 1 12 23 2 3. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 3 6 21 6 -1. + <_> + 3 8 21 2 3. + <_> + + <_> + 0 5 6 12 -1. + <_> + 2 5 2 12 3. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 8 7 8 10 -1. + <_> + 8 12 8 5 2. + <_> + + <_> + 5 7 15 12 -1. + <_> + 10 7 5 12 3. + <_> + + <_> + 0 17 10 6 -1. + <_> + 0 19 10 2 3. + <_> + + <_> + 14 18 9 6 -1. + <_> + 14 20 9 2 3. + <_> + + <_> + 9 6 6 16 -1. + <_> + 9 14 6 8 2. + <_> + + <_> + 14 18 9 6 -1. + <_> + 14 20 9 2 3. + <_> + + <_> + 1 18 9 6 -1. + <_> + 1 20 9 2 3. + <_> + + <_> + 15 9 9 6 -1. + <_> + 15 11 9 2 3. + <_> + + <_> + 0 9 9 6 -1. + <_> + 0 11 9 2 3. + <_> + + <_> + 17 3 6 9 -1. + <_> + 19 3 2 9 3. + <_> + + <_> + 2 17 18 3 -1. + <_> + 2 18 18 1 3. + <_> + + <_> + 3 15 21 6 -1. + <_> + 3 17 21 2 3. + <_> + + <_> + 9 17 6 6 -1. + <_> + 9 20 6 3 2. + <_> + + <_> + 18 3 6 9 -1. + <_> + 18 6 6 3 3. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 4 0 16 10 -1. + <_> + 12 0 8 5 2. + <_> + 4 5 8 5 2. + <_> + + <_> + 2 0 10 16 -1. + <_> + 2 0 5 8 2. + <_> + 7 8 5 8 2. + <_> + + <_> + 14 0 10 5 -1. + <_> + 14 0 5 5 2. + <_> + + <_> + 0 0 10 5 -1. + <_> + 5 0 5 5 2. + <_> + + <_> + 18 3 6 10 -1. + <_> + 18 3 3 10 2. + <_> + + <_> + 5 11 12 6 -1. + <_> + 5 11 6 3 2. + <_> + 11 14 6 3 2. + <_> + + <_> + 21 0 3 18 -1. + <_> + 22 0 1 18 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 8 8 9 7 -1. + <_> + 11 8 3 7 3. + <_> + + <_> + 7 12 8 10 -1. + <_> + 7 12 4 5 2. + <_> + 11 17 4 5 2. + <_> + + <_> + 21 0 3 18 -1. + <_> + 22 0 1 18 3. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 15 0 9 6 -1. + <_> + 15 2 9 2 3. + <_> + + <_> + 0 2 24 3 -1. + <_> + 0 3 24 1 3. + <_> + + <_> + 11 7 6 9 -1. + <_> + 13 7 2 9 3. + <_> + + <_> + 7 6 6 10 -1. + <_> + 9 6 2 10 3. + <_> + + <_> + 12 1 6 12 -1. + <_> + 14 1 2 12 3. + <_> + + <_> + 6 4 12 12 -1. + <_> + 6 10 12 6 2. + <_> + + <_> + 14 3 2 21 -1. + <_> + 14 3 1 21 2. + <_> + + <_> + 6 1 12 8 -1. + <_> + 6 5 12 4 2. + <_> + + <_> + 3 0 18 8 -1. + <_> + 3 4 18 4 2. + <_> + + <_> + 3 0 18 3 -1. + <_> + 3 1 18 1 3. + <_> + + <_> + 0 13 24 4 -1. + <_> + 12 13 12 2 2. + <_> + 0 15 12 2 2. + <_> + + <_> + 10 5 4 9 -1. + <_> + 12 5 2 9 2. + <_> + + <_> + 11 1 6 9 -1. + <_> + 13 1 2 9 3. + <_> + + <_> + 6 2 6 22 -1. + <_> + 8 2 2 22 3. + <_> + + <_> + 16 10 8 14 -1. + <_> + 20 10 4 7 2. + <_> + 16 17 4 7 2. + <_> + + <_> + 3 4 16 15 -1. + <_> + 3 9 16 5 3. + <_> + + <_> + 16 10 8 14 -1. + <_> + 20 10 4 7 2. + <_> + 16 17 4 7 2. + <_> + + <_> + 0 10 8 14 -1. + <_> + 0 10 4 7 2. + <_> + 4 17 4 7 2. + <_> + + <_> + 10 14 11 6 -1. + <_> + 10 17 11 3 2. + <_> + + <_> + 0 7 24 9 -1. + <_> + 8 7 8 9 3. + <_> + + <_> + 13 1 4 16 -1. + <_> + 13 1 2 16 2. + <_> + + <_> + 7 1 4 16 -1. + <_> + 9 1 2 16 2. + <_> + + <_> + 5 5 16 8 -1. + <_> + 13 5 8 4 2. + <_> + 5 9 8 4 2. + <_> + + <_> + 0 9 6 9 -1. + <_> + 0 12 6 3 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 3 12 6 9 -1. + <_> + 3 15 6 3 3. + <_> + + <_> + 8 14 9 6 -1. + <_> + 8 16 9 2 3. + <_> + + <_> + 2 13 8 10 -1. + <_> + 2 13 4 5 2. + <_> + 6 18 4 5 2. + <_> + + <_> + 15 5 3 18 -1. + <_> + 15 11 3 6 3. + <_> + + <_> + 3 5 18 3 -1. + <_> + 3 6 18 1 3. + <_> + + <_> + 17 5 6 11 -1. + <_> + 19 5 2 11 3. + <_> + + <_> + 1 5 6 11 -1. + <_> + 3 5 2 11 3. + <_> + + <_> + 19 1 4 9 -1. + <_> + 19 1 2 9 2. + <_> + + <_> + 1 1 4 9 -1. + <_> + 3 1 2 9 2. + <_> + + <_> + 4 15 18 9 -1. + <_> + 4 15 9 9 2. + <_> + + <_> + 6 9 12 4 -1. + <_> + 6 11 12 2 2. + <_> + + <_> + 15 2 9 6 -1. + <_> + 15 4 9 2 3. + <_> + + <_> + 0 2 9 6 -1. + <_> + 0 4 9 2 3. + <_> + + <_> + 15 0 6 17 -1. + <_> + 17 0 2 17 3. + <_> + + <_> + 3 0 6 17 -1. + <_> + 5 0 2 17 3. + <_> + + <_> + 8 17 9 4 -1. + <_> + 8 19 9 2 2. + <_> + + <_> + 6 5 3 18 -1. + <_> + 6 11 3 6 3. + <_> + + <_> + 5 2 14 12 -1. + <_> + 5 8 14 6 2. + <_> + + <_> + 10 2 3 12 -1. + <_> + 10 8 3 6 2. + <_> + + <_> + 10 7 14 15 -1. + <_> + 10 12 14 5 3. + <_> + + <_> + 0 7 14 15 -1. + <_> + 0 12 14 5 3. + <_> + + <_> + 15 0 9 6 -1. + <_> + 15 2 9 2 3. + <_> + + <_> + 0 0 9 6 -1. + <_> + 0 2 9 2 3. + <_> + + <_> + 12 6 6 14 -1. + <_> + 14 6 2 14 3. + <_> + + <_> + 9 7 6 9 -1. + <_> + 11 7 2 9 3. + <_> + + <_> + 12 6 6 15 -1. + <_> + 14 6 2 15 3. + <_> + + <_> + 6 6 6 15 -1. + <_> + 8 6 2 15 3. + <_> + + <_> + 15 3 8 9 -1. + <_> + 15 3 4 9 2. + <_> + + <_> + 0 0 9 21 -1. + <_> + 3 0 3 21 3. + <_> + + <_> + 11 9 8 12 -1. + <_> + 11 13 8 4 3. + <_> + + <_> + 6 7 10 12 -1. + <_> + 6 7 5 6 2. + <_> + 11 13 5 6 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 0 0 6 9 -1. + <_> + 0 3 6 3 3. + <_> + + <_> + 3 14 18 3 -1. + <_> + 3 15 18 1 3. + <_> + + <_> + 3 14 8 10 -1. + <_> + 3 14 4 5 2. + <_> + 7 19 4 5 2. + <_> + + <_> + 0 12 24 4 -1. + <_> + 12 12 12 2 2. + <_> + 0 14 12 2 2. + <_> + + <_> + 0 2 3 20 -1. + <_> + 1 2 1 20 3. + <_> + + <_> + 12 16 10 8 -1. + <_> + 17 16 5 4 2. + <_> + 12 20 5 4 2. + <_> + + <_> + 2 16 10 8 -1. + <_> + 2 16 5 4 2. + <_> + 7 20 5 4 2. + <_> + + <_> + 7 0 10 9 -1. + <_> + 7 3 10 3 3. + <_> + + <_> + 0 0 24 3 -1. + <_> + 8 0 8 3 3. + <_> + + <_> + 3 8 15 4 -1. + <_> + 3 10 15 2 2. + <_> + + <_> + 6 5 12 6 -1. + <_> + 10 5 4 6 3. + <_> + + <_> + 5 13 14 6 -1. + <_> + 5 16 14 3 2. + <_> + + <_> + 11 14 4 10 -1. + <_> + 11 19 4 5 2. + <_> + + <_> + 0 6 6 7 -1. + <_> + 3 6 3 7 2. + <_> + + <_> + 18 0 6 6 -1. + <_> + 18 0 3 6 2. + <_> + + <_> + 3 1 18 3 -1. + <_> + 3 2 18 1 3. + <_> + + <_> + 9 6 14 18 -1. + <_> + 9 12 14 6 3. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 0 20 24 3 -1. + <_> + 8 20 8 3 3. + <_> + + <_> + 13 11 6 7 -1. + <_> + 13 11 3 7 2. + <_> + + <_> + 4 12 10 6 -1. + <_> + 4 14 10 2 3. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 5 11 6 7 -1. + <_> + 8 11 3 7 2. + <_> + + <_> + 7 4 11 12 -1. + <_> + 7 8 11 4 3. + <_> + + <_> + 6 15 10 4 -1. + <_> + 6 17 10 2 2. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 4 0 6 9 -1. + <_> + 6 0 2 9 3. + <_> + + <_> + 11 2 4 15 -1. + <_> + 11 7 4 5 3. + <_> + + <_> + 0 0 20 3 -1. + <_> + 0 1 20 1 3. + <_> + + <_> + 13 18 10 6 -1. + <_> + 13 20 10 2 3. + <_> + + <_> + 2 7 6 11 -1. + <_> + 5 7 3 11 2. + <_> + + <_> + 10 14 10 9 -1. + <_> + 10 17 10 3 3. + <_> + + <_> + 8 2 4 9 -1. + <_> + 10 2 2 9 2. + <_> + + <_> + 14 3 10 4 -1. + <_> + 14 3 5 4 2. + <_> + + <_> + 6 6 12 6 -1. + <_> + 6 6 6 3 2. + <_> + 12 9 6 3 2. + <_> + + <_> + 8 8 8 10 -1. + <_> + 12 8 4 5 2. + <_> + 8 13 4 5 2. + <_> + + <_> + 7 4 4 16 -1. + <_> + 7 12 4 8 2. + <_> + + <_> + 8 8 9 4 -1. + <_> + 8 10 9 2 2. + <_> + + <_> + 5 2 14 9 -1. + <_> + 5 5 14 3 3. + <_> + + <_> + 3 16 19 8 -1. + <_> + 3 20 19 4 2. + <_> + + <_> + 0 0 10 8 -1. + <_> + 5 0 5 8 2. + <_> + + <_> + 5 2 16 18 -1. + <_> + 5 2 8 18 2. + <_> + + <_> + 0 11 24 11 -1. + <_> + 8 11 8 11 3. + <_> + + <_> + 3 3 18 5 -1. + <_> + 3 3 9 5 2. + <_> + + <_> + 1 16 18 3 -1. + <_> + 1 17 18 1 3. + <_> + + <_> + 5 17 18 3 -1. + <_> + 5 18 18 1 3. + <_> + + <_> + 1 13 9 6 -1. + <_> + 1 15 9 2 3. + <_> + + <_> + 1 9 23 10 -1. + <_> + 1 14 23 5 2. + <_> + + <_> + 3 7 18 3 -1. + <_> + 3 8 18 1 3. + <_> + + <_> + 6 8 12 3 -1. + <_> + 6 8 6 3 2. + <_> + + <_> + 6 2 3 22 -1. + <_> + 7 2 1 22 3. + <_> + + <_> + 14 17 10 6 -1. + <_> + 14 19 10 2 3. + <_> + + <_> + 1 18 10 6 -1. + <_> + 1 20 10 2 3. + <_> + + <_> + 11 3 6 12 -1. + <_> + 13 3 2 12 3. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 12 10 9 6 -1. + <_> + 15 10 3 6 3. + <_> + + <_> + 2 11 6 9 -1. + <_> + 5 11 3 9 2. + <_> + + <_> + 14 5 3 19 -1. + <_> + 15 5 1 19 3. + <_> + + <_> + 6 6 9 6 -1. + <_> + 6 8 9 2 3. + <_> + + <_> + 14 5 3 19 -1. + <_> + 15 5 1 19 3. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 5 21 18 3 -1. + <_> + 5 22 18 1 3. + <_> + + <_> + 1 10 18 4 -1. + <_> + 7 10 6 4 3. + <_> + + <_> + 13 4 8 10 -1. + <_> + 17 4 4 5 2. + <_> + 13 9 4 5 2. + <_> + + <_> + 7 8 9 6 -1. + <_> + 10 8 3 6 3. + <_> + + <_> + 12 9 9 8 -1. + <_> + 15 9 3 8 3. + <_> + + <_> + 0 6 5 12 -1. + <_> + 0 10 5 4 3. + <_> + + <_> + 7 6 14 6 -1. + <_> + 14 6 7 3 2. + <_> + 7 9 7 3 2. + <_> + + <_> + 7 5 3 19 -1. + <_> + 8 5 1 19 3. + <_> + + <_> + 8 4 15 20 -1. + <_> + 13 4 5 20 3. + <_> + + <_> + 1 4 15 20 -1. + <_> + 6 4 5 20 3. + <_> + + <_> + 13 10 6 6 -1. + <_> + 13 10 3 6 2. + <_> + + <_> + 5 10 6 6 -1. + <_> + 8 10 3 6 2. + <_> + + <_> + 14 2 6 14 -1. + <_> + 17 2 3 7 2. + <_> + 14 9 3 7 2. + <_> + + <_> + 4 2 6 14 -1. + <_> + 4 2 3 7 2. + <_> + 7 9 3 7 2. + <_> + + <_> + 12 4 6 7 -1. + <_> + 12 4 3 7 2. + <_> + + <_> + 9 4 6 9 -1. + <_> + 11 4 2 9 3. + <_> + + <_> + 11 4 8 10 -1. + <_> + 11 4 4 10 2. + <_> + + <_> + 5 4 8 10 -1. + <_> + 9 4 4 10 2. + <_> + + <_> + 8 18 10 6 -1. + <_> + 8 20 10 2 3. + <_> + + <_> + 1 18 21 6 -1. + <_> + 1 20 21 2 3. + <_> + + <_> + 9 2 12 6 -1. + <_> + 9 2 6 6 2. + <_> + + <_> + 3 2 12 6 -1. + <_> + 9 2 6 6 2. + <_> + + <_> + 12 5 12 6 -1. + <_> + 18 5 6 3 2. + <_> + 12 8 6 3 2. + <_> + + <_> + 8 8 6 9 -1. + <_> + 8 11 6 3 3. + <_> + + <_> + 2 7 20 6 -1. + <_> + 2 9 20 2 3. + <_> + + <_> + 0 5 12 6 -1. + <_> + 0 5 6 3 2. + <_> + 6 8 6 3 2. + <_> + + <_> + 14 14 8 10 -1. + <_> + 18 14 4 5 2. + <_> + 14 19 4 5 2. + <_> + + <_> + 2 14 8 10 -1. + <_> + 2 14 4 5 2. + <_> + 6 19 4 5 2. + <_> + + <_> + 2 11 20 13 -1. + <_> + 2 11 10 13 2. + <_> + + <_> + 6 9 12 5 -1. + <_> + 12 9 6 5 2. + <_> + + <_> + 5 6 16 6 -1. + <_> + 13 6 8 3 2. + <_> + 5 9 8 3 2. + <_> + + <_> + 1 19 9 4 -1. + <_> + 1 21 9 2 2. + <_> + + <_> + 7 5 12 5 -1. + <_> + 11 5 4 5 3. + <_> + + <_> + 3 5 14 12 -1. + <_> + 3 5 7 6 2. + <_> + 10 11 7 6 2. + <_> + + <_> + 9 4 9 6 -1. + <_> + 12 4 3 6 3. + <_> + + <_> + 2 6 19 3 -1. + <_> + 2 7 19 1 3. + <_> + + <_> + 18 10 6 9 -1. + <_> + 18 13 6 3 3. + <_> + + <_> + 3 7 18 2 -1. + <_> + 3 8 18 1 2. + <_> + + <_> + 20 2 4 18 -1. + <_> + 22 2 2 9 2. + <_> + 20 11 2 9 2. + <_> + + <_> + 2 18 20 3 -1. + <_> + 2 19 20 1 3. + <_> + + <_> + 1 9 22 3 -1. + <_> + 1 10 22 1 3. + <_> + + <_> + 0 2 4 18 -1. + <_> + 0 2 2 9 2. + <_> + 2 11 2 9 2. + <_> + + <_> + 19 0 4 23 -1. + <_> + 19 0 2 23 2. + <_> + + <_> + 0 3 6 19 -1. + <_> + 3 3 3 19 2. + <_> + + <_> + 18 2 6 9 -1. + <_> + 20 2 2 9 3. + <_> + + <_> + 0 5 10 6 -1. + <_> + 0 7 10 2 3. + <_> + + <_> + 7 0 12 12 -1. + <_> + 13 0 6 6 2. + <_> + 7 6 6 6 2. + <_> + + <_> + 0 3 24 6 -1. + <_> + 0 3 12 3 2. + <_> + 12 6 12 3 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 8 9 4 15 -1. + <_> + 8 14 4 5 3. + <_> + + <_> + 4 11 17 6 -1. + <_> + 4 14 17 3 2. + <_> + + <_> + 2 5 18 8 -1. + <_> + 2 5 9 4 2. + <_> + 11 9 9 4 2. + <_> + + <_> + 7 6 14 6 -1. + <_> + 14 6 7 3 2. + <_> + 7 9 7 3 2. + <_> + + <_> + 3 6 14 6 -1. + <_> + 3 6 7 3 2. + <_> + 10 9 7 3 2. + <_> + + <_> + 16 5 3 18 -1. + <_> + 17 5 1 18 3. + <_> + + <_> + 5 5 3 18 -1. + <_> + 6 5 1 18 3. + <_> + + <_> + 10 10 14 4 -1. + <_> + 10 12 14 2 2. + <_> + + <_> + 4 10 9 4 -1. + <_> + 4 12 9 2 2. + <_> + + <_> + 2 0 18 9 -1. + <_> + 2 3 18 3 3. + <_> + + <_> + 6 3 12 8 -1. + <_> + 10 3 4 8 3. + <_> + + <_> + 1 1 8 5 -1. + <_> + 5 1 4 5 2. + <_> + + <_> + 12 7 7 8 -1. + <_> + 12 11 7 4 2. + <_> + + <_> + 0 12 22 4 -1. + <_> + 0 14 22 2 2. + <_> + + <_> + 15 6 4 15 -1. + <_> + 15 11 4 5 3. + <_> + + <_> + 5 7 7 8 -1. + <_> + 5 11 7 4 2. + <_> + + <_> + 8 18 9 4 -1. + <_> + 8 20 9 2 2. + <_> + + <_> + 1 2 22 4 -1. + <_> + 1 4 22 2 2. + <_> + + <_> + 17 3 6 17 -1. + <_> + 19 3 2 17 3. + <_> + + <_> + 8 2 8 18 -1. + <_> + 8 11 8 9 2. + <_> + + <_> + 17 0 6 12 -1. + <_> + 20 0 3 6 2. + <_> + 17 6 3 6 2. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 15 5 9 12 -1. + <_> + 15 11 9 6 2. + <_> + + <_> + 2 22 18 2 -1. + <_> + 2 23 18 1 2. + <_> + + <_> + 10 10 12 6 -1. + <_> + 16 10 6 3 2. + <_> + 10 13 6 3 2. + <_> + + <_> + 0 1 4 11 -1. + <_> + 2 1 2 11 2. + <_> + + <_> + 20 0 4 10 -1. + <_> + 20 0 2 10 2. + <_> + + <_> + 1 3 6 17 -1. + <_> + 3 3 2 17 3. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 13 8 9 -1. + <_> + 0 16 8 3 3. + <_> + + <_> + 16 8 6 12 -1. + <_> + 16 12 6 4 3. + <_> + + <_> + 2 8 6 12 -1. + <_> + 2 12 6 4 3. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 1 5 19 3 -1. + <_> + 1 6 19 1 3. + <_> + + <_> + 11 8 9 7 -1. + <_> + 14 8 3 7 3. + <_> + + <_> + 3 8 12 9 -1. + <_> + 3 11 12 3 3. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 10 0 4 12 -1. + <_> + 10 6 4 6 2. + <_> + + <_> + 3 9 18 14 -1. + <_> + 3 9 9 14 2. + <_> + + <_> + 0 0 4 9 -1. + <_> + 2 0 2 9 2. + <_> + + <_> + 12 5 4 18 -1. + <_> + 12 5 2 18 2. + <_> + + <_> + 8 5 4 18 -1. + <_> + 10 5 2 18 2. + <_> + + <_> + 10 5 6 10 -1. + <_> + 12 5 2 10 3. + <_> + + <_> + 9 4 4 11 -1. + <_> + 11 4 2 11 2. + <_> + + <_> + 4 16 18 3 -1. + <_> + 4 17 18 1 3. + <_> + + <_> + 0 16 20 3 -1. + <_> + 0 17 20 1 3. + <_> + + <_> + 9 9 6 12 -1. + <_> + 9 13 6 4 3. + <_> + + <_> + 8 13 8 8 -1. + <_> + 8 17 8 4 2. + <_> + + <_> + 13 10 3 12 -1. + <_> + 13 16 3 6 2. + <_> + + <_> + 5 9 14 14 -1. + <_> + 5 9 7 7 2. + <_> + 12 16 7 7 2. + <_> + + <_> + 0 0 24 10 -1. + <_> + 12 0 12 5 2. + <_> + 0 5 12 5 2. + <_> + + <_> + 1 11 18 2 -1. + <_> + 1 12 18 1 2. + <_> + + <_> + 19 5 5 12 -1. + <_> + 19 9 5 4 3. + <_> + + <_> + 0 5 5 12 -1. + <_> + 0 9 5 4 3. + <_> + + <_> + 16 6 8 18 -1. + <_> + 20 6 4 9 2. + <_> + 16 15 4 9 2. + <_> + + <_> + 0 6 8 18 -1. + <_> + 0 6 4 9 2. + <_> + 4 15 4 9 2. + <_> + + <_> + 12 5 12 12 -1. + <_> + 18 5 6 6 2. + <_> + 12 11 6 6 2. + <_> + + <_> + 7 6 6 9 -1. + <_> + 9 6 2 9 3. + <_> + + <_> + 9 13 6 11 -1. + <_> + 11 13 2 11 3. + <_> + + <_> + 0 5 12 12 -1. + <_> + 0 5 6 6 2. + <_> + 6 11 6 6 2. + <_> + + <_> + 1 2 23 3 -1. + <_> + 1 3 23 1 3. + <_> + + <_> + 1 15 19 3 -1. + <_> + 1 16 19 1 3. + <_> + + <_> + 13 17 11 4 -1. + <_> + 13 19 11 2 2. + <_> + + <_> + 0 13 8 5 -1. + <_> + 4 13 4 5 2. + <_> + + <_> + 12 10 10 4 -1. + <_> + 12 10 5 4 2. + <_> + + <_> + 4 6 9 9 -1. + <_> + 4 9 9 3 3. + <_> + + <_> + 15 14 9 6 -1. + <_> + 15 16 9 2 3. + <_> + + <_> + 1 12 9 6 -1. + <_> + 1 14 9 2 3. + <_> + + <_> + 3 10 20 8 -1. + <_> + 13 10 10 4 2. + <_> + 3 14 10 4 2. + <_> + + <_> + 2 0 9 18 -1. + <_> + 5 0 3 18 3. + <_> + + <_> + 13 11 9 10 -1. + <_> + 16 11 3 10 3. + <_> + + <_> + 1 2 8 5 -1. + <_> + 5 2 4 5 2. + <_> + + <_> + 3 4 21 6 -1. + <_> + 10 4 7 6 3. + <_> + + <_> + 7 0 10 14 -1. + <_> + 7 0 5 7 2. + <_> + 12 7 5 7 2. + <_> + + <_> + 12 17 12 4 -1. + <_> + 12 19 12 2 2. + <_> + + <_> + 0 6 23 4 -1. + <_> + 0 8 23 2 2. + <_> + + <_> + 13 10 8 10 -1. + <_> + 17 10 4 5 2. + <_> + 13 15 4 5 2. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 15 16 9 4 -1. + <_> + 15 18 9 2 2. + <_> + + <_> + 0 16 9 4 -1. + <_> + 0 18 9 2 2. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 5 11 6 6 -1. + <_> + 8 11 3 6 2. + <_> + + <_> + 0 3 24 6 -1. + <_> + 12 3 12 3 2. + <_> + 0 6 12 3 2. + <_> + + <_> + 2 4 18 3 -1. + <_> + 2 5 18 1 3. + <_> + + <_> + 0 0 24 4 -1. + <_> + 12 0 12 2 2. + <_> + 0 2 12 2 2. + <_> + + <_> + 1 16 18 3 -1. + <_> + 1 17 18 1 3. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 6 17 18 3 -1. + <_> + 6 18 18 1 3. + <_> + + <_> + 8 8 6 10 -1. + <_> + 10 8 2 10 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 8 8 5 8 -1. + <_> + 8 12 5 4 2. + <_> + + <_> + 12 8 6 8 -1. + <_> + 12 12 6 4 2. + <_> + + <_> + 6 5 6 11 -1. + <_> + 8 5 2 11 3. + <_> + + <_> + 13 6 8 9 -1. + <_> + 13 9 8 3 3. + <_> + + <_> + 1 7 21 6 -1. + <_> + 1 9 21 2 3. + <_> + + <_> + 15 5 3 12 -1. + <_> + 15 11 3 6 2. + <_> + + <_> + 6 9 11 12 -1. + <_> + 6 13 11 4 3. + <_> + + <_> + 13 8 10 8 -1. + <_> + 18 8 5 4 2. + <_> + 13 12 5 4 2. + <_> + + <_> + 5 8 12 3 -1. + <_> + 11 8 6 3 2. + <_> + + <_> + 6 11 18 4 -1. + <_> + 12 11 6 4 3. + <_> + + <_> + 0 0 22 22 -1. + <_> + 0 11 22 11 2. + <_> + + <_> + 11 2 6 8 -1. + <_> + 11 6 6 4 2. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 8 3 6 14 -1. + <_> + 8 3 3 7 2. + <_> + 11 10 3 7 2. + <_> + + <_> + 3 10 18 8 -1. + <_> + 9 10 6 8 3. + <_> + + <_> + 10 0 3 14 -1. + <_> + 10 7 3 7 2. + <_> + + <_> + 4 3 16 20 -1. + <_> + 4 13 16 10 2. + <_> + + <_> + 9 4 6 10 -1. + <_> + 11 4 2 10 3. + <_> + + <_> + 5 0 16 4 -1. + <_> + 5 2 16 2 2. + <_> + + <_> + 2 5 18 4 -1. + <_> + 8 5 6 4 3. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 8 4 8 5 -1. + <_> + 12 4 4 5 2. + <_> + + <_> + 12 10 10 4 -1. + <_> + 12 10 5 4 2. + <_> + + <_> + 2 10 10 4 -1. + <_> + 7 10 5 4 2. + <_> + + <_> + 7 11 12 5 -1. + <_> + 11 11 4 5 3. + <_> + + <_> + 3 10 8 10 -1. + <_> + 3 10 4 5 2. + <_> + 7 15 4 5 2. + <_> + + <_> + 11 12 9 8 -1. + <_> + 14 12 3 8 3. + <_> + + <_> + 0 21 24 3 -1. + <_> + 8 21 8 3 3. + <_> + + <_> + 3 20 18 4 -1. + <_> + 9 20 6 4 3. + <_> + + <_> + 1 15 9 6 -1. + <_> + 1 17 9 2 3. + <_> + + <_> + 11 17 10 4 -1. + <_> + 11 19 10 2 2. + <_> + + <_> + 9 12 4 12 -1. + <_> + 9 18 4 6 2. + <_> + + <_> + 9 6 9 6 -1. + <_> + 12 6 3 6 3. + <_> + + <_> + 1 13 6 9 -1. + <_> + 1 16 6 3 3. + <_> + + <_> + 6 16 12 4 -1. + <_> + 6 18 12 2 2. + <_> + + <_> + 1 5 20 3 -1. + <_> + 1 6 20 1 3. + <_> + + <_> + 8 1 9 9 -1. + <_> + 8 4 9 3 3. + <_> + + <_> + 2 19 9 4 -1. + <_> + 2 21 9 2 2. + <_> + + <_> + 11 1 4 18 -1. + <_> + 11 7 4 6 3. + <_> + + <_> + 7 2 8 12 -1. + <_> + 7 2 4 6 2. + <_> + 11 8 4 6 2. + <_> + + <_> + 11 10 9 8 -1. + <_> + 14 10 3 8 3. + <_> + + <_> + 5 11 12 5 -1. + <_> + 9 11 4 5 3. + <_> + + <_> + 11 9 9 6 -1. + <_> + 14 9 3 6 3. + <_> + + <_> + 5 10 6 9 -1. + <_> + 7 10 2 9 3. + <_> + + <_> + 4 7 5 12 -1. + <_> + 4 11 5 4 3. + <_> + + <_> + 2 0 21 6 -1. + <_> + 9 0 7 6 3. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 9 0 6 15 -1. + <_> + 11 0 2 15 3. + <_> + + <_> + 2 2 18 2 -1. + <_> + 2 3 18 1 2. + <_> + + <_> + 8 17 8 6 -1. + <_> + 8 20 8 3 2. + <_> + + <_> + 3 0 18 2 -1. + <_> + 3 1 18 1 2. + <_> + + <_> + 8 0 9 6 -1. + <_> + 11 0 3 6 3. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 6 7 12 5 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 0 3 6 9 -1. + <_> + 2 3 2 9 3. + <_> + + <_> + 20 2 4 9 -1. + <_> + 20 2 2 9 2. + <_> + + <_> + 0 2 4 9 -1. + <_> + 2 2 2 9 2. + <_> + + <_> + 0 1 24 4 -1. + <_> + 12 1 12 2 2. + <_> + 0 3 12 2 2. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 14 13 9 6 -1. + <_> + 14 15 9 2 3. + <_> + + <_> + 0 15 19 3 -1. + <_> + 0 16 19 1 3. + <_> + + <_> + 1 5 22 12 -1. + <_> + 12 5 11 6 2. + <_> + 1 11 11 6 2. + <_> + + <_> + 5 13 6 6 -1. + <_> + 8 13 3 6 2. + <_> + + <_> + 4 2 20 3 -1. + <_> + 4 3 20 1 3. + <_> + + <_> + 8 14 6 10 -1. + <_> + 10 14 2 10 3. + <_> + + <_> + 6 12 16 6 -1. + <_> + 14 12 8 3 2. + <_> + 6 15 8 3 2. + <_> + + <_> + 2 13 8 9 -1. + <_> + 2 16 8 3 3. + <_> + + <_> + 11 8 6 14 -1. + <_> + 14 8 3 7 2. + <_> + 11 15 3 7 2. + <_> + + <_> + 2 12 16 6 -1. + <_> + 2 12 8 3 2. + <_> + 10 15 8 3 2. + <_> + + <_> + 5 16 16 8 -1. + <_> + 5 20 16 4 2. + <_> + + <_> + 9 1 4 12 -1. + <_> + 9 7 4 6 2. + <_> + + <_> + 8 2 8 10 -1. + <_> + 12 2 4 5 2. + <_> + 8 7 4 5 2. + <_> + + <_> + 6 6 12 6 -1. + <_> + 6 6 6 3 2. + <_> + 12 9 6 3 2. + <_> + + <_> + 10 7 6 9 -1. + <_> + 12 7 2 9 3. + <_> + + <_> + 0 0 8 12 -1. + <_> + 0 0 4 6 2. + <_> + 4 6 4 6 2. + <_> + + <_> + 18 8 6 9 -1. + <_> + 18 11 6 3 3. + <_> + + <_> + 2 12 6 6 -1. + <_> + 5 12 3 6 2. + <_> + + <_> + 3 21 21 3 -1. + <_> + 10 21 7 3 3. + <_> + + <_> + 2 0 16 6 -1. + <_> + 2 3 16 3 2. + <_> + + <_> + 13 6 7 6 -1. + <_> + 13 9 7 3 2. + <_> + + <_> + 6 4 4 14 -1. + <_> + 6 11 4 7 2. + <_> + + <_> + 9 7 6 9 -1. + <_> + 11 7 2 9 3. + <_> + + <_> + 7 8 6 14 -1. + <_> + 7 8 3 7 2. + <_> + 10 15 3 7 2. + <_> + + <_> + 18 8 4 16 -1. + <_> + 18 16 4 8 2. + <_> + + <_> + 9 14 6 10 -1. + <_> + 11 14 2 10 3. + <_> + + <_> + 6 11 12 5 -1. + <_> + 10 11 4 5 3. + <_> + + <_> + 0 12 23 3 -1. + <_> + 0 13 23 1 3. + <_> + + <_> + 13 0 6 12 -1. + <_> + 15 0 2 12 3. + <_> + + <_> + 0 10 12 5 -1. + <_> + 4 10 4 5 3. + <_> + + <_> + 13 2 10 4 -1. + <_> + 13 4 10 2 2. + <_> + + <_> + 5 0 6 12 -1. + <_> + 7 0 2 12 3. + <_> + + <_> + 11 6 9 6 -1. + <_> + 14 6 3 6 3. + <_> + + <_> + 4 6 9 6 -1. + <_> + 7 6 3 6 3. + <_> + + <_> + 6 11 18 13 -1. + <_> + 12 11 6 13 3. + <_> + + <_> + 0 11 18 13 -1. + <_> + 6 11 6 13 3. + <_> + + <_> + 12 16 12 6 -1. + <_> + 16 16 4 6 3. + <_> + + <_> + 0 6 21 3 -1. + <_> + 0 7 21 1 3. + <_> + + <_> + 12 16 12 6 -1. + <_> + 16 16 4 6 3. + <_> + + <_> + 5 7 6 14 -1. + <_> + 5 14 6 7 2. + <_> + + <_> + 5 10 19 2 -1. + <_> + 5 11 19 1 2. + <_> + + <_> + 5 4 14 4 -1. + <_> + 5 6 14 2 2. + <_> + + <_> + 3 18 18 4 -1. + <_> + 9 18 6 4 3. + <_> + + <_> + 7 0 4 9 -1. + <_> + 9 0 2 9 2. + <_> + + <_> + 13 3 11 4 -1. + <_> + 13 5 11 2 2. + <_> + + <_> + 2 0 9 6 -1. + <_> + 5 0 3 6 3. + <_> + + <_> + 19 1 4 23 -1. + <_> + 19 1 2 23 2. + <_> + + <_> + 1 1 4 23 -1. + <_> + 3 1 2 23 2. + <_> + + <_> + 5 16 18 3 -1. + <_> + 5 17 18 1 3. + <_> + + <_> + 0 3 11 4 -1. + <_> + 0 5 11 2 2. + <_> + + <_> + 2 16 20 3 -1. + <_> + 2 17 20 1 3. + <_> + + <_> + 5 3 13 4 -1. + <_> + 5 5 13 2 2. + <_> + + <_> + 1 9 22 15 -1. + <_> + 1 9 11 15 2. + <_> + + <_> + 3 4 14 3 -1. + <_> + 10 4 7 3 2. + <_> + + <_> + 8 7 10 4 -1. + <_> + 8 7 5 4 2. + <_> + + <_> + 6 7 10 4 -1. + <_> + 11 7 5 4 2. + <_> + + <_> + 10 4 6 9 -1. + <_> + 12 4 2 9 3. + <_> + + <_> + 1 12 9 6 -1. + <_> + 4 12 3 6 3. + <_> + + <_> + 8 3 8 10 -1. + <_> + 12 3 4 5 2. + <_> + 8 8 4 5 2. + <_> + + <_> + 3 6 16 6 -1. + <_> + 3 6 8 3 2. + <_> + 11 9 8 3 2. + <_> + + <_> + 5 6 14 6 -1. + <_> + 5 9 14 3 2. + <_> + + <_> + 4 3 9 6 -1. + <_> + 4 5 9 2 3. + <_> + + <_> + 6 3 18 2 -1. + <_> + 6 4 18 1 2. + <_> + + <_> + 7 6 9 6 -1. + <_> + 10 6 3 6 3. + <_> + + <_> + 0 1 24 3 -1. + <_> + 0 2 24 1 3. + <_> + + <_> + 0 17 10 6 -1. + <_> + 0 19 10 2 3. + <_> + + <_> + 3 18 18 3 -1. + <_> + 3 19 18 1 3. + <_> + + <_> + 2 5 6 16 -1. + <_> + 2 5 3 8 2. + <_> + 5 13 3 8 2. + <_> + + <_> + 7 6 11 6 -1. + <_> + 7 8 11 2 3. + <_> + + <_> + 5 2 12 22 -1. + <_> + 5 13 12 11 2. + <_> + + <_> + 10 7 4 10 -1. + <_> + 10 12 4 5 2. + <_> + + <_> + 9 0 4 18 -1. + <_> + 9 6 4 6 3. + <_> + + <_> + 18 8 6 9 -1. + <_> + 18 11 6 3 3. + <_> + + <_> + 4 7 15 10 -1. + <_> + 9 7 5 10 3. + <_> + + <_> + 10 5 6 9 -1. + <_> + 12 5 2 9 3. + <_> + + <_> + 9 9 6 10 -1. + <_> + 11 9 2 10 3. + <_> + + <_> + 11 14 6 10 -1. + <_> + 13 14 2 10 3. + <_> + + <_> + 7 14 6 10 -1. + <_> + 9 14 2 10 3. + <_> + + <_> + 4 8 16 9 -1. + <_> + 4 11 16 3 3. + <_> + + <_> + 2 11 20 3 -1. + <_> + 2 12 20 1 3. + <_> + + <_> + 13 0 4 13 -1. + <_> + 13 0 2 13 2. + <_> + + <_> + 7 0 4 13 -1. + <_> + 9 0 2 13 2. + <_> + + <_> + 3 1 18 7 -1. + <_> + 9 1 6 7 3. + <_> + + <_> + 1 11 6 9 -1. + <_> + 1 14 6 3 3. + <_> + + <_> + 8 18 9 6 -1. + <_> + 8 20 9 2 3. + <_> + + <_> + 3 9 15 6 -1. + <_> + 3 11 15 2 3. + <_> + + <_> + 5 10 19 2 -1. + <_> + 5 11 19 1 2. + <_> + + <_> + 8 6 7 16 -1. + <_> + 8 14 7 8 2. + <_> + + <_> + 9 14 9 6 -1. + <_> + 9 16 9 2 3. + <_> + + <_> + 0 7 8 12 -1. + <_> + 0 11 8 4 3. + <_> + + <_> + 6 4 18 3 -1. + <_> + 6 5 18 1 3. + <_> + + <_> + 0 16 12 6 -1. + <_> + 4 16 4 6 3. + <_> + + <_> + 13 13 9 4 -1. + <_> + 13 15 9 2 2. + <_> + + <_> + 5 8 14 14 -1. + <_> + 5 8 7 7 2. + <_> + 12 15 7 7 2. + <_> + + <_> + 1 16 22 6 -1. + <_> + 12 16 11 3 2. + <_> + 1 19 11 3 2. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 9 5 10 10 -1. + <_> + 14 5 5 5 2. + <_> + 9 10 5 5 2. + <_> + + <_> + 5 5 10 10 -1. + <_> + 5 5 5 5 2. + <_> + 10 10 5 5 2. + <_> + + <_> + 4 6 16 6 -1. + <_> + 12 6 8 3 2. + <_> + 4 9 8 3 2. + <_> + + <_> + 0 7 6 9 -1. + <_> + 0 10 6 3 3. + <_> + + <_> + 16 10 8 14 -1. + <_> + 20 10 4 7 2. + <_> + 16 17 4 7 2. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 18 6 6 2. + <_> + + <_> + 8 10 8 12 -1. + <_> + 12 10 4 6 2. + <_> + 8 16 4 6 2. + <_> + + <_> + 8 0 4 9 -1. + <_> + 10 0 2 9 2. + <_> + + <_> + 10 4 8 16 -1. + <_> + 14 4 4 8 2. + <_> + 10 12 4 8 2. + <_> + + <_> + 7 10 10 6 -1. + <_> + 7 12 10 2 3. + <_> + + <_> + 5 6 14 14 -1. + <_> + 12 6 7 7 2. + <_> + 5 13 7 7 2. + <_> + + <_> + 2 11 20 2 -1. + <_> + 2 12 20 1 2. + <_> + + <_> + 18 8 4 16 -1. + <_> + 18 16 4 8 2. + <_> + + <_> + 1 11 12 10 -1. + <_> + 1 11 6 5 2. + <_> + 7 16 6 5 2. + <_> + + <_> + 6 9 12 4 -1. + <_> + 6 11 12 2 2. + <_> + + <_> + 9 12 6 7 -1. + <_> + 12 12 3 7 2. + <_> + + <_> + 10 4 8 16 -1. + <_> + 14 4 4 8 2. + <_> + 10 12 4 8 2. + <_> + + <_> + 6 4 8 16 -1. + <_> + 6 4 4 8 2. + <_> + 10 12 4 8 2. + <_> + + <_> + 8 9 9 6 -1. + <_> + 11 9 3 6 3. + <_> + + <_> + 1 5 16 12 -1. + <_> + 1 5 8 6 2. + <_> + 9 11 8 6 2. + <_> + + <_> + 9 9 6 8 -1. + <_> + 9 9 3 8 2. + <_> + + <_> + 6 0 3 18 -1. + <_> + 7 0 1 18 3. + <_> + + <_> + 17 9 5 14 -1. + <_> + 17 16 5 7 2. + <_> + + <_> + 2 9 5 14 -1. + <_> + 2 16 5 7 2. + <_> + + <_> + 7 4 10 6 -1. + <_> + 7 7 10 3 2. + <_> + + <_> + 1 3 23 18 -1. + <_> + 1 9 23 6 3. + <_> + + <_> + 1 1 21 3 -1. + <_> + 8 1 7 3 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 3 18 12 6 -1. + <_> + 3 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 16 8 8 16 -1. + <_> + 20 8 4 8 2. + <_> + 16 16 4 8 2. + <_> + + <_> + 0 19 24 4 -1. + <_> + 8 19 8 4 3. + <_> + + <_> + 16 8 8 16 -1. + <_> + 20 8 4 8 2. + <_> + 16 16 4 8 2. + <_> + + <_> + 0 8 8 16 -1. + <_> + 0 8 4 8 2. + <_> + 4 16 4 8 2. + <_> + + <_> + 8 12 8 10 -1. + <_> + 8 17 8 5 2. + <_> + + <_> + 5 7 5 8 -1. + <_> + 5 11 5 4 2. + <_> + + <_> + 4 1 19 2 -1. + <_> + 4 2 19 1 2. + <_> + + <_> + 0 12 24 9 -1. + <_> + 8 12 8 9 3. + <_> + + <_> + 6 0 13 8 -1. + <_> + 6 4 13 4 2. + <_> + + <_> + 0 0 24 3 -1. + <_> + 0 1 24 1 3. + <_> + + <_> + 20 3 4 11 -1. + <_> + 20 3 2 11 2. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 6 11 12 8 -1. + <_> + 12 11 6 4 2. + <_> + 6 15 6 4 2. + <_> + + <_> + 0 8 12 6 -1. + <_> + 0 8 6 3 2. + <_> + 6 11 6 3 2. + <_> + + <_> + 6 17 18 3 -1. + <_> + 6 18 18 1 3. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 20 3 4 9 -1. + <_> + 20 3 2 9 2. + <_> + + <_> + 0 3 4 9 -1. + <_> + 2 3 2 9 2. + <_> + + <_> + 15 0 9 19 -1. + <_> + 18 0 3 19 3. + <_> + + <_> + 0 0 9 19 -1. + <_> + 3 0 3 19 3. + <_> + + <_> + 13 11 6 8 -1. + <_> + 13 11 3 8 2. + <_> + + <_> + 5 11 6 8 -1. + <_> + 8 11 3 8 2. + <_> + + <_> + 5 11 19 3 -1. + <_> + 5 12 19 1 3. + <_> + + <_> + 3 20 18 4 -1. + <_> + 9 20 6 4 3. + <_> + + <_> + 6 6 16 6 -1. + <_> + 6 8 16 2 3. + <_> + + <_> + 6 0 9 6 -1. + <_> + 9 0 3 6 3. + <_> + + <_> + 10 3 4 14 -1. + <_> + 10 10 4 7 2. + <_> + + <_> + 1 5 15 12 -1. + <_> + 1 11 15 6 2. + <_> + + <_> + 11 12 8 5 -1. + <_> + 11 12 4 5 2. + <_> + + <_> + 5 0 6 9 -1. + <_> + 7 0 2 9 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 5 5 12 8 -1. + <_> + 5 5 6 4 2. + <_> + 11 9 6 4 2. + <_> + + <_> + 13 12 11 6 -1. + <_> + 13 14 11 2 3. + <_> + + <_> + 0 13 21 3 -1. + <_> + 0 14 21 1 3. + <_> + + <_> + 8 1 8 12 -1. + <_> + 12 1 4 6 2. + <_> + 8 7 4 6 2. + <_> + + <_> + 1 0 6 12 -1. + <_> + 1 0 3 6 2. + <_> + 4 6 3 6 2. + <_> + + <_> + 2 2 21 2 -1. + <_> + 2 3 21 1 2. + <_> + + <_> + 2 2 19 3 -1. + <_> + 2 3 19 1 3. + <_> + + <_> + 17 10 6 14 -1. + <_> + 20 10 3 7 2. + <_> + 17 17 3 7 2. + <_> + + <_> + 1 10 6 14 -1. + <_> + 1 10 3 7 2. + <_> + 4 17 3 7 2. + <_> + + <_> + 7 6 14 14 -1. + <_> + 14 6 7 7 2. + <_> + 7 13 7 7 2. + <_> + + <_> + 0 12 9 6 -1. + <_> + 0 14 9 2 3. + <_> + + <_> + 15 14 8 9 -1. + <_> + 15 17 8 3 3. + <_> + + <_> + 1 1 22 4 -1. + <_> + 1 1 11 2 2. + <_> + 12 3 11 2 2. + <_> + + <_> + 9 11 9 6 -1. + <_> + 9 13 9 2 3. + <_> + + <_> + 0 15 18 3 -1. + <_> + 0 16 18 1 3. + <_> + + <_> + 16 14 7 9 -1. + <_> + 16 17 7 3 3. + <_> + + <_> + 4 3 16 4 -1. + <_> + 12 3 8 4 2. + <_> + + <_> + 7 6 12 5 -1. + <_> + 7 6 6 5 2. + <_> + + <_> + 9 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 12 1 4 10 -1. + <_> + 12 1 2 10 2. + <_> + + <_> + 8 1 4 10 -1. + <_> + 10 1 2 10 2. + <_> + + <_> + 15 15 6 9 -1. + <_> + 15 18 6 3 3. + <_> + + <_> + 3 15 6 9 -1. + <_> + 3 18 6 3 3. + <_> + + <_> + 15 1 3 19 -1. + <_> + 16 1 1 19 3. + <_> + + <_> + 1 3 6 9 -1. + <_> + 3 3 2 9 3. + <_> + + <_> + 15 0 3 19 -1. + <_> + 16 0 1 19 3. + <_> + + <_> + 6 3 12 4 -1. + <_> + 12 3 6 4 2. + <_> + + <_> + 10 5 4 9 -1. + <_> + 10 5 2 9 2. + <_> + + <_> + 6 0 3 19 -1. + <_> + 7 0 1 19 3. + <_> + + <_> + 11 1 3 12 -1. + <_> + 11 7 3 6 2. + <_> + + <_> + 6 7 10 5 -1. + <_> + 11 7 5 5 2. + <_> + + <_> + 11 3 3 18 -1. + <_> + 12 3 1 18 3. + <_> + + <_> + 9 3 6 12 -1. + <_> + 11 3 2 12 3. + <_> + + <_> + 3 7 19 3 -1. + <_> + 3 8 19 1 3. + <_> + + <_> + 2 7 18 3 -1. + <_> + 2 8 18 1 3. + <_> + + <_> + 3 13 18 4 -1. + <_> + 12 13 9 2 2. + <_> + 3 15 9 2 2. + <_> + + <_> + 3 5 6 9 -1. + <_> + 5 5 2 9 3. + <_> + + <_> + 4 1 20 4 -1. + <_> + 14 1 10 2 2. + <_> + 4 3 10 2 2. + <_> + + <_> + 0 1 20 4 -1. + <_> + 0 1 10 2 2. + <_> + 10 3 10 2 2. + <_> + + <_> + 10 15 6 6 -1. + <_> + 10 15 3 6 2. + <_> + + <_> + 0 2 24 8 -1. + <_> + 8 2 8 8 3. + <_> + + <_> + 5 5 18 3 -1. + <_> + 5 6 18 1 3. + <_> + + <_> + 8 15 6 6 -1. + <_> + 11 15 3 6 2. + <_> + + <_> + 11 12 8 5 -1. + <_> + 11 12 4 5 2. + <_> + + <_> + 5 12 8 5 -1. + <_> + 9 12 4 5 2. + <_> + + <_> + 5 0 14 6 -1. + <_> + 5 2 14 2 3. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 10 7 5 12 -1. + <_> + 10 11 5 4 3. + <_> + + <_> + 7 9 8 14 -1. + <_> + 7 9 4 7 2. + <_> + 11 16 4 7 2. + <_> + + <_> + 1 5 22 6 -1. + <_> + 12 5 11 3 2. + <_> + 1 8 11 3 2. + <_> + + <_> + 0 5 6 6 -1. + <_> + 0 8 6 3 2. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 2 18 19 3 -1. + <_> + 2 19 19 1 3. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 1 17 18 3 -1. + <_> + 1 18 18 1 3. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 0 0 24 3 -1. + <_> + 0 1 24 1 3. + <_> + + <_> + 5 0 14 4 -1. + <_> + 5 2 14 2 2. + <_> + + <_> + 6 14 9 6 -1. + <_> + 6 16 9 2 3. + <_> + + <_> + 14 13 6 9 -1. + <_> + 14 16 6 3 3. + <_> + + <_> + 5 20 13 4 -1. + <_> + 5 22 13 2 2. + <_> + + <_> + 9 9 6 12 -1. + <_> + 9 13 6 4 3. + <_> + + <_> + 1 10 21 3 -1. + <_> + 8 10 7 3 3. + <_> + + <_> + 8 8 9 6 -1. + <_> + 11 8 3 6 3. + <_> + + <_> + 3 10 9 7 -1. + <_> + 6 10 3 7 3. + <_> + + <_> + 12 10 10 8 -1. + <_> + 17 10 5 4 2. + <_> + 12 14 5 4 2. + <_> + + <_> + 0 15 24 3 -1. + <_> + 8 15 8 3 3. + <_> + + <_> + 8 5 9 6 -1. + <_> + 8 7 9 2 3. + <_> + + <_> + 4 13 6 9 -1. + <_> + 4 16 6 3 3. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 9 12 6 6 -1. + <_> + 9 15 6 3 2. + <_> + + <_> + 9 9 14 10 -1. + <_> + 16 9 7 5 2. + <_> + 9 14 7 5 2. + <_> + + <_> + 1 9 14 10 -1. + <_> + 1 9 7 5 2. + <_> + 8 14 7 5 2. + <_> + + <_> + 8 7 9 17 -1. + <_> + 11 7 3 17 3. + <_> + + <_> + 3 4 6 20 -1. + <_> + 3 4 3 10 2. + <_> + 6 14 3 10 2. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 8 5 4 2. + <_> + + <_> + 10 7 4 9 -1. + <_> + 12 7 2 9 2. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 3 8 6 16 -1. + <_> + 3 8 3 8 2. + <_> + 6 16 3 8 2. + <_> + + <_> + 12 17 9 4 -1. + <_> + 12 19 9 2 2. + <_> + + <_> + 3 17 9 4 -1. + <_> + 3 19 9 2 2. + <_> + + <_> + 10 1 9 6 -1. + <_> + 13 1 3 6 3. + <_> + + <_> + 5 7 4 10 -1. + <_> + 5 12 4 5 2. + <_> + + <_> + 7 5 12 6 -1. + <_> + 11 5 4 6 3. + <_> + + <_> + 6 4 9 8 -1. + <_> + 9 4 3 8 3. + <_> + + <_> + 12 16 10 8 -1. + <_> + 17 16 5 4 2. + <_> + 12 20 5 4 2. + <_> + + <_> + 2 16 10 8 -1. + <_> + 2 16 5 4 2. + <_> + 7 20 5 4 2. + <_> + + <_> + 0 0 24 4 -1. + <_> + 12 0 12 2 2. + <_> + 0 2 12 2 2. + <_> + + <_> + 0 6 9 6 -1. + <_> + 0 8 9 2 3. + <_> + + <_> + 0 4 24 6 -1. + <_> + 12 4 12 3 2. + <_> + 0 7 12 3 2. + <_> + + <_> + 5 0 11 4 -1. + <_> + 5 2 11 2 2. + <_> + + <_> + 1 1 22 4 -1. + <_> + 12 1 11 2 2. + <_> + 1 3 11 2 2. + <_> + + <_> + 9 6 6 18 -1. + <_> + 9 15 6 9 2. + <_> + + <_> + 2 9 20 4 -1. + <_> + 2 11 20 2 2. + <_> + + <_> + 5 2 14 14 -1. + <_> + 5 9 14 7 2. + <_> + + <_> + 4 2 16 6 -1. + <_> + 4 5 16 3 2. + <_> + + <_> + 2 3 19 3 -1. + <_> + 2 4 19 1 3. + <_> + + <_> + 7 1 10 4 -1. + <_> + 7 3 10 2 2. + <_> + + <_> + 0 9 4 15 -1. + <_> + 0 14 4 5 3. + <_> + + <_> + 2 10 21 3 -1. + <_> + 2 11 21 1 3. + <_> + + <_> + 3 0 6 6 -1. + <_> + 6 0 3 6 2. + <_> + + <_> + 6 4 14 9 -1. + <_> + 6 7 14 3 3. + <_> + + <_> + 9 1 6 9 -1. + <_> + 11 1 2 9 3. + <_> + + <_> + 15 8 9 9 -1. + <_> + 15 11 9 3 3. + <_> + + <_> + 8 0 4 21 -1. + <_> + 8 7 4 7 3. + <_> + + <_> + 3 22 19 2 -1. + <_> + 3 23 19 1 2. + <_> + + <_> + 2 15 20 3 -1. + <_> + 2 16 20 1 3. + <_> + + <_> + 19 0 4 13 -1. + <_> + 19 0 2 13 2. + <_> + + <_> + 1 7 8 8 -1. + <_> + 1 11 8 4 2. + <_> + + <_> + 14 14 6 9 -1. + <_> + 14 17 6 3 3. + <_> + + <_> + 4 14 6 9 -1. + <_> + 4 17 6 3 3. + <_> + + <_> + 14 5 4 10 -1. + <_> + 14 5 2 10 2. + <_> + + <_> + 6 5 4 10 -1. + <_> + 8 5 2 10 2. + <_> + + <_> + 14 5 6 6 -1. + <_> + 14 8 6 3 2. + <_> + + <_> + 4 5 6 6 -1. + <_> + 4 8 6 3 2. + <_> + + <_> + 0 2 24 21 -1. + <_> + 8 2 8 21 3. + <_> + + <_> + 1 2 6 13 -1. + <_> + 3 2 2 13 3. + <_> + + <_> + 20 0 4 21 -1. + <_> + 20 0 2 21 2. + <_> + + <_> + 0 4 4 20 -1. + <_> + 2 4 2 20 2. + <_> + + <_> + 8 16 9 6 -1. + <_> + 8 18 9 2 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 16 12 7 9 -1. + <_> + 16 15 7 3 3. + <_> + + <_> + 5 21 14 3 -1. + <_> + 12 21 7 3 2. + <_> + + <_> + 11 5 6 9 -1. + <_> + 11 5 3 9 2. + <_> + + <_> + 10 5 4 10 -1. + <_> + 12 5 2 10 2. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 7 5 6 9 -1. + <_> + 10 5 3 9 2. + <_> + + <_> + 14 14 10 4 -1. + <_> + 14 16 10 2 2. + <_> + + <_> + 5 5 14 14 -1. + <_> + 5 5 7 7 2. + <_> + 12 12 7 7 2. + <_> + + <_> + 12 8 12 6 -1. + <_> + 18 8 6 3 2. + <_> + 12 11 6 3 2. + <_> + + <_> + 6 6 12 12 -1. + <_> + 6 6 6 6 2. + <_> + 12 12 6 6 2. + <_> + + <_> + 11 13 6 10 -1. + <_> + 13 13 2 10 3. + <_> + + <_> + 1 10 20 8 -1. + <_> + 1 10 10 4 2. + <_> + 11 14 10 4 2. + <_> + + <_> + 15 13 9 6 -1. + <_> + 15 15 9 2 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 9 3 6 3 3. + <_> + + <_> + 10 1 5 14 -1. + <_> + 10 8 5 7 2. + <_> + + <_> + 3 4 16 6 -1. + <_> + 3 6 16 2 3. + <_> + + <_> + 16 3 8 9 -1. + <_> + 16 6 8 3 3. + <_> + + <_> + 7 13 6 10 -1. + <_> + 9 13 2 10 3. + <_> + + <_> + 15 13 9 6 -1. + <_> + 15 15 9 2 3. + <_> + + <_> + 0 13 9 6 -1. + <_> + 0 15 9 2 3. + <_> + + <_> + 13 16 9 6 -1. + <_> + 13 18 9 2 3. + <_> + + <_> + 2 16 9 6 -1. + <_> + 2 18 9 2 3. + <_> + + <_> + 5 16 18 3 -1. + <_> + 5 17 18 1 3. + <_> + + <_> + 1 16 18 3 -1. + <_> + 1 17 18 1 3. + <_> + + <_> + 5 0 18 3 -1. + <_> + 5 1 18 1 3. + <_> + + <_> + 1 1 19 2 -1. + <_> + 1 2 19 1 2. + <_> + + <_> + 14 2 6 11 -1. + <_> + 16 2 2 11 3. + <_> + + <_> + 4 15 15 6 -1. + <_> + 9 15 5 6 3. + <_> + + <_> + 14 2 6 11 -1. + <_> + 16 2 2 11 3. + <_> + + <_> + 4 2 6 11 -1. + <_> + 6 2 2 11 3. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 1 2 22 4 -1. + <_> + 1 2 11 2 2. + <_> + 12 4 11 2 2. + <_> + + <_> + 2 0 21 12 -1. + <_> + 9 0 7 12 3. + <_> + + <_> + 0 12 18 3 -1. + <_> + 0 13 18 1 3. + <_> + + <_> + 12 2 6 9 -1. + <_> + 14 2 2 9 3. + <_> + + <_> + 3 10 18 3 -1. + <_> + 3 11 18 1 3. + <_> + + <_> + 16 3 8 9 -1. + <_> + 16 6 8 3 3. + <_> + + <_> + 3 7 18 3 -1. + <_> + 3 8 18 1 3. + <_> + + <_> + 9 11 6 9 -1. + <_> + 11 11 2 9 3. + <_> + + <_> + 9 8 6 9 -1. + <_> + 11 8 2 9 3. + <_> + + <_> + 15 0 2 18 -1. + <_> + 15 0 1 18 2. + <_> + + <_> + 7 0 2 18 -1. + <_> + 8 0 1 18 2. + <_> + + <_> + 17 3 7 9 -1. + <_> + 17 6 7 3 3. + <_> + + <_> + 3 18 9 6 -1. + <_> + 3 20 9 2 3. + <_> + + <_> + 3 18 21 3 -1. + <_> + 3 19 21 1 3. + <_> + + <_> + 0 3 7 9 -1. + <_> + 0 6 7 3 3. + <_> + + <_> + 2 7 22 3 -1. + <_> + 2 8 22 1 3. + <_> + + <_> + 0 3 24 16 -1. + <_> + 0 3 12 8 2. + <_> + 12 11 12 8 2. + <_> + + <_> + 13 17 9 4 -1. + <_> + 13 19 9 2 2. + <_> + + <_> + 5 5 12 8 -1. + <_> + 5 5 6 4 2. + <_> + 11 9 6 4 2. + <_> + + <_> + 5 6 14 6 -1. + <_> + 12 6 7 3 2. + <_> + 5 9 7 3 2. + <_> + + <_> + 5 16 14 6 -1. + <_> + 5 16 7 3 2. + <_> + 12 19 7 3 2. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 0 5 6 3 3. + <_> + + <_> + 3 4 20 10 -1. + <_> + 13 4 10 5 2. + <_> + 3 9 10 5 2. + <_> + + <_> + 2 13 9 8 -1. + <_> + 5 13 3 8 3. + <_> + + <_> + 2 1 21 15 -1. + <_> + 9 1 7 15 3. + <_> + + <_> + 5 12 14 8 -1. + <_> + 12 12 7 8 2. + <_> + + <_> + 6 7 12 4 -1. + <_> + 6 7 6 4 2. + <_> + + <_> + 6 5 9 6 -1. + <_> + 9 5 3 6 3. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 5 11 6 6 -1. + <_> + 8 11 3 6 2. + <_> + + <_> + 6 4 18 2 -1. + <_> + 6 5 18 1 2. + <_> + + <_> + 0 2 6 11 -1. + <_> + 2 2 2 11 3. + <_> + + <_> + 18 0 6 15 -1. + <_> + 20 0 2 15 3. + <_> + + <_> + 0 0 6 13 -1. + <_> + 2 0 2 13 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 3 13 18 4 -1. + <_> + 12 13 9 4 2. + <_> + + <_> + 9 7 10 4 -1. + <_> + 9 7 5 4 2. + <_> + + <_> + 5 8 12 3 -1. + <_> + 11 8 6 3 2. + <_> + + <_> + 4 14 19 3 -1. + <_> + 4 15 19 1 3. + <_> + + <_> + 10 0 4 20 -1. + <_> + 10 10 4 10 2. + <_> + + <_> + 8 15 9 6 -1. + <_> + 8 17 9 2 3. + <_> + + <_> + 2 9 15 4 -1. + <_> + 7 9 5 4 3. + <_> + + <_> + 8 4 12 7 -1. + <_> + 12 4 4 7 3. + <_> + + <_> + 0 10 6 9 -1. + <_> + 0 13 6 3 3. + <_> + + <_> + 18 5 6 9 -1. + <_> + 18 8 6 3 3. + <_> + + <_> + 0 18 16 6 -1. + <_> + 0 18 8 3 2. + <_> + 8 21 8 3 2. + <_> + + <_> + 9 18 14 6 -1. + <_> + 16 18 7 3 2. + <_> + 9 21 7 3 2. + <_> + + <_> + 1 20 20 4 -1. + <_> + 1 20 10 2 2. + <_> + 11 22 10 2 2. + <_> + + <_> + 2 8 20 6 -1. + <_> + 12 8 10 3 2. + <_> + 2 11 10 3 2. + <_> + + <_> + 7 8 6 9 -1. + <_> + 9 8 2 9 3. + <_> + + <_> + 8 5 12 8 -1. + <_> + 12 5 4 8 3. + <_> + + <_> + 4 5 12 8 -1. + <_> + 8 5 4 8 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 2 0 6 16 -1. + <_> + 4 0 2 16 3. + <_> + + <_> + 15 4 6 12 -1. + <_> + 15 8 6 4 3. + <_> + + <_> + 3 4 6 12 -1. + <_> + 3 8 6 4 3. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 4 0 15 22 -1. + <_> + 4 11 15 11 2. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 0 12 9 6 -1. + <_> + 0 14 9 2 3. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 10 0 8 10 -1. + <_> + 14 0 4 5 2. + <_> + 10 5 4 5 2. + <_> + + <_> + 1 0 4 16 -1. + <_> + 3 0 2 16 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 10 12 4 10 -1. + <_> + 10 17 4 5 2. + <_> + + <_> + 8 4 10 6 -1. + <_> + 8 6 10 2 3. + <_> + + <_> + 3 22 18 2 -1. + <_> + 12 22 9 2 2. + <_> + + <_> + 7 7 11 6 -1. + <_> + 7 9 11 2 3. + <_> + + <_> + 0 0 12 10 -1. + <_> + 0 0 6 5 2. + <_> + 6 5 6 5 2. + <_> + + <_> + 10 1 12 6 -1. + <_> + 16 1 6 3 2. + <_> + 10 4 6 3 2. + <_> + + <_> + 7 16 9 4 -1. + <_> + 7 18 9 2 2. + <_> + + <_> + 5 7 15 16 -1. + <_> + 10 7 5 16 3. + <_> + + <_> + 5 10 12 13 -1. + <_> + 11 10 6 13 2. + <_> + + <_> + 6 2 12 6 -1. + <_> + 12 2 6 3 2. + <_> + 6 5 6 3 2. + <_> + + <_> + 3 9 12 9 -1. + <_> + 3 12 12 3 3. + <_> + + <_> + 16 2 8 6 -1. + <_> + 16 5 8 3 2. + <_> + + <_> + 0 2 8 6 -1. + <_> + 0 5 8 3 2. + <_> + + <_> + 0 3 24 11 -1. + <_> + 0 3 12 11 2. + <_> + + <_> + 0 13 8 10 -1. + <_> + 0 13 4 5 2. + <_> + 4 18 4 5 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 10 2 4 21 -1. + <_> + 10 9 4 7 3. + <_> + + <_> + 4 4 15 9 -1. + <_> + 4 7 15 3 3. + <_> + + <_> + 0 1 24 6 -1. + <_> + 8 1 8 6 3. + <_> + + <_> + 9 6 5 16 -1. + <_> + 9 14 5 8 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 6 5 3 12 -1. + <_> + 6 11 3 6 2. + <_> + + <_> + 11 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 5 6 9 8 -1. + <_> + 8 6 3 8 3. + <_> + + <_> + 4 3 20 2 -1. + <_> + 4 4 20 1 2. + <_> + + <_> + 2 10 18 3 -1. + <_> + 8 10 6 3 3. + <_> + + <_> + 7 15 10 6 -1. + <_> + 7 17 10 2 3. + <_> + + <_> + 1 4 4 18 -1. + <_> + 1 4 2 9 2. + <_> + 3 13 2 9 2. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 5 0 6 9 -1. + <_> + 7 0 2 9 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 6 7 9 6 -1. + <_> + 9 7 3 6 3. + <_> + + <_> + 3 0 18 2 -1. + <_> + 3 1 18 1 2. + <_> + + <_> + 0 10 20 4 -1. + <_> + 0 10 10 2 2. + <_> + 10 12 10 2 2. + <_> + + <_> + 10 2 4 12 -1. + <_> + 10 8 4 6 2. + <_> + + <_> + 6 5 6 12 -1. + <_> + 6 5 3 6 2. + <_> + 9 11 3 6 2. + <_> + + <_> + 6 0 18 22 -1. + <_> + 15 0 9 11 2. + <_> + 6 11 9 11 2. + <_> + + <_> + 0 0 18 22 -1. + <_> + 0 0 9 11 2. + <_> + 9 11 9 11 2. + <_> + + <_> + 18 2 6 11 -1. + <_> + 20 2 2 11 3. + <_> + + <_> + 0 2 6 11 -1. + <_> + 2 2 2 11 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 0 0 20 3 -1. + <_> + 0 1 20 1 3. + <_> + + <_> + 2 2 20 2 -1. + <_> + 2 3 20 1 2. + <_> + + <_> + 1 10 18 2 -1. + <_> + 1 11 18 1 2. + <_> + + <_> + 18 7 6 9 -1. + <_> + 18 10 6 3 3. + <_> + + <_> + 0 0 22 9 -1. + <_> + 0 3 22 3 3. + <_> + + <_> + 17 3 6 9 -1. + <_> + 17 6 6 3 3. + <_> + + <_> + 0 7 6 9 -1. + <_> + 0 10 6 3 3. + <_> + + <_> + 0 6 24 6 -1. + <_> + 0 8 24 2 3. + <_> + + <_> + 0 2 6 10 -1. + <_> + 2 2 2 10 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 15 0 6 9 -1. + <_> + 17 0 2 9 3. + <_> + + <_> + 3 0 6 9 -1. + <_> + 5 0 2 9 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 15 14 9 6 -1. + <_> + 15 16 9 2 3. + <_> + + <_> + 0 15 23 6 -1. + <_> + 0 17 23 2 3. + <_> + + <_> + 5 15 18 3 -1. + <_> + 5 16 18 1 3. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 3 7 15 6 -1. + <_> + 8 7 5 6 3. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 5 0 6 12 -1. + <_> + 8 0 3 12 2. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 8 5 6 9 -1. + <_> + 10 5 2 9 3. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 5 7 12 4 -1. + <_> + 11 7 6 4 2. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 7 8 8 10 -1. + <_> + 7 8 4 5 2. + <_> + 11 13 4 5 2. + <_> + + <_> + 11 10 6 14 -1. + <_> + 14 10 3 7 2. + <_> + 11 17 3 7 2. + <_> + + <_> + 9 5 6 19 -1. + <_> + 12 5 3 19 2. + <_> + + <_> + 6 12 12 6 -1. + <_> + 12 12 6 3 2. + <_> + 6 15 6 3 2. + <_> + + <_> + 1 9 18 6 -1. + <_> + 1 9 9 3 2. + <_> + 10 12 9 3 2. + <_> + + <_> + 16 14 8 10 -1. + <_> + 20 14 4 5 2. + <_> + 16 19 4 5 2. + <_> + + <_> + 0 9 22 8 -1. + <_> + 0 9 11 4 2. + <_> + 11 13 11 4 2. + <_> + + <_> + 8 18 12 6 -1. + <_> + 14 18 6 3 2. + <_> + 8 21 6 3 2. + <_> + + <_> + 0 6 20 18 -1. + <_> + 0 6 10 9 2. + <_> + 10 15 10 9 2. + <_> + + <_> + 3 6 20 12 -1. + <_> + 13 6 10 6 2. + <_> + 3 12 10 6 2. + <_> + + <_> + 0 16 10 8 -1. + <_> + 0 16 5 4 2. + <_> + 5 20 5 4 2. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 0 11 19 3 -1. + <_> + 0 12 19 1 3. + <_> + + <_> + 14 6 6 9 -1. + <_> + 14 9 6 3 3. + <_> + + <_> + 1 7 22 4 -1. + <_> + 1 7 11 2 2. + <_> + 12 9 11 2 2. + <_> + + <_> + 13 6 7 12 -1. + <_> + 13 10 7 4 3. + <_> + + <_> + 4 7 11 9 -1. + <_> + 4 10 11 3 3. + <_> + + <_> + 12 10 10 8 -1. + <_> + 17 10 5 4 2. + <_> + 12 14 5 4 2. + <_> + + <_> + 2 12 9 7 -1. + <_> + 5 12 3 7 3. + <_> + + <_> + 16 14 6 9 -1. + <_> + 16 17 6 3 3. + <_> + + <_> + 3 12 6 12 -1. + <_> + 3 16 6 4 3. + <_> + + <_> + 14 13 6 6 -1. + <_> + 14 16 6 3 2. + <_> + + <_> + 8 0 6 9 -1. + <_> + 10 0 2 9 3. + <_> + + <_> + 9 1 6 23 -1. + <_> + 11 1 2 23 3. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 4 17 18 3 -1. + <_> + 4 18 18 1 3. + <_> + + <_> + 5 2 13 14 -1. + <_> + 5 9 13 7 2. + <_> + + <_> + 15 0 8 12 -1. + <_> + 19 0 4 6 2. + <_> + 15 6 4 6 2. + <_> + + <_> + 0 0 8 12 -1. + <_> + 0 0 4 6 2. + <_> + 4 6 4 6 2. + <_> + + <_> + 8 2 8 7 -1. + <_> + 8 2 4 7 2. + <_> + + <_> + 1 1 6 9 -1. + <_> + 3 1 2 9 3. + <_> + + <_> + 14 8 6 12 -1. + <_> + 17 8 3 6 2. + <_> + 14 14 3 6 2. + <_> + + <_> + 4 8 6 12 -1. + <_> + 4 8 3 6 2. + <_> + 7 14 3 6 2. + <_> + + <_> + 16 5 5 15 -1. + <_> + 16 10 5 5 3. + <_> + + <_> + 3 5 5 15 -1. + <_> + 3 10 5 5 3. + <_> + + <_> + 18 4 6 9 -1. + <_> + 18 7 6 3 3. + <_> + + <_> + 1 7 6 15 -1. + <_> + 1 12 6 5 3. + <_> + + <_> + 11 15 12 8 -1. + <_> + 17 15 6 4 2. + <_> + 11 19 6 4 2. + <_> + + <_> + 0 2 24 4 -1. + <_> + 0 2 12 2 2. + <_> + 12 4 12 2 2. + <_> + + <_> + 15 1 2 19 -1. + <_> + 15 1 1 19 2. + <_> + + <_> + 7 1 2 19 -1. + <_> + 8 1 1 19 2. + <_> + + <_> + 22 1 2 20 -1. + <_> + 22 1 1 20 2. + <_> + + <_> + 0 1 2 20 -1. + <_> + 1 1 1 20 2. + <_> + + <_> + 18 11 6 12 -1. + <_> + 20 11 2 12 3. + <_> + + <_> + 0 11 6 12 -1. + <_> + 2 11 2 12 3. + <_> + + <_> + 3 6 18 14 -1. + <_> + 3 13 18 7 2. + <_> + + <_> + 6 10 7 8 -1. + <_> + 6 14 7 4 2. + <_> + + <_> + 7 9 12 12 -1. + <_> + 7 13 12 4 3. + <_> + + <_> + 2 18 18 5 -1. + <_> + 11 18 9 5 2. + <_> + + <_> + 4 21 20 3 -1. + <_> + 4 22 20 1 3. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 12 3 6 2. + <_> + 12 18 3 6 2. + <_> + + <_> + 4 6 18 3 -1. + <_> + 4 7 18 1 3. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 18 4 6 9 -1. + <_> + 18 7 6 3 3. + <_> + + <_> + 2 12 9 6 -1. + <_> + 2 14 9 2 3. + <_> + + <_> + 4 14 18 4 -1. + <_> + 13 14 9 2 2. + <_> + 4 16 9 2 2. + <_> + + <_> + 7 7 6 14 -1. + <_> + 7 7 3 7 2. + <_> + 10 14 3 7 2. + <_> + + <_> + 7 13 12 6 -1. + <_> + 13 13 6 3 2. + <_> + 7 16 6 3 2. + <_> + + <_> + 6 7 12 9 -1. + <_> + 10 7 4 9 3. + <_> + + <_> + 12 12 6 6 -1. + <_> + 12 12 3 6 2. + <_> + + <_> + 0 2 4 10 -1. + <_> + 0 7 4 5 2. + <_> + + <_> + 8 0 9 6 -1. + <_> + 11 0 3 6 3. + <_> + + <_> + 2 9 12 6 -1. + <_> + 2 12 12 3 2. + <_> + + <_> + 13 10 6 9 -1. + <_> + 13 13 6 3 3. + <_> + + <_> + 5 10 6 9 -1. + <_> + 5 13 6 3 3. + <_> + + <_> + 9 15 9 6 -1. + <_> + 9 17 9 2 3. + <_> + + <_> + 5 16 12 6 -1. + <_> + 5 19 12 3 2. + <_> + + <_> + 3 2 20 3 -1. + <_> + 3 3 20 1 3. + <_> + + <_> + 2 5 12 6 -1. + <_> + 6 5 4 6 3. + <_> + + <_> + 11 0 3 24 -1. + <_> + 12 0 1 24 3. + <_> + + <_> + 3 16 15 4 -1. + <_> + 8 16 5 4 3. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 18 6 6 2. + <_> + + <_> + 1 15 12 8 -1. + <_> + 1 15 6 4 2. + <_> + 7 19 6 4 2. + <_> + + <_> + 15 10 8 14 -1. + <_> + 19 10 4 7 2. + <_> + 15 17 4 7 2. + <_> + + <_> + 1 9 8 14 -1. + <_> + 1 9 4 7 2. + <_> + 5 16 4 7 2. + <_> + + <_> + 9 11 9 10 -1. + <_> + 9 16 9 5 2. + <_> + + <_> + 6 7 12 6 -1. + <_> + 6 9 12 2 3. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 7 8 9 7 -1. + <_> + 10 8 3 7 3. + <_> + + <_> + 10 4 8 10 -1. + <_> + 14 4 4 5 2. + <_> + 10 9 4 5 2. + <_> + + <_> + 4 6 6 9 -1. + <_> + 4 9 6 3 3. + <_> + + <_> + 0 6 24 12 -1. + <_> + 8 6 8 12 3. + <_> + + <_> + 3 7 6 14 -1. + <_> + 6 7 3 14 2. + <_> + + <_> + 19 8 5 8 -1. + <_> + 19 12 5 4 2. + <_> + + <_> + 0 8 5 8 -1. + <_> + 0 12 5 4 2. + <_> + + <_> + 17 3 6 6 -1. + <_> + 17 6 6 3 2. + <_> + + <_> + 1 3 6 6 -1. + <_> + 1 6 6 3 2. + <_> + + <_> + 18 2 6 9 -1. + <_> + 18 5 6 3 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 0 5 6 3 3. + <_> + + <_> + 3 3 18 6 -1. + <_> + 3 5 18 2 3. + <_> + + <_> + 2 3 9 6 -1. + <_> + 2 5 9 2 3. + <_> + + <_> + 9 3 10 8 -1. + <_> + 14 3 5 4 2. + <_> + 9 7 5 4 2. + <_> + + <_> + 5 3 10 8 -1. + <_> + 5 3 5 4 2. + <_> + 10 7 5 4 2. + <_> + + <_> + 10 11 6 12 -1. + <_> + 10 11 3 12 2. + <_> + + <_> + 8 11 6 11 -1. + <_> + 11 11 3 11 2. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 8 5 4 2. + <_> + + <_> + 9 6 6 7 -1. + <_> + 12 6 3 7 2. + <_> + + <_> + 5 18 18 3 -1. + <_> + 5 19 18 1 3. + <_> + + <_> + 8 4 6 9 -1. + <_> + 10 4 2 9 3. + <_> + + <_> + 8 1 9 7 -1. + <_> + 11 1 3 7 3. + <_> + + <_> + 6 11 6 6 -1. + <_> + 9 11 3 6 2. + <_> + + <_> + 14 12 4 11 -1. + <_> + 14 12 2 11 2. + <_> + + <_> + 6 12 4 11 -1. + <_> + 8 12 2 11 2. + <_> + + <_> + 8 0 12 18 -1. + <_> + 12 0 4 18 3. + <_> + + <_> + 2 12 10 5 -1. + <_> + 7 12 5 5 2. + <_> + + <_> + 2 20 22 3 -1. + <_> + 2 21 22 1 3. + <_> + + <_> + 0 4 2 20 -1. + <_> + 1 4 1 20 2. + <_> + + <_> + 0 2 24 4 -1. + <_> + 8 2 8 4 3. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 10 10 2 2. + <_> + + <_> + 6 7 8 10 -1. + <_> + 6 7 4 5 2. + <_> + 10 12 4 5 2. + <_> + + <_> + 14 0 6 14 -1. + <_> + 17 0 3 7 2. + <_> + 14 7 3 7 2. + <_> + + <_> + 4 11 5 8 -1. + <_> + 4 15 5 4 2. + <_> + + <_> + 2 0 20 9 -1. + <_> + 2 3 20 3 3. + <_> + + <_> + 6 7 12 8 -1. + <_> + 6 7 6 4 2. + <_> + 12 11 6 4 2. + <_> + + <_> + 9 17 6 6 -1. + <_> + 9 20 6 3 2. + <_> + + <_> + 7 10 10 4 -1. + <_> + 7 12 10 2 2. + <_> + + <_> + 6 5 12 9 -1. + <_> + 10 5 4 9 3. + <_> + + <_> + 5 11 6 8 -1. + <_> + 8 11 3 8 2. + <_> + + <_> + 18 4 4 17 -1. + <_> + 18 4 2 17 2. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 18 4 4 17 -1. + <_> + 18 4 2 17 2. + <_> + + <_> + 2 4 4 17 -1. + <_> + 4 4 2 17 2. + <_> + + <_> + 5 18 19 3 -1. + <_> + 5 19 19 1 3. + <_> + + <_> + 11 0 2 18 -1. + <_> + 11 9 2 9 2. + <_> + + <_> + 15 4 2 18 -1. + <_> + 15 13 2 9 2. + <_> + + <_> + 7 4 2 18 -1. + <_> + 7 13 2 9 2. + <_> + + <_> + 7 11 10 8 -1. + <_> + 12 11 5 4 2. + <_> + 7 15 5 4 2. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 2 9 16 8 -1. + <_> + 2 9 8 4 2. + <_> + 10 13 8 4 2. + <_> + + <_> + 14 15 6 9 -1. + <_> + 14 18 6 3 3. + <_> + + <_> + 8 7 6 9 -1. + <_> + 10 7 2 9 3. + <_> + + <_> + 14 15 6 9 -1. + <_> + 14 18 6 3 3. + <_> + + <_> + 3 12 12 6 -1. + <_> + 3 14 12 2 3. + <_> + + <_> + 14 12 9 6 -1. + <_> + 14 14 9 2 3. + <_> + + <_> + 1 12 9 6 -1. + <_> + 1 14 9 2 3. + <_> + + <_> + 3 7 18 3 -1. + <_> + 3 8 18 1 3. + <_> + + <_> + 1 7 22 6 -1. + <_> + 1 9 22 2 3. + <_> + + <_> + 18 4 6 6 -1. + <_> + 18 7 6 3 2. + <_> + + <_> + 0 4 6 6 -1. + <_> + 0 7 6 3 2. + <_> + + <_> + 5 11 16 6 -1. + <_> + 5 14 16 3 2. + <_> + + <_> + 6 16 9 4 -1. + <_> + 6 18 9 2 2. + <_> + + <_> + 14 15 6 9 -1. + <_> + 14 18 6 3 3. + <_> + + <_> + 4 15 6 9 -1. + <_> + 4 18 6 3 3. + <_> + + <_> + 15 1 6 23 -1. + <_> + 17 1 2 23 3. + <_> + + <_> + 0 21 24 3 -1. + <_> + 8 21 8 3 3. + <_> + + <_> + 0 20 24 4 -1. + <_> + 8 20 8 4 3. + <_> + + <_> + 3 1 6 23 -1. + <_> + 5 1 2 23 3. + <_> + + <_> + 3 17 18 3 -1. + <_> + 3 18 18 1 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 1 16 22 4 -1. + <_> + 12 16 11 2 2. + <_> + 1 18 11 2 2. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 2 10 21 3 -1. + <_> + 9 10 7 3 3. + <_> + + <_> + 2 18 12 6 -1. + <_> + 2 18 6 3 2. + <_> + 8 21 6 3 2. + <_> + + <_> + 0 5 24 4 -1. + <_> + 0 7 24 2 2. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 10 7 6 12 -1. + <_> + 10 13 6 6 2. + <_> + + <_> + 6 6 6 9 -1. + <_> + 8 6 2 9 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 9 7 6 9 -1. + <_> + 11 7 2 9 3. + <_> + + <_> + 2 1 20 3 -1. + <_> + 2 2 20 1 3. + <_> + + <_> + 1 18 12 6 -1. + <_> + 1 18 6 3 2. + <_> + 7 21 6 3 2. + <_> + + <_> + 13 2 4 13 -1. + <_> + 13 2 2 13 2. + <_> + + <_> + 6 7 12 4 -1. + <_> + 12 7 6 4 2. + <_> + + <_> + 10 1 4 13 -1. + <_> + 10 1 2 13 2. + <_> + + <_> + 6 0 3 18 -1. + <_> + 7 0 1 18 3. + <_> + + <_> + 14 3 10 5 -1. + <_> + 14 3 5 5 2. + <_> + + <_> + 6 15 12 8 -1. + <_> + 10 15 4 8 3. + <_> + + <_> + 9 10 6 9 -1. + <_> + 11 10 2 9 3. + <_> + + <_> + 8 3 4 9 -1. + <_> + 10 3 2 9 2. + <_> + + <_> + 17 0 6 14 -1. + <_> + 20 0 3 7 2. + <_> + 17 7 3 7 2. + <_> + + <_> + 1 0 6 14 -1. + <_> + 1 0 3 7 2. + <_> + 4 7 3 7 2. + <_> + + <_> + 14 0 6 16 -1. + <_> + 17 0 3 8 2. + <_> + 14 8 3 8 2. + <_> + + <_> + 7 4 4 10 -1. + <_> + 9 4 2 10 2. + <_> + + <_> + 3 17 18 6 -1. + <_> + 12 17 9 3 2. + <_> + 3 20 9 3 2. + <_> + + <_> + 1 20 22 4 -1. + <_> + 12 20 11 4 2. + <_> + + <_> + 14 3 10 5 -1. + <_> + 14 3 5 5 2. + <_> + + <_> + 0 3 10 5 -1. + <_> + 5 3 5 5 2. + <_> + + <_> + 12 6 12 16 -1. + <_> + 16 6 4 16 3. + <_> + + <_> + 0 6 12 16 -1. + <_> + 4 6 4 16 3. + <_> + + <_> + 10 9 5 15 -1. + <_> + 10 14 5 5 3. + <_> + + <_> + 1 18 21 2 -1. + <_> + 1 19 21 1 2. + <_> + + <_> + 15 0 9 6 -1. + <_> + 15 2 9 2 3. + <_> + + <_> + 6 1 12 4 -1. + <_> + 12 1 6 4 2. + <_> + + <_> + 6 0 12 12 -1. + <_> + 12 0 6 6 2. + <_> + 6 6 6 6 2. + <_> + + <_> + 8 10 8 12 -1. + <_> + 8 10 4 6 2. + <_> + 12 16 4 6 2. + <_> + + <_> + 14 16 10 8 -1. + <_> + 19 16 5 4 2. + <_> + 14 20 5 4 2. + <_> + + <_> + 0 16 10 8 -1. + <_> + 0 16 5 4 2. + <_> + 5 20 5 4 2. + <_> + + <_> + 10 12 12 5 -1. + <_> + 14 12 4 5 3. + <_> + + <_> + 6 16 10 8 -1. + <_> + 6 16 5 4 2. + <_> + 11 20 5 4 2. + <_> + + <_> + 7 6 12 6 -1. + <_> + 13 6 6 3 2. + <_> + 7 9 6 3 2. + <_> + + <_> + 9 6 4 18 -1. + <_> + 9 6 2 9 2. + <_> + 11 15 2 9 2. + <_> + + <_> + 10 9 6 14 -1. + <_> + 13 9 3 7 2. + <_> + 10 16 3 7 2. + <_> + + <_> + 8 9 6 14 -1. + <_> + 8 9 3 7 2. + <_> + 11 16 3 7 2. + <_> + + <_> + 7 4 11 12 -1. + <_> + 7 10 11 6 2. + <_> + + <_> + 4 8 6 16 -1. + <_> + 4 8 3 8 2. + <_> + 7 16 3 8 2. + <_> + + <_> + 17 3 4 21 -1. + <_> + 17 10 4 7 3. + <_> + + <_> + 3 3 4 21 -1. + <_> + 3 10 4 7 3. + <_> + + <_> + 10 1 8 18 -1. + <_> + 14 1 4 9 2. + <_> + 10 10 4 9 2. + <_> + + <_> + 2 5 16 8 -1. + <_> + 2 5 8 4 2. + <_> + 10 9 8 4 2. + <_> + + <_> + 3 6 18 12 -1. + <_> + 3 10 18 4 3. + <_> + + <_> + 4 10 16 12 -1. + <_> + 4 14 16 4 3. + <_> + + <_> + 15 4 8 20 -1. + <_> + 19 4 4 10 2. + <_> + 15 14 4 10 2. + <_> + + <_> + 7 2 9 6 -1. + <_> + 10 2 3 6 3. + <_> + + <_> + 15 4 8 20 -1. + <_> + 19 4 4 10 2. + <_> + 15 14 4 10 2. + <_> + + <_> + 1 4 8 20 -1. + <_> + 1 4 4 10 2. + <_> + 5 14 4 10 2. + <_> + + <_> + 11 8 8 14 -1. + <_> + 15 8 4 7 2. + <_> + 11 15 4 7 2. + <_> + + <_> + 5 8 8 14 -1. + <_> + 5 8 4 7 2. + <_> + 9 15 4 7 2. + <_> + + <_> + 10 13 5 8 -1. + <_> + 10 17 5 4 2. + <_> + + <_> + 4 13 7 9 -1. + <_> + 4 16 7 3 3. + <_> + + <_> + 0 13 24 10 -1. + <_> + 0 18 24 5 2. + <_> + + <_> + 4 2 8 11 -1. + <_> + 8 2 4 11 2. + <_> + + <_> + 10 2 8 16 -1. + <_> + 14 2 4 8 2. + <_> + 10 10 4 8 2. + <_> + + <_> + 0 2 24 6 -1. + <_> + 0 2 12 3 2. + <_> + 12 5 12 3 2. + <_> + + <_> + 6 0 12 9 -1. + <_> + 6 3 12 3 3. + <_> + + <_> + 1 2 12 12 -1. + <_> + 1 2 6 6 2. + <_> + 7 8 6 6 2. + <_> + + <_> + 18 5 6 9 -1. + <_> + 18 8 6 3 3. + <_> + + <_> + 4 3 8 10 -1. + <_> + 4 3 4 5 2. + <_> + 8 8 4 5 2. + <_> + + <_> + 6 21 18 3 -1. + <_> + 6 22 18 1 3. + <_> + + <_> + 1 10 18 2 -1. + <_> + 1 11 18 1 2. + <_> + + <_> + 1 10 22 3 -1. + <_> + 1 11 22 1 3. + <_> + + <_> + 2 8 12 9 -1. + <_> + 2 11 12 3 3. + <_> + + <_> + 12 8 12 6 -1. + <_> + 18 8 6 3 2. + <_> + 12 11 6 3 2. + <_> + + <_> + 0 8 12 6 -1. + <_> + 0 8 6 3 2. + <_> + 6 11 6 3 2. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 7 13 9 6 -1. + <_> + 7 15 9 2 3. + <_> + + <_> + 9 8 7 12 -1. + <_> + 9 14 7 6 2. + <_> + + <_> + 4 13 9 6 -1. + <_> + 7 13 3 6 3. + <_> + + <_> + 6 15 18 4 -1. + <_> + 12 15 6 4 3. + <_> + + <_> + 5 4 4 16 -1. + <_> + 7 4 2 16 2. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 8 15 6 9 -1. + <_> + 10 15 2 9 3. + <_> + + <_> + 9 11 12 10 -1. + <_> + 15 11 6 5 2. + <_> + 9 16 6 5 2. + <_> + + <_> + 3 6 14 6 -1. + <_> + 3 8 14 2 3. + <_> + + <_> + 4 2 17 8 -1. + <_> + 4 6 17 4 2. + <_> + + <_> + 6 2 12 21 -1. + <_> + 6 9 12 7 3. + <_> + + <_> + 8 1 9 9 -1. + <_> + 8 4 9 3 3. + <_> + + <_> + 0 7 24 3 -1. + <_> + 12 7 12 3 2. + <_> + + <_> + 11 6 9 10 -1. + <_> + 11 11 9 5 2. + <_> + + <_> + 2 11 18 3 -1. + <_> + 2 12 18 1 3. + <_> + + <_> + 8 16 9 4 -1. + <_> + 8 18 9 2 2. + <_> + + <_> + 0 0 9 6 -1. + <_> + 0 2 9 2 3. + <_> + + <_> + 0 11 24 6 -1. + <_> + 0 13 24 2 3. + <_> + + <_> + 2 9 20 6 -1. + <_> + 2 12 20 3 2. + <_> + + <_> + 4 5 16 12 -1. + <_> + 12 5 8 6 2. + <_> + 4 11 8 6 2. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 7 3 10 4 -1. + <_> + 7 5 10 2 2. + <_> + + <_> + 9 15 6 8 -1. + <_> + 9 19 6 4 2. + <_> + + <_> + 17 0 7 10 -1. + <_> + 17 5 7 5 2. + <_> + + <_> + 0 0 7 10 -1. + <_> + 0 5 7 5 2. + <_> + + <_> + 16 1 6 12 -1. + <_> + 19 1 3 6 2. + <_> + 16 7 3 6 2. + <_> + + <_> + 1 0 19 8 -1. + <_> + 1 4 19 4 2. + <_> + + <_> + 12 2 9 4 -1. + <_> + 12 4 9 2 2. + <_> + + <_> + 3 2 9 4 -1. + <_> + 3 4 9 2 2. + <_> + + <_> + 12 2 10 6 -1. + <_> + 12 4 10 2 3. + <_> + + <_> + 3 4 18 2 -1. + <_> + 12 4 9 2 2. + <_> + + <_> + 12 1 4 9 -1. + <_> + 12 1 2 9 2. + <_> + + <_> + 8 1 4 9 -1. + <_> + 10 1 2 9 2. + <_> + + <_> + 10 5 8 10 -1. + <_> + 14 5 4 5 2. + <_> + 10 10 4 5 2. + <_> + + <_> + 6 4 12 13 -1. + <_> + 10 4 4 13 3. + <_> + + <_> + 13 5 6 6 -1. + <_> + 13 5 3 6 2. + <_> + + <_> + 1 5 12 3 -1. + <_> + 7 5 6 3 2. + <_> + + <_> + 7 5 10 6 -1. + <_> + 7 7 10 2 3. + <_> + + <_> + 2 0 21 5 -1. + <_> + 9 0 7 5 3. + <_> + + <_> + 0 8 9 9 -1. + <_> + 0 11 9 3 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 0 3 6 7 -1. + <_> + 3 3 3 7 2. + <_> + + <_> + 9 18 12 6 -1. + <_> + 15 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 2 8 20 6 -1. + <_> + 2 8 10 3 2. + <_> + 12 11 10 3 2. + <_> + + <_> + 13 2 10 4 -1. + <_> + 13 4 10 2 2. + <_> + + <_> + 4 5 5 18 -1. + <_> + 4 11 5 6 3. + <_> + + <_> + 20 4 4 9 -1. + <_> + 20 4 2 9 2. + <_> + + <_> + 8 6 8 14 -1. + <_> + 8 13 8 7 2. + <_> + + <_> + 0 1 24 6 -1. + <_> + 12 1 12 3 2. + <_> + 0 4 12 3 2. + <_> + + <_> + 0 4 4 9 -1. + <_> + 2 4 2 9 2. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 3 17 16 6 -1. + <_> + 3 19 16 2 3. + <_> + + <_> + 13 6 6 9 -1. + <_> + 13 9 6 3 3. + <_> + + <_> + 5 6 14 6 -1. + <_> + 5 6 7 3 2. + <_> + 12 9 7 3 2. + <_> + + <_> + 13 5 8 10 -1. + <_> + 17 5 4 5 2. + <_> + 13 10 4 5 2. + <_> + + <_> + 2 2 20 3 -1. + <_> + 2 3 20 1 3. + <_> + + <_> + 9 2 9 6 -1. + <_> + 12 2 3 6 3. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 12 3 4 11 -1. + <_> + 12 3 2 11 2. + <_> + + <_> + 8 3 4 11 -1. + <_> + 10 3 2 11 2. + <_> + + <_> + 8 3 8 10 -1. + <_> + 12 3 4 5 2. + <_> + 8 8 4 5 2. + <_> + + <_> + 11 1 2 18 -1. + <_> + 12 1 1 18 2. + <_> + + <_> + 9 2 9 6 -1. + <_> + 12 2 3 6 3. + <_> + + <_> + 0 2 19 3 -1. + <_> + 0 3 19 1 3. + <_> + + <_> + 9 14 9 6 -1. + <_> + 9 16 9 2 3. + <_> + + <_> + 1 8 18 5 -1. + <_> + 7 8 6 5 3. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 13 6 4 15 -1. + <_> + 13 11 4 5 3. + <_> + + <_> + 1 5 18 3 -1. + <_> + 1 6 18 1 3. + <_> + + <_> + 9 7 14 6 -1. + <_> + 9 9 14 2 3. + <_> + + <_> + 2 16 18 3 -1. + <_> + 2 17 18 1 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 8 12 6 -1. + <_> + 0 8 6 3 2. + <_> + 6 11 6 3 2. + <_> + + <_> + 9 13 7 8 -1. + <_> + 9 17 7 4 2. + <_> + + <_> + 2 17 20 3 -1. + <_> + 2 18 20 1 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 4 0 15 4 -1. + <_> + 4 2 15 2 2. + <_> + + <_> + 17 2 6 6 -1. + <_> + 17 5 6 3 2. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 17 9 6 -1. + <_> + 0 19 9 2 3. + <_> + + <_> + 9 18 12 6 -1. + <_> + 15 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 3 15 6 9 -1. + <_> + 3 18 6 3 3. + <_> + + <_> + 16 13 8 10 -1. + <_> + 20 13 4 5 2. + <_> + 16 18 4 5 2. + <_> + + <_> + 0 14 24 4 -1. + <_> + 8 14 8 4 3. + <_> + + <_> + 13 18 6 6 -1. + <_> + 13 18 3 6 2. + <_> + + <_> + 0 13 8 10 -1. + <_> + 0 13 4 5 2. + <_> + 4 18 4 5 2. + <_> + + <_> + 0 14 24 6 -1. + <_> + 0 17 24 3 2. + <_> + + <_> + 5 2 12 8 -1. + <_> + 5 2 6 4 2. + <_> + 11 6 6 4 2. + <_> + + <_> + 8 9 9 6 -1. + <_> + 11 9 3 6 3. + <_> + + <_> + 4 3 16 4 -1. + <_> + 4 5 16 2 2. + <_> + + <_> + 10 2 4 10 -1. + <_> + 10 7 4 5 2. + <_> + + <_> + 8 4 5 8 -1. + <_> + 8 8 5 4 2. + <_> + + <_> + 11 5 9 12 -1. + <_> + 11 9 9 4 3. + <_> + + <_> + 4 5 9 12 -1. + <_> + 4 9 9 4 3. + <_> + + <_> + 14 6 6 9 -1. + <_> + 14 9 6 3 3. + <_> + + <_> + 2 4 20 12 -1. + <_> + 2 8 20 4 3. + <_> + + <_> + 4 4 17 16 -1. + <_> + 4 12 17 8 2. + <_> + + <_> + 8 7 7 6 -1. + <_> + 8 10 7 3 2. + <_> + + <_> + 1 9 23 2 -1. + <_> + 1 10 23 1 2. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 13 3 4 9 -1. + <_> + 13 3 2 9 2. + <_> + + <_> + 8 1 6 13 -1. + <_> + 10 1 2 13 3. + <_> + + <_> + 4 22 18 2 -1. + <_> + 4 23 18 1 2. + <_> + + <_> + 3 10 9 6 -1. + <_> + 6 10 3 6 3. + <_> + + <_> + 14 0 2 24 -1. + <_> + 14 0 1 24 2. + <_> + + <_> + 8 0 2 24 -1. + <_> + 9 0 1 24 2. + <_> + + <_> + 3 2 18 10 -1. + <_> + 9 2 6 10 3. + <_> + + <_> + 4 13 15 6 -1. + <_> + 9 13 5 6 3. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 9 1 4 11 -1. + <_> + 11 1 2 11 2. + <_> + + <_> + 9 7 10 4 -1. + <_> + 9 7 5 4 2. + <_> + + <_> + 7 0 10 18 -1. + <_> + 12 0 5 18 2. + <_> + + <_> + 12 1 6 16 -1. + <_> + 14 1 2 16 3. + <_> + + <_> + 6 1 6 16 -1. + <_> + 8 1 2 16 3. + <_> + + <_> + 18 2 6 6 -1. + <_> + 18 5 6 3 2. + <_> + + <_> + 3 5 18 2 -1. + <_> + 3 6 18 1 2. + <_> + + <_> + 18 2 6 6 -1. + <_> + 18 5 6 3 2. + <_> + + <_> + 0 2 6 6 -1. + <_> + 0 5 6 3 2. + <_> + + <_> + 13 11 11 6 -1. + <_> + 13 13 11 2 3. + <_> + + <_> + 5 7 10 4 -1. + <_> + 10 7 5 4 2. + <_> + + <_> + 11 9 10 7 -1. + <_> + 11 9 5 7 2. + <_> + + <_> + 3 9 10 7 -1. + <_> + 8 9 5 7 2. + <_> + + <_> + 16 4 6 6 -1. + <_> + 16 4 3 6 2. + <_> + + <_> + 5 6 10 8 -1. + <_> + 5 6 5 4 2. + <_> + 10 10 5 4 2. + <_> + + <_> + 7 21 16 3 -1. + <_> + 7 21 8 3 2. + <_> + + <_> + 1 21 16 3 -1. + <_> + 9 21 8 3 2. + <_> + + <_> + 2 5 22 14 -1. + <_> + 13 5 11 7 2. + <_> + 2 12 11 7 2. + <_> + + <_> + 3 10 8 10 -1. + <_> + 3 10 4 5 2. + <_> + 7 15 4 5 2. + <_> + + <_> + 17 0 6 12 -1. + <_> + 20 0 3 6 2. + <_> + 17 6 3 6 2. + <_> + + <_> + 5 2 6 18 -1. + <_> + 7 2 2 18 3. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 0 12 7 9 -1. + <_> + 0 15 7 3 3. + <_> + + <_> + 15 13 8 10 -1. + <_> + 19 13 4 5 2. + <_> + 15 18 4 5 2. + <_> + + <_> + 1 0 6 12 -1. + <_> + 1 0 3 6 2. + <_> + 4 6 3 6 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 1 13 8 10 -1. + <_> + 1 13 4 5 2. + <_> + 5 18 4 5 2. + <_> + + <_> + 3 21 19 2 -1. + <_> + 3 22 19 1 2. + <_> + + <_> + 6 3 4 13 -1. + <_> + 8 3 2 13 2. + <_> + + <_> + 5 10 18 3 -1. + <_> + 5 11 18 1 3. + <_> + + <_> + 9 3 5 12 -1. + <_> + 9 7 5 4 3. + <_> + + <_> + 11 2 4 15 -1. + <_> + 11 7 4 5 3. + <_> + + <_> + 4 1 16 4 -1. + <_> + 4 3 16 2 2. + <_> + + <_> + 6 0 18 3 -1. + <_> + 6 1 18 1 3. + <_> + + <_> + 5 1 10 8 -1. + <_> + 5 1 5 4 2. + <_> + 10 5 5 4 2. + <_> + + <_> + 11 18 12 6 -1. + <_> + 17 18 6 3 2. + <_> + 11 21 6 3 2. + <_> + + <_> + 5 15 12 3 -1. + <_> + 11 15 6 3 2. + <_> + + <_> + 1 10 22 4 -1. + <_> + 1 10 11 4 2. + <_> + + <_> + 7 9 9 6 -1. + <_> + 10 9 3 6 3. + <_> + + <_> + 6 11 12 5 -1. + <_> + 10 11 4 5 3. + <_> + + <_> + 6 7 10 7 -1. + <_> + 11 7 5 7 2. + <_> + + <_> + 11 2 8 10 -1. + <_> + 11 2 4 10 2. + <_> + + <_> + 5 2 8 10 -1. + <_> + 9 2 4 10 2. + <_> + + <_> + 6 4 18 6 -1. + <_> + 15 4 9 3 2. + <_> + 6 7 9 3 2. + <_> + + <_> + 0 5 10 9 -1. + <_> + 0 8 10 3 3. + <_> + + <_> + 2 7 21 6 -1. + <_> + 2 9 21 2 3. + <_> + + <_> + 0 4 22 16 -1. + <_> + 0 4 11 8 2. + <_> + 11 12 11 8 2. + <_> + + <_> + 9 0 6 22 -1. + <_> + 9 11 6 11 2. + <_> + + <_> + 9 1 3 12 -1. + <_> + 9 7 3 6 2. + <_> + + <_> + 12 0 12 18 -1. + <_> + 18 0 6 9 2. + <_> + 12 9 6 9 2. + <_> + + <_> + 0 0 12 18 -1. + <_> + 0 0 6 9 2. + <_> + 6 9 6 9 2. + <_> + + <_> + 1 1 22 4 -1. + <_> + 12 1 11 2 2. + <_> + 1 3 11 2 2. + <_> + + <_> + 3 0 18 4 -1. + <_> + 3 2 18 2 2. + <_> + + <_> + 2 5 22 6 -1. + <_> + 2 7 22 2 3. + <_> + + <_> + 5 0 6 9 -1. + <_> + 5 3 6 3 3. + <_> + + <_> + 10 14 6 9 -1. + <_> + 12 14 2 9 3. + <_> + + <_> + 8 14 6 9 -1. + <_> + 10 14 2 9 3. + <_> + + <_> + 5 18 18 3 -1. + <_> + 5 19 18 1 3. + <_> + + <_> + 6 0 6 13 -1. + <_> + 9 0 3 13 2. + <_> + + <_> + 7 4 12 4 -1. + <_> + 7 4 6 4 2. + <_> + + <_> + 5 2 12 6 -1. + <_> + 9 2 4 6 3. + <_> + + <_> + 4 1 18 3 -1. + <_> + 4 2 18 1 3. + <_> + + <_> + 0 8 6 12 -1. + <_> + 0 12 6 4 3. + <_> + + <_> + 9 15 6 9 -1. + <_> + 11 15 2 9 3. + <_> + + <_> + 9 10 6 13 -1. + <_> + 11 10 2 13 3. + <_> + + <_> + 6 17 18 2 -1. + <_> + 6 18 18 1 2. + <_> + + <_> + 9 4 6 9 -1. + <_> + 11 4 2 9 3. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 5 6 10 8 -1. + <_> + 5 6 5 4 2. + <_> + 10 10 5 4 2. + <_> + + <_> + 14 9 5 8 -1. + <_> + 14 13 5 4 2. + <_> + + <_> + 5 9 5 8 -1. + <_> + 5 13 5 4 2. + <_> + + <_> + 14 11 9 6 -1. + <_> + 14 13 9 2 3. + <_> + + <_> + 0 2 23 15 -1. + <_> + 0 7 23 5 3. + <_> + + <_> + 16 0 8 12 -1. + <_> + 16 6 8 6 2. + <_> + + <_> + 4 15 6 9 -1. + <_> + 4 18 6 3 3. + <_> + + <_> + 8 18 9 4 -1. + <_> + 8 20 9 2 2. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 13 11 11 6 -1. + <_> + 13 13 11 2 3. + <_> + + <_> + 0 11 11 6 -1. + <_> + 0 13 11 2 3. + <_> + + <_> + 0 9 24 6 -1. + <_> + 12 9 12 3 2. + <_> + 0 12 12 3 2. + <_> + + <_> + 6 16 8 8 -1. + <_> + 6 20 8 4 2. + <_> + + <_> + 10 16 14 6 -1. + <_> + 10 18 14 2 3. + <_> + + <_> + 1 1 21 3 -1. + <_> + 1 2 21 1 3. + <_> + + <_> + 0 2 24 3 -1. + <_> + 0 2 12 3 2. + <_> + + <_> + 2 15 8 5 -1. + <_> + 6 15 4 5 2. + <_> + + <_> + 2 11 21 3 -1. + <_> + 9 11 7 3 3. + <_> + + <_> + 1 18 12 6 -1. + <_> + 1 18 6 3 2. + <_> + 7 21 6 3 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 7 7 4 10 -1. + <_> + 7 12 4 5 2. + <_> + + <_> + 9 8 6 12 -1. + <_> + 9 12 6 4 3. + <_> + + <_> + 7 1 9 6 -1. + <_> + 10 1 3 6 3. + <_> + + <_> + 3 14 19 2 -1. + <_> + 3 15 19 1 2. + <_> + + <_> + 7 7 10 10 -1. + <_> + 7 7 5 5 2. + <_> + 12 12 5 5 2. + <_> + + <_> + 3 12 18 12 -1. + <_> + 3 12 9 12 2. + <_> + + <_> + 8 0 6 12 -1. + <_> + 10 0 2 12 3. + <_> + + <_> + 3 0 17 9 -1. + <_> + 3 3 17 3 3. + <_> + + <_> + 6 0 12 11 -1. + <_> + 10 0 4 11 3. + <_> + + <_> + 1 0 6 13 -1. + <_> + 4 0 3 13 2. + <_> + + <_> + 5 8 16 6 -1. + <_> + 5 11 16 3 2. + <_> + + <_> + 8 8 5 12 -1. + <_> + 8 14 5 6 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 9 21 6 3 3. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 2 0 20 3 -1. + <_> + 2 1 20 1 3. + <_> + + <_> + 4 6 15 10 -1. + <_> + 9 6 5 10 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 7 16 9 6 -1. + <_> + 7 18 9 2 3. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 4 0 6 9 -1. + <_> + 6 0 2 9 3. + <_> + + <_> + 17 1 6 16 -1. + <_> + 19 1 2 16 3. + <_> + + <_> + 1 1 6 16 -1. + <_> + 3 1 2 16 3. + <_> + + <_> + 14 13 6 9 -1. + <_> + 14 16 6 3 3. + <_> + + <_> + 0 0 6 9 -1. + <_> + 0 3 6 3 3. + <_> + + <_> + 9 5 6 6 -1. + <_> + 9 5 3 6 2. + <_> + + <_> + 3 10 9 6 -1. + <_> + 6 10 3 6 3. + <_> + + <_> + 14 7 3 16 -1. + <_> + 14 15 3 8 2. + <_> + + <_> + 4 10 14 12 -1. + <_> + 4 10 7 6 2. + <_> + 11 16 7 6 2. + <_> + + <_> + 7 6 12 6 -1. + <_> + 7 8 12 2 3. + <_> + + <_> + 7 2 4 20 -1. + <_> + 9 2 2 20 2. + <_> + + <_> + 14 13 6 9 -1. + <_> + 14 16 6 3 3. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 14 13 6 9 -1. + <_> + 14 16 6 3 3. + <_> + + <_> + 5 20 14 4 -1. + <_> + 5 22 14 2 2. + <_> + + <_> + 4 4 16 12 -1. + <_> + 4 10 16 6 2. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 3 0 21 4 -1. + <_> + 3 2 21 2 2. + <_> + + <_> + 4 13 6 9 -1. + <_> + 4 16 6 3 3. + <_> + + <_> + 16 16 5 8 -1. + <_> + 16 20 5 4 2. + <_> + + <_> + 4 0 16 16 -1. + <_> + 4 0 8 8 2. + <_> + 12 8 8 8 2. + <_> + + <_> + 6 6 14 6 -1. + <_> + 13 6 7 3 2. + <_> + 6 9 7 3 2. + <_> + + <_> + 10 5 4 15 -1. + <_> + 10 10 4 5 3. + <_> + + <_> + 9 15 12 8 -1. + <_> + 15 15 6 4 2. + <_> + 9 19 6 4 2. + <_> + + <_> + 6 7 12 4 -1. + <_> + 12 7 6 4 2. + <_> + + <_> + 5 6 14 6 -1. + <_> + 12 6 7 3 2. + <_> + 5 9 7 3 2. + <_> + + <_> + 3 6 18 10 -1. + <_> + 3 6 9 5 2. + <_> + 12 11 9 5 2. + <_> + + <_> + 6 0 18 21 -1. + <_> + 12 0 6 21 3. + <_> + + <_> + 0 0 24 21 -1. + <_> + 8 0 8 21 3. + <_> + + <_> + 6 18 18 3 -1. + <_> + 6 19 18 1 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 4 3 19 2 -1. + <_> + 4 4 19 1 2. + <_> + + <_> + 0 3 24 2 -1. + <_> + 0 4 24 1 2. + <_> + + <_> + 15 14 9 4 -1. + <_> + 15 16 9 2 2. + <_> + + <_> + 0 14 9 4 -1. + <_> + 0 16 9 2 2. + <_> + + <_> + 6 15 18 2 -1. + <_> + 6 16 18 1 2. + <_> + + <_> + 3 17 18 3 -1. + <_> + 3 18 18 1 3. + <_> + + <_> + 12 0 3 23 -1. + <_> + 13 0 1 23 3. + <_> + + <_> + 6 0 8 6 -1. + <_> + 6 3 8 3 2. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 9 0 3 23 -1. + <_> + 10 0 1 23 3. + <_> + + <_> + 10 7 4 10 -1. + <_> + 10 12 4 5 2. + <_> + + <_> + 7 8 10 12 -1. + <_> + 7 12 10 4 3. + <_> + + <_> + 14 9 6 14 -1. + <_> + 17 9 3 7 2. + <_> + 14 16 3 7 2. + <_> + + <_> + 2 0 10 9 -1. + <_> + 2 3 10 3 3. + <_> + + <_> + 11 1 5 12 -1. + <_> + 11 7 5 6 2. + <_> + + <_> + 1 4 12 10 -1. + <_> + 1 4 6 5 2. + <_> + 7 9 6 5 2. + <_> + + <_> + 15 1 9 4 -1. + <_> + 15 3 9 2 2. + <_> + + <_> + 1 2 8 10 -1. + <_> + 1 2 4 5 2. + <_> + 5 7 4 5 2. + <_> + + <_> + 10 1 5 12 -1. + <_> + 10 5 5 4 3. + <_> + + <_> + 4 0 14 24 -1. + <_> + 11 0 7 24 2. + <_> + + <_> + 7 17 10 4 -1. + <_> + 7 19 10 2 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 13 15 6 9 -1. + <_> + 15 15 2 9 3. + <_> + + <_> + 3 21 18 3 -1. + <_> + 3 22 18 1 3. + <_> + + <_> + 13 15 6 9 -1. + <_> + 15 15 2 9 3. + <_> + + <_> + 5 15 6 9 -1. + <_> + 7 15 2 9 3. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 7 3 6 11 -1. + <_> + 9 3 2 11 3. + <_> + + <_> + 15 1 9 4 -1. + <_> + 15 3 9 2 2. + <_> + + <_> + 5 4 14 8 -1. + <_> + 5 8 14 4 2. + <_> + + <_> + 8 1 15 9 -1. + <_> + 8 4 15 3 3. + <_> + + <_> + 7 2 8 10 -1. + <_> + 7 2 4 5 2. + <_> + 11 7 4 5 2. + <_> + + <_> + 12 2 6 12 -1. + <_> + 12 2 3 12 2. + <_> + + <_> + 6 2 6 12 -1. + <_> + 9 2 3 12 2. + <_> + + <_> + 7 7 12 4 -1. + <_> + 7 7 6 4 2. + <_> + + <_> + 6 3 12 10 -1. + <_> + 10 3 4 10 3. + <_> + + <_> + 5 6 16 6 -1. + <_> + 13 6 8 3 2. + <_> + 5 9 8 3 2. + <_> + + <_> + 3 1 18 9 -1. + <_> + 9 1 6 9 3. + <_> + + <_> + 3 8 18 5 -1. + <_> + 9 8 6 5 3. + <_> + + <_> + 0 0 24 22 -1. + <_> + 0 0 12 11 2. + <_> + 12 11 12 11 2. + <_> + + <_> + 14 16 9 6 -1. + <_> + 14 18 9 2 3. + <_> + + <_> + 0 16 24 8 -1. + <_> + 0 20 24 4 2. + <_> + + <_> + 1 19 22 4 -1. + <_> + 12 19 11 2 2. + <_> + 1 21 11 2 2. + <_> + + <_> + 1 16 9 6 -1. + <_> + 1 18 9 2 3. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 8 5 4 2. + <_> + + <_> + 9 15 6 9 -1. + <_> + 11 15 2 9 3. + <_> + + <_> + 10 18 12 6 -1. + <_> + 16 18 6 3 2. + <_> + 10 21 6 3 2. + <_> + + <_> + 2 18 12 6 -1. + <_> + 2 18 6 3 2. + <_> + 8 21 6 3 2. + <_> + + <_> + 8 3 16 9 -1. + <_> + 8 6 16 3 3. + <_> + + <_> + 0 5 10 6 -1. + <_> + 0 7 10 2 3. + <_> + + <_> + 5 5 18 3 -1. + <_> + 5 6 18 1 3. + <_> + + <_> + 2 6 9 6 -1. + <_> + 2 9 9 3 2. + <_> + + <_> + 14 2 10 9 -1. + <_> + 14 5 10 3 3. + <_> + + <_> + 3 6 18 3 -1. + <_> + 3 7 18 1 3. + <_> + + <_> + 9 2 15 6 -1. + <_> + 9 4 15 2 3. + <_> + + <_> + 4 8 15 6 -1. + <_> + 4 10 15 2 3. + <_> + + <_> + 0 5 24 4 -1. + <_> + 12 5 12 2 2. + <_> + 0 7 12 2 2. + <_> + + <_> + 7 8 6 12 -1. + <_> + 9 8 2 12 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 0 12 6 12 -1. + <_> + 0 12 3 6 2. + <_> + 3 18 3 6 2. + <_> + + <_> + 14 12 10 6 -1. + <_> + 14 14 10 2 3. + <_> + + <_> + 2 7 18 9 -1. + <_> + 2 10 18 3 3. + <_> + + <_> + 11 14 10 9 -1. + <_> + 11 17 10 3 3. + <_> + + <_> + 7 6 10 8 -1. + <_> + 7 6 5 4 2. + <_> + 12 10 5 4 2. + <_> + + <_> + 6 6 14 6 -1. + <_> + 13 6 7 3 2. + <_> + 6 9 7 3 2. + <_> + + <_> + 4 13 9 7 -1. + <_> + 7 13 3 7 3. + <_> + + <_> + 14 10 6 12 -1. + <_> + 17 10 3 6 2. + <_> + 14 16 3 6 2. + <_> + + <_> + 4 10 6 12 -1. + <_> + 4 10 3 6 2. + <_> + 7 16 3 6 2. + <_> + + <_> + 13 9 8 6 -1. + <_> + 13 9 4 6 2. + <_> + + <_> + 8 3 4 14 -1. + <_> + 10 3 2 14 2. + <_> + + <_> + 17 0 3 18 -1. + <_> + 18 0 1 18 3. + <_> + + <_> + 4 12 16 12 -1. + <_> + 12 12 8 12 2. + <_> + + <_> + 15 0 6 14 -1. + <_> + 17 0 2 14 3. + <_> + + <_> + 3 0 6 14 -1. + <_> + 5 0 2 14 3. + <_> + + <_> + 12 2 12 20 -1. + <_> + 16 2 4 20 3. + <_> + + <_> + 0 2 12 20 -1. + <_> + 4 2 4 20 3. + <_> + + <_> + 16 0 6 17 -1. + <_> + 18 0 2 17 3. + <_> + + <_> + 2 0 6 17 -1. + <_> + 4 0 2 17 3. + <_> + + <_> + 15 6 9 6 -1. + <_> + 15 8 9 2 3. + <_> + + <_> + 0 6 9 6 -1. + <_> + 0 8 9 2 3. + <_> + + <_> + 18 1 6 13 -1. + <_> + 20 1 2 13 3. + <_> + + <_> + 0 1 6 13 -1. + <_> + 2 1 2 13 3. + <_> + + <_> + 16 0 4 9 -1. + <_> + 16 0 2 9 2. + <_> + + <_> + 5 10 12 7 -1. + <_> + 9 10 4 7 3. + <_> + + <_> + 12 9 12 6 -1. + <_> + 12 11 12 2 3. + <_> + + <_> + 0 9 12 6 -1. + <_> + 0 11 12 2 3. + <_> + + <_> + 5 7 14 9 -1. + <_> + 5 10 14 3 3. + <_> + + <_> + 0 15 20 3 -1. + <_> + 0 16 20 1 3. + <_> + + <_> + 8 10 8 10 -1. + <_> + 12 10 4 5 2. + <_> + 8 15 4 5 2. + <_> + + <_> + 5 4 13 9 -1. + <_> + 5 7 13 3 3. + <_> + + <_> + 10 2 6 18 -1. + <_> + 10 8 6 6 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 6 9 12 4 -1. + <_> + 6 11 12 2 2. + <_> + + <_> + 3 2 15 12 -1. + <_> + 3 6 15 4 3. + <_> + + <_> + 12 0 12 5 -1. + <_> + 16 0 4 5 3. + <_> + + <_> + 0 15 18 3 -1. + <_> + 6 15 6 3 3. + <_> + + <_> + 0 14 24 5 -1. + <_> + 8 14 8 5 3. + <_> + + <_> + 5 1 3 18 -1. + <_> + 6 1 1 18 3. + <_> + + <_> + 10 0 4 14 -1. + <_> + 10 0 2 14 2. + <_> + + <_> + 9 3 4 9 -1. + <_> + 11 3 2 9 2. + <_> + + <_> + 8 2 12 6 -1. + <_> + 14 2 6 3 2. + <_> + 8 5 6 3 2. + <_> + + <_> + 0 4 17 4 -1. + <_> + 0 6 17 2 2. + <_> + + <_> + 16 16 5 8 -1. + <_> + 16 20 5 4 2. + <_> + + <_> + 3 16 5 8 -1. + <_> + 3 20 5 4 2. + <_> + + <_> + 6 18 18 2 -1. + <_> + 6 19 18 1 2. + <_> + + <_> + 0 0 12 5 -1. + <_> + 4 0 4 5 3. + <_> + + <_> + 14 3 6 12 -1. + <_> + 17 3 3 6 2. + <_> + 14 9 3 6 2. + <_> + + <_> + 0 12 6 12 -1. + <_> + 2 12 2 12 3. + <_> + + <_> + 2 3 21 3 -1. + <_> + 2 4 21 1 3. + <_> + + <_> + 4 3 6 12 -1. + <_> + 4 3 3 6 2. + <_> + 7 9 3 6 2. + <_> + + <_> + 12 8 12 6 -1. + <_> + 18 8 6 3 2. + <_> + 12 11 6 3 2. + <_> + + <_> + 0 15 16 9 -1. + <_> + 8 15 8 9 2. + <_> + + <_> + 6 13 18 5 -1. + <_> + 6 13 9 5 2. + <_> + + <_> + 1 6 15 6 -1. + <_> + 6 6 5 6 3. + <_> + + <_> + 11 9 9 6 -1. + <_> + 14 9 3 6 3. + <_> + + <_> + 3 0 15 11 -1. + <_> + 8 0 5 11 3. + <_> + + <_> + 15 3 3 18 -1. + <_> + 15 9 3 6 3. + <_> + + <_> + 6 3 3 18 -1. + <_> + 6 9 3 6 3. + <_> + + <_> + 9 5 10 8 -1. + <_> + 14 5 5 4 2. + <_> + 9 9 5 4 2. + <_> + + <_> + 4 4 16 8 -1. + <_> + 4 4 8 4 2. + <_> + 12 8 8 4 2. + <_> + + <_> + 7 7 12 3 -1. + <_> + 7 7 6 3 2. + <_> + + <_> + 5 0 9 13 -1. + <_> + 8 0 3 13 3. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 8 1 10 9 -1. + <_> + 8 4 10 3 3. + <_> + + <_> + 0 2 18 2 -1. + <_> + 0 3 18 1 2. + <_> + + <_> + 10 13 14 6 -1. + <_> + 17 13 7 3 2. + <_> + 10 16 7 3 2. + <_> + + <_> + 0 13 14 6 -1. + <_> + 0 13 7 3 2. + <_> + 7 16 7 3 2. + <_> + + <_> + 20 2 3 21 -1. + <_> + 21 2 1 21 3. + <_> + + <_> + 0 9 5 12 -1. + <_> + 0 13 5 4 3. + <_> + + <_> + 12 6 12 6 -1. + <_> + 12 8 12 2 3. + <_> + + <_> + 1 8 20 3 -1. + <_> + 1 9 20 1 3. + <_> + + <_> + 5 7 19 3 -1. + <_> + 5 8 19 1 3. + <_> + + <_> + 1 12 9 6 -1. + <_> + 1 14 9 2 3. + <_> + + <_> + 6 10 14 12 -1. + <_> + 6 14 14 4 3. + <_> + + <_> + 5 6 14 18 -1. + <_> + 5 12 14 6 3. + <_> + + <_> + 11 12 9 7 -1. + <_> + 14 12 3 7 3. + <_> + + <_> + 1 15 18 4 -1. + <_> + 1 17 18 2 2. + <_> + + <_> + 11 14 6 9 -1. + <_> + 11 17 6 3 3. + <_> + + <_> + 0 8 18 4 -1. + <_> + 0 8 9 2 2. + <_> + 9 10 9 2 2. + <_> + + <_> + 3 10 20 6 -1. + <_> + 13 10 10 3 2. + <_> + 3 13 10 3 2. + <_> + + <_> + 1 10 20 6 -1. + <_> + 1 10 10 3 2. + <_> + 11 13 10 3 2. + <_> + + <_> + 0 9 24 2 -1. + <_> + 0 9 12 2 2. + <_> + + <_> + 1 12 20 8 -1. + <_> + 1 12 10 4 2. + <_> + 11 16 10 4 2. + <_> + + <_> + 11 12 9 7 -1. + <_> + 14 12 3 7 3. + <_> + + <_> + 4 12 9 7 -1. + <_> + 7 12 3 7 3. + <_> + + <_> + 12 12 8 5 -1. + <_> + 12 12 4 5 2. + <_> + + <_> + 4 12 8 5 -1. + <_> + 8 12 4 5 2. + <_> + + <_> + 13 10 4 10 -1. + <_> + 13 10 2 10 2. + <_> + + <_> + 1 15 20 2 -1. + <_> + 11 15 10 2 2. + <_> + + <_> + 9 10 6 6 -1. + <_> + 9 10 3 6 2. + <_> + + <_> + 0 1 21 3 -1. + <_> + 7 1 7 3 3. + <_> + + <_> + 6 4 13 9 -1. + <_> + 6 7 13 3 3. + <_> + + <_> + 6 5 12 5 -1. + <_> + 10 5 4 5 3. + <_> + + <_> + 10 10 10 6 -1. + <_> + 10 12 10 2 3. + <_> + + <_> + 6 12 5 8 -1. + <_> + 6 16 5 4 2. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 2 10 18 6 -1. + <_> + 8 10 6 6 3. + <_> + + <_> + 11 2 9 4 -1. + <_> + 11 4 9 2 2. + <_> + + <_> + 1 20 21 3 -1. + <_> + 8 20 7 3 3. + <_> + + <_> + 1 10 22 2 -1. + <_> + 1 11 22 1 2. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 13 0 6 9 -1. + <_> + 15 0 2 9 3. + <_> + + <_> + 5 0 6 9 -1. + <_> + 7 0 2 9 3. + <_> + + <_> + 18 2 6 20 -1. + <_> + 20 2 2 20 3. + <_> + + <_> + 0 2 6 20 -1. + <_> + 2 2 2 20 3. + <_> + + <_> + 11 7 6 14 -1. + <_> + 14 7 3 7 2. + <_> + 11 14 3 7 2. + <_> + + <_> + 0 1 4 9 -1. + <_> + 2 1 2 9 2. + <_> + + <_> + 12 14 9 4 -1. + <_> + 12 16 9 2 2. + <_> + + <_> + 1 13 9 4 -1. + <_> + 1 15 9 2 2. + <_> + + <_> + 7 6 15 6 -1. + <_> + 7 8 15 2 3. + <_> + + <_> + 8 2 3 18 -1. + <_> + 8 8 3 6 3. + <_> + + <_> + 6 6 12 6 -1. + <_> + 12 6 6 3 2. + <_> + 6 9 6 3 2. + <_> + + <_> + 2 19 20 4 -1. + <_> + 2 19 10 2 2. + <_> + 12 21 10 2 2. + <_> + + <_> + 14 15 6 9 -1. + <_> + 14 18 6 3 3. + <_> + + <_> + 3 5 18 14 -1. + <_> + 3 5 9 7 2. + <_> + 12 12 9 7 2. + <_> + + <_> + 15 6 4 18 -1. + <_> + 17 6 2 9 2. + <_> + 15 15 2 9 2. + <_> + + <_> + 5 6 4 18 -1. + <_> + 5 6 2 9 2. + <_> + 7 15 2 9 2. + <_> + + <_> + 11 0 6 9 -1. + <_> + 13 0 2 9 3. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 11 5 6 9 -1. + <_> + 13 5 2 9 3. + <_> + + <_> + 9 5 6 6 -1. + <_> + 12 5 3 6 2. + <_> + + <_> + 4 1 16 6 -1. + <_> + 12 1 8 3 2. + <_> + 4 4 8 3 2. + <_> + + <_> + 9 13 6 11 -1. + <_> + 11 13 2 11 3. + <_> + + <_> + 17 1 6 12 -1. + <_> + 20 1 3 6 2. + <_> + 17 7 3 6 2. + <_> + + <_> + 1 17 18 3 -1. + <_> + 1 18 18 1 3. + <_> + + <_> + 7 13 10 8 -1. + <_> + 7 17 10 4 2. + <_> + + <_> + 6 18 10 6 -1. + <_> + 6 20 10 2 3. + <_> + + <_> + 9 14 9 4 -1. + <_> + 9 16 9 2 2. + <_> + + <_> + 1 1 6 12 -1. + <_> + 1 1 3 6 2. + <_> + 4 7 3 6 2. + <_> + + <_> + 19 4 5 12 -1. + <_> + 19 8 5 4 3. + <_> + + <_> + 0 0 8 8 -1. + <_> + 4 0 4 8 2. + <_> + + <_> + 3 5 19 3 -1. + <_> + 3 6 19 1 3. + <_> + + <_> + 1 5 12 6 -1. + <_> + 1 5 6 3 2. + <_> + 7 8 6 3 2. + <_> + + <_> + 2 1 21 8 -1. + <_> + 9 1 7 8 3. + <_> + + <_> + 4 1 16 8 -1. + <_> + 4 5 16 4 2. + <_> + + <_> + 6 0 18 3 -1. + <_> + 6 1 18 1 3. + <_> + + <_> + 4 4 10 14 -1. + <_> + 4 11 10 7 2. + <_> + + <_> + 15 6 4 10 -1. + <_> + 15 11 4 5 2. + <_> + + <_> + 3 18 18 3 -1. + <_> + 9 18 6 3 3. + <_> + + <_> + 8 18 12 6 -1. + <_> + 12 18 4 6 3. + <_> + + <_> + 3 15 6 9 -1. + <_> + 6 15 3 9 2. + <_> + + <_> + 15 7 6 8 -1. + <_> + 15 11 6 4 2. + <_> + + <_> + 3 7 6 8 -1. + <_> + 3 11 6 4 2. + <_> + + <_> + 5 9 18 6 -1. + <_> + 14 9 9 3 2. + <_> + 5 12 9 3 2. + <_> + + <_> + 1 13 12 6 -1. + <_> + 1 15 12 2 3. + <_> + + <_> + 14 15 10 6 -1. + <_> + 14 17 10 2 3. + <_> + + <_> + 0 15 10 6 -1. + <_> + 0 17 10 2 3. + <_> + + <_> + 15 13 6 9 -1. + <_> + 15 16 6 3 3. + <_> + + <_> + 3 13 6 9 -1. + <_> + 3 16 6 3 3. + <_> + + <_> + 9 5 8 8 -1. + <_> + 9 5 4 8 2. + <_> + + <_> + 1 18 12 6 -1. + <_> + 1 18 6 3 2. + <_> + 7 21 6 3 2. + <_> + + <_> + 13 19 10 4 -1. + <_> + 13 21 10 2 2. + <_> + + <_> + 1 19 10 4 -1. + <_> + 1 21 10 2 2. + <_> + + <_> + 6 19 18 3 -1. + <_> + 6 20 18 1 3. + <_> + + <_> + 8 14 4 10 -1. + <_> + 8 19 4 5 2. + <_> + + <_> + 0 0 24 6 -1. + <_> + 0 2 24 2 3. + <_> + + <_> + 0 1 6 9 -1. + <_> + 0 4 6 3 3. + <_> + + <_> + 4 9 20 6 -1. + <_> + 14 9 10 3 2. + <_> + 4 12 10 3 2. + <_> + + <_> + 1 15 19 8 -1. + <_> + 1 19 19 4 2. + <_> + + <_> + 14 0 10 6 -1. + <_> + 14 2 10 2 3. + <_> + + <_> + 1 10 21 14 -1. + <_> + 8 10 7 14 3. + <_> + + <_> + 10 10 8 8 -1. + <_> + 10 10 4 8 2. + <_> + + <_> + 6 8 10 4 -1. + <_> + 11 8 5 4 2. + <_> + + <_> + 10 5 4 9 -1. + <_> + 10 5 2 9 2. + <_> + + <_> + 7 5 6 10 -1. + <_> + 9 5 2 10 3. + <_> + + <_> + 14 4 4 13 -1. + <_> + 14 4 2 13 2. + <_> + + <_> + 6 4 4 13 -1. + <_> + 8 4 2 13 2. + <_> + + <_> + 8 7 9 6 -1. + <_> + 11 7 3 6 3. + <_> + + <_> + 3 6 16 6 -1. + <_> + 3 6 8 3 2. + <_> + 11 9 8 3 2. + <_> + + <_> + 5 4 16 14 -1. + <_> + 13 4 8 7 2. + <_> + 5 11 8 7 2. + <_> + + <_> + 0 0 24 4 -1. + <_> + 0 0 12 2 2. + <_> + 12 2 12 2 2. + <_> + + <_> + 9 1 9 6 -1. + <_> + 12 1 3 6 3. + <_> + + <_> + 4 1 14 4 -1. + <_> + 11 1 7 4 2. + <_> + + <_> + 10 14 7 9 -1. + <_> + 10 17 7 3 3. + <_> + + <_> + 8 3 8 10 -1. + <_> + 8 3 4 5 2. + <_> + 12 8 4 5 2. + <_> + + <_> + 7 3 12 5 -1. + <_> + 11 3 4 5 3. + <_> + + <_> + 8 2 4 13 -1. + <_> + 10 2 2 13 2. + <_> + + <_> + 11 2 3 19 -1. + <_> + 12 2 1 19 3. + <_> + + <_> + 7 7 9 6 -1. + <_> + 10 7 3 6 3. + <_> + + <_> + 4 22 20 2 -1. + <_> + 4 22 10 2 2. + <_> + + <_> + 0 16 24 4 -1. + <_> + 0 16 12 2 2. + <_> + 12 18 12 2 2. + <_> + + <_> + 7 3 12 5 -1. + <_> + 11 3 4 5 3. + <_> + + <_> + 1 10 8 14 -1. + <_> + 1 10 4 7 2. + <_> + 5 17 4 7 2. + <_> + + <_> + 11 16 6 6 -1. + <_> + 11 19 6 3 2. + <_> + + <_> + 6 0 10 24 -1. + <_> + 6 0 5 12 2. + <_> + 11 12 5 12 2. + <_> + + <_> + 7 5 14 14 -1. + <_> + 14 5 7 7 2. + <_> + 7 12 7 7 2. + <_> + + <_> + 7 8 10 8 -1. + <_> + 7 8 5 4 2. + <_> + 12 12 5 4 2. + <_> + + <_> + 9 1 9 6 -1. + <_> + 12 1 3 6 3. + <_> + + <_> + 0 6 24 3 -1. + <_> + 12 6 12 3 2. + <_> + + <_> + 7 3 12 5 -1. + <_> + 11 3 4 5 3. + <_> + + <_> + 1 13 22 4 -1. + <_> + 1 13 11 2 2. + <_> + 12 15 11 2 2. + <_> + + <_> + 9 12 12 6 -1. + <_> + 9 14 12 2 3. + <_> + + <_> + 0 5 9 6 -1. + <_> + 0 7 9 2 3. + <_> + + <_> + 1 5 23 6 -1. + <_> + 1 7 23 2 3. + <_> + + <_> + 1 6 19 12 -1. + <_> + 1 10 19 4 3. + <_> + + <_> + 9 1 6 21 -1. + <_> + 9 8 6 7 3. + <_> + + <_> + 3 19 18 3 -1. + <_> + 9 19 6 3 3. + <_> + + <_> + 9 14 6 9 -1. + <_> + 11 14 2 9 3. + <_> + + <_> + 9 6 4 12 -1. + <_> + 11 6 2 12 2. + <_> + + <_> + 16 0 6 9 -1. + <_> + 18 0 2 9 3. + <_> + + <_> + 2 0 6 9 -1. + <_> + 4 0 2 9 3. + <_> + + <_> + 13 1 4 22 -1. + <_> + 15 1 2 11 2. + <_> + 13 12 2 11 2. + <_> + + <_> + 1 8 8 12 -1. + <_> + 1 14 8 6 2. + <_> + + <_> + 14 7 7 9 -1. + <_> + 14 10 7 3 3. + <_> + + <_> + 3 12 18 4 -1. + <_> + 3 12 9 2 2. + <_> + 12 14 9 2 2. + <_> + + <_> + 13 1 4 22 -1. + <_> + 15 1 2 11 2. + <_> + 13 12 2 11 2. + <_> + + <_> + 7 1 4 22 -1. + <_> + 7 1 2 11 2. + <_> + 9 12 2 11 2. + <_> + + <_> + 4 7 20 4 -1. + <_> + 14 7 10 2 2. + <_> + 4 9 10 2 2. + <_> + + <_> + 9 10 6 7 -1. + <_> + 12 10 3 7 2. + <_> + + <_> + 7 7 10 4 -1. + <_> + 7 7 5 4 2. + <_> + + <_> + 0 3 4 15 -1. + <_> + 0 8 4 5 3. + <_> + + <_> + 15 0 8 12 -1. + <_> + 19 0 4 6 2. + <_> + 15 6 4 6 2. + <_> + + <_> + 1 0 8 12 -1. + <_> + 1 0 4 6 2. + <_> + 5 6 4 6 2. + <_> + + <_> + 14 5 6 16 -1. + <_> + 16 5 2 16 3. + <_> + + <_> + 4 5 6 16 -1. + <_> + 6 5 2 16 3. + <_> + + <_> + 15 0 6 16 -1. + <_> + 17 0 2 16 3. + <_> + + <_> + 3 0 6 16 -1. + <_> + 5 0 2 16 3. + <_> + + <_> + 0 2 24 3 -1. + <_> + 0 3 24 1 3. + <_> + + <_> + 7 1 10 4 -1. + <_> + 7 3 10 2 2. + <_> + + <_> + 1 0 23 8 -1. + <_> + 1 4 23 4 2. + <_> + + <_> + 1 17 19 3 -1. + <_> + 1 18 19 1 3. + <_> + + <_> + 6 18 18 2 -1. + <_> + 6 19 18 1 2. + <_> + + <_> + 1 17 9 6 -1. + <_> + 1 19 9 2 3. + <_> + + <_> + 15 15 6 9 -1. + <_> + 15 18 6 3 3. + <_> + + <_> + 3 15 6 9 -1. + <_> + 3 18 6 3 3. + <_> + + <_> + 4 14 20 6 -1. + <_> + 4 17 20 3 2. + <_> + + <_> + 0 10 6 14 -1. + <_> + 0 10 3 7 2. + <_> + 3 17 3 7 2. + <_> + + <_> + 6 18 18 3 -1. + <_> + 6 19 18 1 3. + <_> + + <_> + 4 12 9 7 -1. + <_> + 7 12 3 7 3. + <_> + + <_> + 6 10 18 5 -1. + <_> + 12 10 6 5 3. + <_> + + <_> + 0 10 18 5 -1. + <_> + 6 10 6 5 3. + <_> + + <_> + 3 2 18 9 -1. + <_> + 9 2 6 9 3. + <_> + + <_> + 4 6 10 10 -1. + <_> + 4 6 5 5 2. + <_> + 9 11 5 5 2. + <_> + + <_> + 20 14 4 9 -1. + <_> + 20 14 2 9 2. + <_> + + <_> + 0 14 4 9 -1. + <_> + 2 14 2 9 2. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 6 21 12 3 -1. + <_> + 12 21 6 3 2. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 1 16 10 8 -1. + <_> + 1 16 5 4 2. + <_> + 6 20 5 4 2. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 1 0 3 19 -1. + <_> + 2 0 1 19 3. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 0 1 6 9 -1. + <_> + 2 1 2 9 3. + <_> + + <_> + 3 7 19 4 -1. + <_> + 3 9 19 2 2. + <_> + + <_> + 7 14 9 6 -1. + <_> + 7 16 9 2 3. + <_> + + <_> + 17 1 7 6 -1. + <_> + 17 4 7 3 2. + <_> + + <_> + 5 0 14 8 -1. + <_> + 5 4 14 4 2. + <_> + + <_> + 16 1 8 6 -1. + <_> + 16 4 8 3 2. + <_> + + <_> + 0 1 8 6 -1. + <_> + 0 4 8 3 2. + <_> + + <_> + 6 0 18 4 -1. + <_> + 15 0 9 2 2. + <_> + 6 2 9 2 2. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 3 7 18 8 -1. + <_> + 9 7 6 8 3. + <_> + + <_> + 2 11 6 9 -1. + <_> + 4 11 2 9 3. + <_> + + <_> + 10 5 6 9 -1. + <_> + 12 5 2 9 3. + <_> + + <_> + 10 6 4 18 -1. + <_> + 10 6 2 9 2. + <_> + 12 15 2 9 2. + <_> + + <_> + 11 1 4 20 -1. + <_> + 13 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 9 1 4 20 -1. + <_> + 9 1 2 10 2. + <_> + 11 11 2 10 2. + <_> + + <_> + 5 9 18 6 -1. + <_> + 14 9 9 3 2. + <_> + 5 12 9 3 2. + <_> + + <_> + 6 4 6 9 -1. + <_> + 8 4 2 9 3. + <_> + + <_> + 10 16 8 6 -1. + <_> + 10 16 4 6 2. + <_> + + <_> + 0 0 18 8 -1. + <_> + 0 0 9 4 2. + <_> + 9 4 9 4 2. + <_> + + <_> + 6 5 14 12 -1. + <_> + 13 5 7 6 2. + <_> + 6 11 7 6 2. + <_> + + <_> + 4 3 15 7 -1. + <_> + 9 3 5 7 3. + <_> + + <_> + 14 12 10 6 -1. + <_> + 14 14 10 2 3. + <_> + + <_> + 0 11 4 10 -1. + <_> + 0 16 4 5 2. + <_> + + <_> + 1 10 22 3 -1. + <_> + 1 11 22 1 3. + <_> + + <_> + 8 9 6 10 -1. + <_> + 10 9 2 10 3. + <_> + + <_> + 13 2 6 12 -1. + <_> + 16 2 3 6 2. + <_> + 13 8 3 6 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 10 6 2 9 2. + <_> + 12 15 2 9 2. + <_> + + <_> + 7 8 10 16 -1. + <_> + 12 8 5 8 2. + <_> + 7 16 5 8 2. + <_> + + <_> + 8 1 8 12 -1. + <_> + 8 1 4 6 2. + <_> + 12 7 4 6 2. + <_> + + <_> + 7 1 12 14 -1. + <_> + 13 1 6 7 2. + <_> + 7 8 6 7 2. + <_> + + <_> + 2 14 12 6 -1. + <_> + 2 16 12 2 3. + <_> + + <_> + 11 16 6 6 -1. + <_> + 11 19 6 3 2. + <_> + + <_> + 7 16 6 6 -1. + <_> + 7 19 6 3 2. + <_> + + <_> + 13 4 4 10 -1. + <_> + 13 4 2 10 2. + <_> + + <_> + 0 19 19 3 -1. + <_> + 0 20 19 1 3. + <_> + + <_> + 12 8 6 8 -1. + <_> + 12 12 6 4 2. + <_> + + <_> + 8 1 8 22 -1. + <_> + 8 12 8 11 2. + <_> + + <_> + 12 8 6 8 -1. + <_> + 12 12 6 4 2. + <_> + + <_> + 6 8 6 8 -1. + <_> + 6 12 6 4 2. + <_> + + <_> + 14 5 6 9 -1. + <_> + 14 8 6 3 3. + <_> + + <_> + 0 6 24 4 -1. + <_> + 0 8 24 2 2. + <_> + + <_> + 14 12 10 6 -1. + <_> + 14 14 10 2 3. + <_> + + <_> + 0 12 10 6 -1. + <_> + 0 14 10 2 3. + <_> + + <_> + 4 6 19 3 -1. + <_> + 4 7 19 1 3. + <_> + + <_> + 1 6 19 3 -1. + <_> + 1 7 19 1 3. + <_> + + <_> + 4 0 16 9 -1. + <_> + 4 3 16 3 3. + <_> + + <_> + 0 1 24 5 -1. + <_> + 8 1 8 5 3. + <_> + + <_> + 3 6 6 15 -1. + <_> + 3 11 6 5 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 6 22 18 2 -1. + <_> + 6 23 18 1 2. + <_> + + <_> + 2 12 6 9 -1. + <_> + 2 15 6 3 3. + <_> + + <_> + 18 12 6 9 -1. + <_> + 18 15 6 3 3. + <_> + + <_> + 0 12 6 9 -1. + <_> + 0 15 6 3 3. + <_> + + <_> + 11 14 4 10 -1. + <_> + 11 19 4 5 2. + <_> + + <_> + 9 6 6 16 -1. + <_> + 9 14 6 8 2. + <_> + + <_> + 7 7 10 10 -1. + <_> + 7 12 10 5 2. + <_> + + <_> + 1 3 6 13 -1. + <_> + 3 3 2 13 3. + <_> + + <_> + 18 1 6 13 -1. + <_> + 18 1 3 13 2. + <_> + + <_> + 5 1 6 9 -1. + <_> + 7 1 2 9 3. + <_> + + <_> + 18 2 6 11 -1. + <_> + 18 2 3 11 2. + <_> + + <_> + 0 2 6 11 -1. + <_> + 3 2 3 11 2. + <_> + + <_> + 9 12 15 6 -1. + <_> + 9 14 15 2 3. + <_> + + <_> + 2 2 20 3 -1. + <_> + 2 3 20 1 3. + <_> + + <_> + 10 6 4 9 -1. + <_> + 10 6 2 9 2. + <_> + + <_> + 5 6 12 14 -1. + <_> + 5 6 6 7 2. + <_> + 11 13 6 7 2. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 7 0 9 6 -1. + <_> + 10 0 3 6 3. + <_> + + <_> + 10 6 6 9 -1. + <_> + 12 6 2 9 3. + <_> + + <_> + 4 1 12 20 -1. + <_> + 4 1 6 10 2. + <_> + 10 11 6 10 2. + <_> + + <_> + 6 7 18 3 -1. + <_> + 6 7 9 3 2. + <_> + + <_> + 0 7 18 3 -1. + <_> + 9 7 9 3 2. + <_> + + <_> + 3 20 18 3 -1. + <_> + 9 20 6 3 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 6 2 12 15 -1. + <_> + 10 2 4 15 3. + <_> + + <_> + 2 3 18 3 -1. + <_> + 2 4 18 1 3. + <_> + + <_> + 19 4 4 18 -1. + <_> + 21 4 2 9 2. + <_> + 19 13 2 9 2. + <_> + + <_> + 0 1 19 3 -1. + <_> + 0 2 19 1 3. + <_> + + <_> + 5 0 15 4 -1. + <_> + 5 2 15 2 2. + <_> + + <_> + 5 2 14 5 -1. + <_> + 12 2 7 5 2. + <_> + + <_> + 1 2 22 14 -1. + <_> + 1 2 11 14 2. + <_> + + <_> + 8 15 6 9 -1. + <_> + 10 15 2 9 3. + <_> + + <_> + 6 17 18 3 -1. + <_> + 6 18 18 1 3. + <_> + + <_> + 9 6 3 18 -1. + <_> + 9 12 3 6 3. + <_> + + <_> + 2 0 20 3 -1. + <_> + 2 1 20 1 3. + <_> + + <_> + 5 4 5 12 -1. + <_> + 5 8 5 4 3. + <_> + + <_> + 8 6 12 5 -1. + <_> + 12 6 4 5 3. + <_> + + <_> + 9 12 6 12 -1. + <_> + 9 12 3 6 2. + <_> + 12 18 3 6 2. + <_> + + <_> + 14 14 8 10 -1. + <_> + 18 14 4 5 2. + <_> + 14 19 4 5 2. + <_> + + <_> + 2 14 8 10 -1. + <_> + 2 14 4 5 2. + <_> + 6 19 4 5 2. + <_> + + <_> + 10 18 12 6 -1. + <_> + 16 18 6 3 2. + <_> + 10 21 6 3 2. + <_> + + <_> + 1 3 6 9 -1. + <_> + 1 6 6 3 3. + <_> + + <_> + 11 3 3 20 -1. + <_> + 12 3 1 20 3. + <_> + + <_> + 4 6 14 6 -1. + <_> + 4 6 7 3 2. + <_> + 11 9 7 3 2. + <_> + + <_> + 6 5 12 13 -1. + <_> + 10 5 4 13 3. + <_> + + <_> + 5 4 4 15 -1. + <_> + 5 9 4 5 3. + <_> + + <_> + 9 16 15 4 -1. + <_> + 14 16 5 4 3. + <_> + + <_> + 7 8 6 14 -1. + <_> + 7 8 3 7 2. + <_> + 10 15 3 7 2. + <_> + + <_> + 7 6 10 6 -1. + <_> + 7 8 10 2 3. + <_> + + <_> + 2 5 18 3 -1. + <_> + 2 6 18 1 3. + <_> + + <_> + 5 1 15 8 -1. + <_> + 5 5 15 4 2. + <_> + + <_> + 7 1 8 18 -1. + <_> + 7 10 8 9 2. + <_> + + <_> + 0 10 24 3 -1. + <_> + 0 11 24 1 3. + <_> + + <_> + 0 2 6 13 -1. + <_> + 2 2 2 13 3. + <_> + + <_> + 16 0 8 10 -1. + <_> + 20 0 4 5 2. + <_> + 16 5 4 5 2. + <_> + + <_> + 5 1 10 9 -1. + <_> + 5 4 10 3 3. + <_> + + <_> + 5 6 18 3 -1. + <_> + 5 7 18 1 3. + <_> + + <_> + 0 1 24 3 -1. + <_> + 0 2 24 1 3. + <_> + + <_> + 11 4 6 11 -1. + <_> + 13 4 2 11 3. + <_> + + <_> + 0 0 8 10 -1. + <_> + 0 0 4 5 2. + <_> + 4 5 4 5 2. + <_> + + <_> + 4 16 18 3 -1. + <_> + 4 17 18 1 3. + <_> + + <_> + 2 16 18 3 -1. + <_> + 2 17 18 1 3. + <_> + + <_> + 3 0 18 10 -1. + <_> + 12 0 9 5 2. + <_> + 3 5 9 5 2. + <_> + + <_> + 2 3 20 21 -1. + <_> + 12 3 10 21 2. + <_> + + <_> + 6 7 14 3 -1. + <_> + 6 7 7 3 2. + <_> + + <_> + 0 9 12 6 -1. + <_> + 0 9 6 3 2. + <_> + 6 12 6 3 2. + <_> + + <_> + 3 14 21 4 -1. + <_> + 10 14 7 4 3. + <_> + + <_> + 0 14 21 4 -1. + <_> + 7 14 7 4 3. + <_> + + <_> + 5 21 18 3 -1. + <_> + 11 21 6 3 3. + <_> + + <_> + 1 21 18 3 -1. + <_> + 7 21 6 3 3. + <_> + + <_> + 19 4 4 18 -1. + <_> + 21 4 2 9 2. + <_> + 19 13 2 9 2. + <_> + + <_> + 3 7 18 3 -1. + <_> + 3 8 18 1 3. + <_> + + <_> + 19 4 4 18 -1. + <_> + 21 4 2 9 2. + <_> + 19 13 2 9 2. + <_> + + <_> + 7 15 10 6 -1. + <_> + 7 17 10 2 3. + <_> + + <_> + 9 13 11 9 -1. + <_> + 9 16 11 3 3. + <_> + + <_> + 0 6 4 10 -1. + <_> + 0 11 4 5 2. + <_> + + <_> + 15 16 9 6 -1. + <_> + 15 18 9 2 3. + <_> + + <_> + 1 5 4 18 -1. + <_> + 1 5 2 9 2. + <_> + 3 14 2 9 2. + <_> + + <_> + 9 8 8 10 -1. + <_> + 13 8 4 5 2. + <_> + 9 13 4 5 2. + <_> + + <_> + 7 8 8 10 -1. + <_> + 7 8 4 5 2. + <_> + 11 13 4 5 2. + <_> + + <_> + 9 8 12 5 -1. + <_> + 13 8 4 5 3. + <_> + + <_> + 7 8 9 7 -1. + <_> + 10 8 3 7 3. + <_> + + <_> + 9 8 12 5 -1. + <_> + 13 8 4 5 3. + <_> + + <_> + 7 6 9 7 -1. + <_> + 10 6 3 7 3. + <_> + + <_> + 9 8 12 5 -1. + <_> + 13 8 4 5 3. + <_> + + <_> + 10 5 4 18 -1. + <_> + 10 11 4 6 3. + <_> + + <_> + 5 5 14 12 -1. + <_> + 5 11 14 6 2. + <_> + + <_> + 0 1 11 4 -1. + <_> + 0 3 11 2 2. + <_> + + <_> + 9 10 6 10 -1. + <_> + 11 10 2 10 3. + <_> + + <_> + 2 17 11 6 -1. + <_> + 2 19 11 2 3. + <_> + + <_> + 15 16 9 6 -1. + <_> + 15 18 9 2 3. + <_> + + <_> + 1 10 18 2 -1. + <_> + 1 11 18 1 2. + <_> + + <_> + 6 4 12 13 -1. + <_> + 10 4 4 13 3. + <_> + + <_> + 0 18 18 3 -1. + <_> + 0 19 18 1 3. + <_> + + <_> + 6 18 18 3 -1. + <_> + 6 19 18 1 3. + <_> + + <_> + 0 16 9 6 -1. + <_> + 0 18 9 2 3. + <_> + + <_> + 13 15 9 6 -1. + <_> + 13 17 9 2 3. + <_> + + <_> + 2 15 9 6 -1. + <_> + 2 17 9 2 3. + <_> + + <_> + 13 1 6 16 -1. + <_> + 13 1 3 16 2. + <_> + + <_> + 5 1 6 16 -1. + <_> + 8 1 3 16 2. + <_> + + <_> + 11 5 6 10 -1. + <_> + 13 5 2 10 3. + <_> + + <_> + 7 5 6 10 -1. + <_> + 9 5 2 10 3. + <_> + + <_> + 10 0 6 24 -1. + <_> + 12 0 2 24 3. + <_> + + <_> + 3 4 4 20 -1. + <_> + 3 4 2 10 2. + <_> + 5 14 2 10 2. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 4 0 6 9 -1. + <_> + 6 0 2 9 3. + <_> + + <_> + 4 5 18 5 -1. + <_> + 10 5 6 5 3. + <_> + + <_> + 5 6 6 9 -1. + <_> + 7 6 2 9 3. + <_> + + <_> + 7 2 15 8 -1. + <_> + 12 2 5 8 3. + <_> + + <_> + 2 2 15 8 -1. + <_> + 7 2 5 8 3. + <_> + + <_> + 10 0 4 9 -1. + <_> + 10 0 2 9 2. + <_> + + <_> + 3 4 6 12 -1. + <_> + 3 4 3 6 2. + <_> + 6 10 3 6 2. + <_> + + <_> + 16 0 8 18 -1. + <_> + 16 0 4 18 2. + <_> + + <_> + 0 0 8 18 -1. + <_> + 4 0 4 18 2. + <_> + + <_> + 0 7 24 6 -1. + <_> + 0 9 24 2 3. + <_> + + <_> + 4 7 14 3 -1. + <_> + 11 7 7 3 2. + <_> + + <_> + 10 8 8 15 -1. + <_> + 10 8 4 15 2. + <_> + + <_> + 7 0 10 14 -1. + <_> + 12 0 5 14 2. + <_> + + <_> + 13 10 8 10 -1. + <_> + 17 10 4 5 2. + <_> + 13 15 4 5 2. + <_> + + <_> + 3 0 4 9 -1. + <_> + 5 0 2 9 2. + <_> + + <_> + 16 1 6 8 -1. + <_> + 16 1 3 8 2. + <_> + + <_> + 2 1 6 8 -1. + <_> + 5 1 3 8 2. + <_> + + <_> + 3 6 18 12 -1. + <_> + 3 10 18 4 3. + <_> + + <_> + 4 12 16 4 -1. + <_> + 4 14 16 2 2. + <_> + + <_> + 4 9 16 15 -1. + <_> + 4 14 16 5 3. + <_> + + <_> + 3 10 8 10 -1. + <_> + 3 10 4 5 2. + <_> + 7 15 4 5 2. + <_> + + <_> + 8 18 16 6 -1. + <_> + 16 18 8 3 2. + <_> + 8 21 8 3 2. + <_> + + <_> + 2 16 12 5 -1. + <_> + 6 16 4 5 3. + <_> + + <_> + 14 14 9 4 -1. + <_> + 14 16 9 2 2. + <_> + + <_> + 7 14 9 6 -1. + <_> + 7 16 9 2 3. + <_> + + <_> + 4 10 16 12 -1. + <_> + 4 14 16 4 3. + <_> + + <_> + 0 13 19 6 -1. + <_> + 0 15 19 2 3. + <_> + + <_> + 10 13 9 6 -1. + <_> + 10 15 9 2 3. + <_> + + <_> + 5 0 3 23 -1. + <_> + 6 0 1 23 3. + <_> + + <_> + 0 8 24 6 -1. + <_> + 0 10 24 2 3. + <_> + + <_> + 0 5 5 12 -1. + <_> + 0 9 5 4 3. + <_> + + <_> + 3 0 19 18 -1. + <_> + 3 9 19 9 2. + <_> + + <_> + 9 11 6 12 -1. + <_> + 9 11 3 6 2. + <_> + 12 17 3 6 2. + <_> + + <_> + 0 5 24 8 -1. + <_> + 12 5 12 4 2. + <_> + 0 9 12 4 2. + <_> + + <_> + 6 18 9 4 -1. + <_> + 6 20 9 2 2. + <_> + + <_> + 8 8 10 6 -1. + <_> + 8 10 10 2 3. + <_> + + <_> + 2 7 20 3 -1. + <_> + 2 8 20 1 3. + <_> + + <_> + 12 0 7 20 -1. + <_> + 12 10 7 10 2. + <_> + + <_> + 5 0 7 20 -1. + <_> + 5 10 7 10 2. + <_> + + <_> + 14 2 2 18 -1. + <_> + 14 11 2 9 2. + <_> + + <_> + 5 8 10 12 -1. + <_> + 10 8 5 12 2. + <_> + + <_> + 6 9 12 8 -1. + <_> + 12 9 6 4 2. + <_> + 6 13 6 4 2. + <_> + + <_> + 7 7 3 14 -1. + <_> + 7 14 3 7 2. + <_> + + <_> + 11 2 12 16 -1. + <_> + 17 2 6 8 2. + <_> + 11 10 6 8 2. + <_> + + <_> + 7 0 6 9 -1. + <_> + 9 0 2 9 3. + <_> + + <_> + 13 14 9 4 -1. + <_> + 13 16 9 2 2. + <_> + + <_> + 0 12 22 4 -1. + <_> + 0 12 11 2 2. + <_> + 11 14 11 2 2. + <_> + + <_> + 1 12 22 6 -1. + <_> + 12 12 11 3 2. + <_> + 1 15 11 3 2. + <_> + + <_> + 6 6 9 6 -1. + <_> + 9 6 3 6 3. + <_> + + <_> + 10 0 4 9 -1. + <_> + 10 0 2 9 2. + <_> + + <_> + 3 8 18 7 -1. + <_> + 9 8 6 7 3. + <_> + + <_> + 0 6 24 6 -1. + <_> + 0 8 24 2 3. + <_> + + <_> + 0 11 24 10 -1. + <_> + 8 11 8 10 3. + <_> + + <_> + 3 3 18 21 -1. + <_> + 9 3 6 21 3. + <_> + + <_> + 7 12 4 10 -1. + <_> + 9 12 2 10 2. + <_> + + <_> + 10 16 10 8 -1. + <_> + 15 16 5 4 2. + <_> + 10 20 5 4 2. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 12 10 6 12 -1. + <_> + 15 10 3 6 2. + <_> + 12 16 3 6 2. + <_> + + <_> + 6 10 6 12 -1. + <_> + 6 10 3 6 2. + <_> + 9 16 3 6 2. + <_> + + <_> + 16 12 6 12 -1. + <_> + 19 12 3 6 2. + <_> + 16 18 3 6 2. + <_> + + <_> + 2 12 6 12 -1. + <_> + 2 12 3 6 2. + <_> + 5 18 3 6 2. + <_> + + <_> + 10 15 6 9 -1. + <_> + 12 15 2 9 3. + <_> + + <_> + 8 15 6 9 -1. + <_> + 10 15 2 9 3. + <_> + + <_> + 14 20 10 4 -1. + <_> + 14 20 5 4 2. + <_> + + <_> + 0 20 10 4 -1. + <_> + 5 20 5 4 2. + <_> + + <_> + 11 17 9 6 -1. + <_> + 11 19 9 2 3. + <_> + + <_> + 3 2 14 4 -1. + <_> + 3 4 14 2 2. + <_> + + <_> + 10 1 10 4 -1. + <_> + 10 3 10 2 2. + <_> + + <_> + 0 15 10 4 -1. + <_> + 5 15 5 4 2. + <_> + + <_> + 19 2 3 19 -1. + <_> + 20 2 1 19 3. + <_> + + <_> + 4 12 9 8 -1. + <_> + 7 12 3 8 3. + <_> + + <_> + 4 7 5 12 -1. + <_> + 4 11 5 4 3. + <_> + + <_> + 0 1 24 3 -1. + <_> + 8 1 8 3 3. + <_> + + <_> + 6 8 12 4 -1. + <_> + 6 10 12 2 2. + <_> + + <_> + 19 3 4 10 -1. + <_> + 19 3 2 10 2. + <_> + + <_> + 0 6 9 6 -1. + <_> + 3 6 3 6 3. + <_> + + <_> + 18 0 6 22 -1. + <_> + 20 0 2 22 3. + <_> + + <_> + 0 0 6 22 -1. + <_> + 2 0 2 22 3. + <_> + + <_> + 5 15 19 3 -1. + <_> + 5 16 19 1 3. + <_> + + <_> + 10 7 4 15 -1. + <_> + 10 12 4 5 3. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 0 21 18 3 -1. + <_> + 0 22 18 1 3. + <_> + + <_> + 7 3 10 15 -1. + <_> + 7 8 10 5 3. + <_> + + <_> + 1 7 18 3 -1. + <_> + 1 8 18 1 3. + <_> + + <_> + 8 2 9 6 -1. + <_> + 11 2 3 6 3. + <_> + + <_> + 0 10 24 14 -1. + <_> + 0 17 24 7 2. + <_> + + <_> + 13 9 8 10 -1. + <_> + 17 9 4 5 2. + <_> + 13 14 4 5 2. + <_> + + <_> + 10 5 4 9 -1. + <_> + 12 5 2 9 2. + <_> + + <_> + 13 9 8 10 -1. + <_> + 17 9 4 5 2. + <_> + 13 14 4 5 2. + <_> + + <_> + 7 11 10 10 -1. + <_> + 7 11 5 5 2. + <_> + 12 16 5 5 2. + <_> + + <_> + 4 13 18 4 -1. + <_> + 13 13 9 2 2. + <_> + 4 15 9 2 2. + <_> + + <_> + 0 0 19 2 -1. + <_> + 0 1 19 1 2. + <_> + + <_> + 0 18 24 6 -1. + <_> + 8 18 8 6 3. + <_> + + <_> + 6 4 8 16 -1. + <_> + 6 12 8 8 2. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 10 10 2 2. + <_> + + <_> + 0 3 6 9 -1. + <_> + 0 6 6 3 3. + <_> + + <_> + 13 15 7 9 -1. + <_> + 13 18 7 3 3. + <_> + + <_> + 3 18 12 6 -1. + <_> + 3 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 12 14 6 9 -1. + <_> + 12 17 6 3 3. + <_> + + <_> + 2 15 15 8 -1. + <_> + 2 19 15 4 2. + <_> + + <_> + 9 6 6 16 -1. + <_> + 9 14 6 8 2. + <_> + + <_> + 6 6 7 12 -1. + <_> + 6 10 7 4 3. + <_> + + <_> + 14 6 6 9 -1. + <_> + 14 9 6 3 3. + <_> + + <_> + 5 14 6 9 -1. + <_> + 5 17 6 3 3. + <_> + + <_> + 10 8 6 9 -1. + <_> + 12 8 2 9 3. + <_> + + <_> + 6 6 4 18 -1. + <_> + 6 6 2 9 2. + <_> + 8 15 2 9 2. + <_> + + <_> + 14 9 6 12 -1. + <_> + 17 9 3 6 2. + <_> + 14 15 3 6 2. + <_> + + <_> + 4 9 6 12 -1. + <_> + 4 9 3 6 2. + <_> + 7 15 3 6 2. + <_> + + <_> + 14 15 9 6 -1. + <_> + 14 17 9 2 3. + <_> + + <_> + 0 20 18 4 -1. + <_> + 0 20 9 2 2. + <_> + 9 22 9 2 2. + <_> + + <_> + 13 18 9 6 -1. + <_> + 13 20 9 2 3. + <_> + + <_> + 2 18 9 6 -1. + <_> + 2 20 9 2 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 19 2 4 22 -1. + <_> + 21 2 2 11 2. + <_> + 19 13 2 11 2. + <_> + + <_> + 1 2 4 22 -1. + <_> + 1 2 2 11 2. + <_> + 3 13 2 11 2. + <_> + + <_> + 15 0 2 24 -1. + <_> + 15 0 1 24 2. + <_> + + <_> + 3 20 16 4 -1. + <_> + 11 20 8 4 2. + <_> + + <_> + 11 6 4 18 -1. + <_> + 13 6 2 9 2. + <_> + 11 15 2 9 2. + <_> + + <_> + 7 9 10 14 -1. + <_> + 7 9 5 7 2. + <_> + 12 16 5 7 2. + <_> + + <_> + 14 6 6 9 -1. + <_> + 14 9 6 3 3. + <_> + + <_> + 3 6 7 9 -1. + <_> + 3 9 7 3 3. + <_> + + <_> + 20 4 4 20 -1. + <_> + 22 4 2 10 2. + <_> + 20 14 2 10 2. + <_> + + <_> + 7 6 6 9 -1. + <_> + 7 9 6 3 3. + <_> + + <_> + 7 0 10 14 -1. + <_> + 12 0 5 7 2. + <_> + 7 7 5 7 2. + <_> + + <_> + 2 1 18 6 -1. + <_> + 11 1 9 6 2. + <_> + + <_> + 15 0 2 24 -1. + <_> + 15 0 1 24 2. + <_> + + <_> + 7 0 2 24 -1. + <_> + 8 0 1 24 2. + <_> + + <_> + 13 12 6 7 -1. + <_> + 13 12 3 7 2. + <_> + + <_> + 5 12 6 7 -1. + <_> + 8 12 3 7 2. + <_> + + <_> + 3 5 18 19 -1. + <_> + 9 5 6 19 3. + <_> + + <_> + 5 6 9 6 -1. + <_> + 8 6 3 6 3. + <_> + + <_> + 9 5 9 6 -1. + <_> + 12 5 3 6 3. + <_> + + <_> + 3 16 10 8 -1. + <_> + 3 16 5 4 2. + <_> + 8 20 5 4 2. + <_> + + <_> + 19 8 5 15 -1. + <_> + 19 13 5 5 3. + <_> + + <_> + 0 8 5 15 -1. + <_> + 0 13 5 5 3. + <_> + + <_> + 20 4 4 20 -1. + <_> + 22 4 2 10 2. + <_> + 20 14 2 10 2. + <_> + + <_> + 0 4 4 20 -1. + <_> + 0 4 2 10 2. + <_> + 2 14 2 10 2. + <_> + + <_> + 7 7 10 4 -1. + <_> + 7 7 5 4 2. + <_> + + <_> + 4 19 14 4 -1. + <_> + 11 19 7 4 2. + <_> + + <_> + 10 11 12 3 -1. + <_> + 10 11 6 3 2. + <_> + + <_> + 0 1 24 3 -1. + <_> + 0 2 24 1 3. + <_> + + <_> + 7 2 14 20 -1. + <_> + 14 2 7 10 2. + <_> + 7 12 7 10 2. + <_> + + <_> + 0 13 6 9 -1. + <_> + 2 13 2 9 3. + <_> + + <_> + 13 0 4 19 -1. + <_> + 13 0 2 19 2. + <_> + + <_> + 1 11 14 3 -1. + <_> + 8 11 7 3 2. + <_> + + <_> + 7 1 16 20 -1. + <_> + 15 1 8 10 2. + <_> + 7 11 8 10 2. + <_> + + <_> + 0 10 21 9 -1. + <_> + 7 10 7 9 3. + <_> + + <_> + 6 19 15 5 -1. + <_> + 11 19 5 5 3. + <_> + + <_> + 8 10 6 6 -1. + <_> + 11 10 3 6 2. + <_> + + <_> + 7 1 16 20 -1. + <_> + 15 1 8 10 2. + <_> + 7 11 8 10 2. + <_> + + <_> + 1 1 16 20 -1. + <_> + 1 1 8 10 2. + <_> + 9 11 8 10 2. + <_> + + <_> + 16 4 3 12 -1. + <_> + 16 10 3 6 2. + <_> + + <_> + 5 4 3 12 -1. + <_> + 5 10 3 6 2. + <_> + + <_> + 7 6 10 8 -1. + <_> + 12 6 5 4 2. + <_> + 7 10 5 4 2. + <_> + + <_> + 4 9 6 6 -1. + <_> + 4 12 6 3 2. + <_> + + <_> + 6 5 12 4 -1. + <_> + 6 7 12 2 2. + <_> + + <_> + 9 2 5 15 -1. + <_> + 9 7 5 5 3. + <_> + + <_> + 15 0 9 6 -1. + <_> + 15 2 9 2 3. + <_> + + <_> + 6 0 11 10 -1. + <_> + 6 5 11 5 2. + <_> + + <_> + 12 7 4 12 -1. + <_> + 12 13 4 6 2. + <_> + + <_> + 7 2 9 4 -1. + <_> + 7 4 9 2 2. + <_> + + <_> + 6 0 13 6 -1. + <_> + 6 2 13 2 3. + <_> + + <_> + 10 6 4 18 -1. + <_> + 10 6 2 9 2. + <_> + 12 15 2 9 2. + <_> + + <_> + 10 8 6 9 -1. + <_> + 12 8 2 9 3. + <_> + + <_> + 3 18 10 6 -1. + <_> + 3 20 10 2 3. + <_> + + <_> + 4 14 20 3 -1. + <_> + 4 15 20 1 3. + <_> + + <_> + 2 15 9 6 -1. + <_> + 2 17 9 2 3. + <_> + + <_> + 13 0 4 19 -1. + <_> + 13 0 2 19 2. + <_> + + <_> + 7 0 4 19 -1. + <_> + 9 0 2 19 2. + <_> + + <_> + 1 4 22 2 -1. + <_> + 1 5 22 1 2. + <_> + + <_> + 0 0 9 6 -1. + <_> + 0 2 9 2 3. + <_> + + <_> + 0 0 24 18 -1. + <_> + 0 9 24 9 2. + <_> + + <_> + 3 2 16 8 -1. + <_> + 3 6 16 4 2. + <_> + + <_> + 3 6 18 6 -1. + <_> + 3 8 18 2 3. + <_> + + <_> + 3 1 6 10 -1. + <_> + 5 1 2 10 3. + <_> + + <_> + 13 0 9 6 -1. + <_> + 16 0 3 6 3. + <_> + + <_> + 2 0 9 6 -1. + <_> + 5 0 3 6 3. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 6 0 7 10 -1. + <_> + 6 5 7 5 2. + <_> + + <_> + 2 2 20 4 -1. + <_> + 12 2 10 2 2. + <_> + 2 4 10 2 2. + <_> + + <_> + 2 11 19 3 -1. + <_> + 2 12 19 1 3. + <_> + + <_> + 10 8 6 9 -1. + <_> + 12 8 2 9 3. + <_> + + <_> + 8 8 6 9 -1. + <_> + 10 8 2 9 3. + <_> + + <_> + 13 8 4 9 -1. + <_> + 13 8 2 9 2. + <_> + + <_> + 3 11 9 9 -1. + <_> + 6 11 3 9 3. + <_> + + <_> + 3 9 18 5 -1. + <_> + 9 9 6 5 3. + <_> + + <_> + 2 4 2 20 -1. + <_> + 2 14 2 10 2. + <_> + + <_> + 14 17 8 6 -1. + <_> + 14 20 8 3 2. + <_> + + <_> + 3 21 18 2 -1. + <_> + 3 22 18 1 2. + <_> + + <_> + 5 4 15 6 -1. + <_> + 10 4 5 6 3. + <_> + + <_> + 2 15 12 6 -1. + <_> + 2 17 12 2 3. + <_> + + <_> + 17 8 6 9 -1. + <_> + 17 11 6 3 3. + <_> + + <_> + 2 12 20 4 -1. + <_> + 2 12 10 2 2. + <_> + 12 14 10 2 2. + <_> + + <_> + 0 17 24 6 -1. + <_> + 0 19 24 2 3. + <_> + + <_> + 7 16 9 4 -1. + <_> + 7 18 9 2 2. + <_> + + <_> + 15 1 4 22 -1. + <_> + 17 1 2 11 2. + <_> + 15 12 2 11 2. + <_> + + <_> + 5 1 4 22 -1. + <_> + 5 1 2 11 2. + <_> + 7 12 2 11 2. + <_> + + <_> + 11 13 8 9 -1. + <_> + 11 16 8 3 3. + <_> + + <_> + 6 1 6 9 -1. + <_> + 8 1 2 9 3. + <_> + + <_> + 11 4 3 18 -1. + <_> + 11 10 3 6 3. + <_> + + <_> + 5 8 12 6 -1. + <_> + 5 8 6 3 2. + <_> + 11 11 6 3 2. + <_> + + <_> + 15 7 5 8 -1. + <_> + 15 11 5 4 2. + <_> + + <_> + 4 7 5 8 -1. + <_> + 4 11 5 4 2. + <_> + + <_> + 12 6 6 12 -1. + <_> + 15 6 3 6 2. + <_> + 12 12 3 6 2. + <_> + + <_> + 6 6 6 12 -1. + <_> + 6 6 3 6 2. + <_> + 9 12 3 6 2. + <_> + + <_> + 5 9 14 8 -1. + <_> + 12 9 7 4 2. + <_> + 5 13 7 4 2. + <_> + + <_> + 9 1 3 14 -1. + <_> + 9 8 3 7 2. + <_> + + <_> + 12 6 6 12 -1. + <_> + 12 10 6 4 3. + <_> + + <_> + 4 5 4 18 -1. + <_> + 4 5 2 9 2. + <_> + 6 14 2 9 2. + <_> + + <_> + 4 6 16 18 -1. + <_> + 4 12 16 6 3. + <_> + + <_> + 5 4 7 20 -1. + <_> + 5 14 7 10 2. + <_> + + <_> + 14 8 8 12 -1. + <_> + 14 14 8 6 2. + <_> + + <_> + 9 10 6 14 -1. + <_> + 9 10 3 7 2. + <_> + 12 17 3 7 2. + <_> + + <_> + 9 5 9 6 -1. + <_> + 12 5 3 6 3. + <_> + + <_> + 9 4 3 18 -1. + <_> + 10 4 1 18 3. + <_> + + <_> + 1 4 22 14 -1. + <_> + 12 4 11 7 2. + <_> + 1 11 11 7 2. + <_> + + <_> + 2 7 18 2 -1. + <_> + 2 8 18 1 2. + <_> + + <_> + 12 6 6 12 -1. + <_> + 12 10 6 4 3. + <_> + + <_> + 6 5 9 7 -1. + <_> + 9 5 3 7 3. + <_> + + <_> + 12 7 4 12 -1. + <_> + 12 13 4 6 2. + <_> + + <_> + 8 7 4 12 -1. + <_> + 8 13 4 6 2. + <_> + + <_> + 7 2 10 22 -1. + <_> + 7 13 10 11 2. + <_> + + <_> + 0 1 3 20 -1. + <_> + 1 1 1 20 3. + <_> + + <_> + 4 13 18 4 -1. + <_> + 13 13 9 2 2. + <_> + 4 15 9 2 2. + <_> + + <_> + 2 13 18 4 -1. + <_> + 2 13 9 2 2. + <_> + 11 15 9 2 2. + <_> + + <_> + 15 15 9 6 -1. + <_> + 15 17 9 2 3. + <_> + + <_> + 0 15 9 6 -1. + <_> + 0 17 9 2 3. + <_> + + <_> + 6 0 18 24 -1. + <_> + 15 0 9 12 2. + <_> + 6 12 9 12 2. + <_> + + <_> + 6 6 6 12 -1. + <_> + 6 10 6 4 3. + <_> + + <_> + 8 7 10 4 -1. + <_> + 8 9 10 2 2. + <_> + + <_> + 1 9 18 6 -1. + <_> + 1 9 9 3 2. + <_> + 10 12 9 3 2. + <_> + + <_> + 6 6 18 3 -1. + <_> + 6 7 18 1 3. + <_> + + <_> + 7 7 9 8 -1. + <_> + 10 7 3 8 3. + <_> + + <_> + 10 12 6 12 -1. + <_> + 12 12 2 12 3. + <_> + + <_> + 3 14 18 3 -1. + <_> + 3 15 18 1 3. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 1 12 10 6 -1. + <_> + 1 14 10 2 3. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 10 3 3 19 -1. + <_> + 11 3 1 19 3. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 6 1 11 9 -1. + <_> + 6 4 11 3 3. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 6 5 11 6 -1. + <_> + 6 8 11 3 2. + <_> + + <_> + 16 7 8 5 -1. + <_> + 16 7 4 5 2. + <_> + + <_> + 2 4 20 19 -1. + <_> + 12 4 10 19 2. + <_> + + <_> + 2 1 21 6 -1. + <_> + 9 1 7 6 3. + <_> + + <_> + 6 5 12 14 -1. + <_> + 6 5 6 7 2. + <_> + 12 12 6 7 2. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 2 11 8 5 -1. + <_> + 6 11 4 5 2. + <_> + + <_> + 16 7 8 5 -1. + <_> + 16 7 4 5 2. + <_> + + <_> + 0 7 8 5 -1. + <_> + 4 7 4 5 2. + <_> + + <_> + 15 17 9 7 -1. + <_> + 18 17 3 7 3. + <_> + + <_> + 8 6 8 10 -1. + <_> + 8 6 4 5 2. + <_> + 12 11 4 5 2. + <_> + + <_> + 15 15 9 9 -1. + <_> + 18 15 3 9 3. + <_> + + <_> + 0 15 9 9 -1. + <_> + 3 15 3 9 3. + <_> + + <_> + 12 10 9 7 -1. + <_> + 15 10 3 7 3. + <_> + + <_> + 3 10 9 7 -1. + <_> + 6 10 3 7 3. + <_> + + <_> + 13 15 10 8 -1. + <_> + 18 15 5 4 2. + <_> + 13 19 5 4 2. + <_> + + <_> + 0 1 6 12 -1. + <_> + 0 1 3 6 2. + <_> + 3 7 3 6 2. + <_> + + <_> + 10 0 6 12 -1. + <_> + 13 0 3 6 2. + <_> + 10 6 3 6 2. + <_> + + <_> + 7 0 10 12 -1. + <_> + 7 0 5 6 2. + <_> + 12 6 5 6 2. + <_> + + <_> + 4 1 16 8 -1. + <_> + 4 1 8 8 2. + <_> + + <_> + 0 21 19 3 -1. + <_> + 0 22 19 1 3. + <_> + + <_> + 6 9 18 4 -1. + <_> + 15 9 9 2 2. + <_> + 6 11 9 2 2. + <_> + + <_> + 3 4 9 6 -1. + <_> + 3 6 9 2 3. + <_> + + <_> + 9 1 6 15 -1. + <_> + 9 6 6 5 3. + <_> + + <_> + 5 9 6 6 -1. + <_> + 8 9 3 6 2. + <_> + + <_> + 5 1 14 9 -1. + <_> + 5 4 14 3 3. + <_> + + <_> + 3 0 8 20 -1. + <_> + 3 0 4 10 2. + <_> + 7 10 4 10 2. + <_> + + <_> + 5 0 7 9 -1. + <_> + 5 3 7 3 3. + <_> + + <_> + 6 6 12 5 -1. + <_> + 10 6 4 5 3. + <_> + + <_> + 0 1 8 14 -1. + <_> + 4 1 4 14 2. + <_> + + <_> + 2 12 22 4 -1. + <_> + 2 14 22 2 2. + <_> + + <_> + 8 17 6 6 -1. + <_> + 8 20 6 3 2. + <_> + + <_> + 18 1 6 7 -1. + <_> + 18 1 3 7 2. + <_> + + <_> + 0 0 6 6 -1. + <_> + 3 0 3 6 2. + <_> + + <_> + 4 6 17 18 -1. + <_> + 4 12 17 6 3. + <_> + + <_> + 6 0 12 6 -1. + <_> + 6 0 6 3 2. + <_> + 12 3 6 3 2. + <_> + + <_> + 4 7 18 4 -1. + <_> + 13 7 9 2 2. + <_> + 4 9 9 2 2. + <_> + + <_> + 4 12 10 6 -1. + <_> + 4 14 10 2 3. + <_> + + <_> + 7 9 10 12 -1. + <_> + 12 9 5 6 2. + <_> + 7 15 5 6 2. + <_> + + <_> + 0 1 24 3 -1. + <_> + 8 1 8 3 3. + <_> + + <_> + 13 11 6 6 -1. + <_> + 13 11 3 6 2. + <_> + + <_> + 5 11 6 6 -1. + <_> + 8 11 3 6 2. + <_> + + <_> + 3 10 19 3 -1. + <_> + 3 11 19 1 3. + <_> + + <_> + 0 2 6 9 -1. + <_> + 0 5 6 3 3. + <_> + + <_> + 14 16 10 6 -1. + <_> + 14 18 10 2 3. + <_> + + <_> + 0 16 10 6 -1. + <_> + 0 18 10 2 3. + <_> + + <_> + 14 13 9 6 -1. + <_> + 14 15 9 2 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 0 18 9 6 -1. + <_> + 0 20 9 2 3. + <_> + + <_> + 14 13 9 6 -1. + <_> + 14 15 9 2 3. + <_> + + <_> + 6 2 6 9 -1. + <_> + 8 2 2 9 3. + <_> + + <_> + 15 8 4 12 -1. + <_> + 15 8 2 12 2. + <_> + + <_> + 8 13 8 8 -1. + <_> + 8 17 8 4 2. + <_> + + <_> + 4 20 18 3 -1. + <_> + 10 20 6 3 3. + <_> + + <_> + 5 8 4 12 -1. + <_> + 7 8 2 12 2. + <_> + + <_> + 7 7 12 3 -1. + <_> + 7 7 6 3 2. + <_> + + <_> + 10 6 4 9 -1. + <_> + 12 6 2 9 2. + <_> + + <_> + 5 20 18 3 -1. + <_> + 11 20 6 3 3. + <_> + + <_> + 1 20 18 3 -1. + <_> + 7 20 6 3 3. + <_> + + <_> + 18 1 6 20 -1. + <_> + 21 1 3 10 2. + <_> + 18 11 3 10 2. + <_> + + <_> + 0 1 6 20 -1. + <_> + 0 1 3 10 2. + <_> + 3 11 3 10 2. + <_> + + <_> + 13 3 4 18 -1. + <_> + 15 3 2 9 2. + <_> + 13 12 2 9 2. + <_> + + <_> + 0 2 6 12 -1. + <_> + 0 6 6 4 3. + <_> + + <_> + 12 9 12 6 -1. + <_> + 18 9 6 3 2. + <_> + 12 12 6 3 2. + <_> + + <_> + 7 3 4 18 -1. + <_> + 7 3 2 9 2. + <_> + 9 12 2 9 2. + <_> + + <_> + 14 0 6 9 -1. + <_> + 16 0 2 9 3. + <_> + + <_> + 0 9 12 6 -1. + <_> + 0 9 6 3 2. + <_> + 6 12 6 3 2. + <_> + + <_> + 14 4 8 20 -1. + <_> + 18 4 4 10 2. + <_> + 14 14 4 10 2. + <_> + + <_> + 2 4 8 20 -1. + <_> + 2 4 4 10 2. + <_> + 6 14 4 10 2. + <_> + + <_> + 14 13 9 6 -1. + <_> + 14 15 9 2 3. + <_> + + <_> + 1 13 9 6 -1. + <_> + 1 15 9 2 3. + <_> + + <_> + 3 15 18 3 -1. + <_> + 9 15 6 3 3. + <_> + + <_> + 5 13 9 6 -1. + <_> + 5 15 9 2 3. + <_> + + <_> + 5 0 18 3 -1. + <_> + 5 1 18 1 3. + <_> + + <_> + 8 2 6 7 -1. + <_> + 11 2 3 7 2. + <_> + + <_> + 9 1 9 6 -1. + <_> + 12 1 3 6 3. + <_> + + <_> + 6 1 9 6 -1. + <_> + 9 1 3 6 3. + <_> + + <_> + 5 6 14 6 -1. + <_> + 12 6 7 3 2. + <_> + 5 9 7 3 2. + <_> + + <_> + 8 2 6 13 -1. + <_> + 10 2 2 13 3. + <_> + + <_> + 6 11 12 6 -1. + <_> + 12 11 6 3 2. + <_> + 6 14 6 3 2. + <_> + + <_> + 3 1 18 15 -1. + <_> + 9 1 6 15 3. + <_> + + <_> + 13 0 6 7 -1. + <_> + 13 0 3 7 2. + <_> + + <_> + 3 3 16 6 -1. + <_> + 3 6 16 3 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 7 7 6 9 -1. + <_> + 9 7 2 9 3. + <_> + + <_> + 13 0 4 24 -1. + <_> + 13 0 2 24 2. + <_> + + <_> + 7 0 4 24 -1. + <_> + 9 0 2 24 2. + <_> + + <_> + 11 9 5 12 -1. + <_> + 11 13 5 4 3. + <_> + + <_> + 7 15 9 6 -1. + <_> + 7 17 9 2 3. + <_> + + <_> + 5 7 18 6 -1. + <_> + 5 9 18 2 3. + <_> + + <_> + 8 9 5 12 -1. + <_> + 8 13 5 4 3. + <_> + + <_> + 4 17 17 6 -1. + <_> + 4 19 17 2 3. + <_> + + <_> + 0 3 18 14 -1. + <_> + 0 3 9 7 2. + <_> + 9 10 9 7 2. + <_> + + <_> + 0 1 24 2 -1. + <_> + 0 2 24 1 2. + <_> + + <_> + 0 15 18 3 -1. + <_> + 0 16 18 1 3. + <_> + + <_> + 9 0 6 9 -1. + <_> + 11 0 2 9 3. + <_> + + <_> + 3 3 14 12 -1. + <_> + 3 9 14 6 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 8 0 6 9 -1. + <_> + 10 0 2 9 3. + <_> + + <_> + 10 6 6 10 -1. + <_> + 12 6 2 10 3. + <_> + + <_> + 5 0 6 9 -1. + <_> + 7 0 2 9 3. + <_> + + <_> + 2 0 21 7 -1. + <_> + 9 0 7 7 3. + <_> + + <_> + 6 11 12 5 -1. + <_> + 10 11 4 5 3. + <_> + + <_> + 8 7 9 8 -1. + <_> + 11 7 3 8 3. + <_> + + <_> + 9 6 6 18 -1. + <_> + 9 6 3 9 2. + <_> + 12 15 3 9 2. + <_> + + <_> + 15 14 8 10 -1. + <_> + 19 14 4 5 2. + <_> + 15 19 4 5 2. + <_> + + <_> + 1 14 8 10 -1. + <_> + 1 14 4 5 2. + <_> + 5 19 4 5 2. + <_> + + <_> + 11 0 8 10 -1. + <_> + 15 0 4 5 2. + <_> + 11 5 4 5 2. + <_> + + <_> + 5 0 8 10 -1. + <_> + 5 0 4 5 2. + <_> + 9 5 4 5 2. + <_> + + <_> + 6 1 12 5 -1. + <_> + 6 1 6 5 2. + <_> + + <_> + 1 12 18 2 -1. + <_> + 10 12 9 2 2. + <_> + + <_> + 2 8 20 6 -1. + <_> + 12 8 10 3 2. + <_> + 2 11 10 3 2. + <_> + + <_> + 7 6 9 7 -1. + <_> + 10 6 3 7 3. + <_> + + <_> + 10 5 8 16 -1. + <_> + 14 5 4 8 2. + <_> + 10 13 4 8 2. + <_> + + <_> + 3 9 16 8 -1. + <_> + 3 9 8 4 2. + <_> + 11 13 8 4 2. + <_> + + <_> + 7 8 10 4 -1. + <_> + 7 8 5 4 2. + <_> + + <_> + 7 12 10 8 -1. + <_> + 7 12 5 4 2. + <_> + 12 16 5 4 2. + <_> + + <_> + 9 19 15 4 -1. + <_> + 14 19 5 4 3. + <_> + + <_> + 1 0 18 9 -1. + <_> + 7 0 6 9 3. + <_> + + <_> + 13 4 10 8 -1. + <_> + 18 4 5 4 2. + <_> + 13 8 5 4 2. + <_> + + <_> + 3 16 18 4 -1. + <_> + 9 16 6 4 3. + <_> + + <_> + 8 7 10 12 -1. + <_> + 13 7 5 6 2. + <_> + 8 13 5 6 2. + <_> + + <_> + 6 7 10 12 -1. + <_> + 6 7 5 6 2. + <_> + 11 13 5 6 2. + <_> + + <_> + 4 6 18 7 -1. + <_> + 10 6 6 7 3. + <_> + + <_> + 0 17 18 3 -1. + <_> + 0 18 18 1 3. + <_> + + <_> + 3 17 18 3 -1. + <_> + 3 18 18 1 3. + <_> + + <_> + 2 4 6 10 -1. + <_> + 4 4 2 10 3. + <_> + + <_> + 16 0 8 24 -1. + <_> + 16 0 4 24 2. + <_> + + <_> + 4 0 8 15 -1. + <_> + 8 0 4 15 2. + <_> + + <_> + 16 0 8 24 -1. + <_> + 16 0 4 24 2. + <_> + + <_> + 1 4 18 9 -1. + <_> + 7 4 6 9 3. + <_> + + <_> + 15 12 9 6 -1. + <_> + 15 14 9 2 3. + <_> + + <_> + 3 9 18 6 -1. + <_> + 3 9 9 3 2. + <_> + 12 12 9 3 2. + <_> + + <_> + 18 5 6 9 -1. + <_> + 18 8 6 3 3. + <_> + + <_> + 0 5 6 9 -1. + <_> + 0 8 6 3 3. + <_> + + <_> + 4 7 18 4 -1. + <_> + 13 7 9 2 2. + <_> + 4 9 9 2 2. + <_> + + <_> + 2 1 12 20 -1. + <_> + 2 1 6 10 2. + <_> + 8 11 6 10 2. + <_> + + <_> + 17 0 6 23 -1. + <_> + 17 0 3 23 2. + <_> + + <_> + 1 6 2 18 -1. + <_> + 1 15 2 9 2. + <_> + + <_> + 8 8 10 6 -1. + <_> + 8 10 10 2 3. + <_> + + <_> + 0 6 20 6 -1. + <_> + 0 6 10 3 2. + <_> + 10 9 10 3 2. + <_> + + <_> + 11 12 12 5 -1. + <_> + 15 12 4 5 3. + <_> + + <_> + 0 4 3 19 -1. + <_> + 1 4 1 19 3. + <_> + + <_> + 19 1 3 18 -1. + <_> + 20 1 1 18 3. + <_> + + <_> + 2 1 3 18 -1. + <_> + 3 1 1 18 3. + <_> + + <_> + 3 10 18 3 -1. + <_> + 9 10 6 3 3. + <_> + + <_> + 4 4 10 9 -1. + <_> + 9 4 5 9 2. + <_> + + <_> + 7 13 14 7 -1. + <_> + 7 13 7 7 2. + <_> + + <_> + 3 13 14 7 -1. + <_> + 10 13 7 7 2. + <_> + + <_> + 8 15 9 6 -1. + <_> + 11 15 3 6 3. + <_> + + <_> + 4 14 8 10 -1. + <_> + 4 14 4 5 2. + <_> + 8 19 4 5 2. + <_> + + <_> + 10 14 4 10 -1. + <_> + 10 19 4 5 2. + <_> + + <_> + 3 8 5 16 -1. + <_> + 3 16 5 8 2. + <_> + + <_> + 15 10 9 6 -1. + <_> + 15 12 9 2 3. + <_> + + <_> + 0 10 9 6 -1. + <_> + 0 12 9 2 3. + <_> + + <_> + 6 7 12 9 -1. + <_> + 6 10 12 3 3. + <_> + + <_> + 9 10 5 8 -1. + <_> + 9 14 5 4 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 8 15 6 9 -1. + <_> + 10 15 2 9 3. + <_> + + <_> + 16 6 7 6 -1. + <_> + 16 9 7 3 2. + <_> + + <_> + 8 1 4 22 -1. + <_> + 10 1 2 22 2. + <_> + + <_> + 6 6 14 3 -1. + <_> + 6 6 7 3 2. + <_> + + <_> + 0 18 19 3 -1. + <_> + 0 19 19 1 3. + <_> + + <_> + 17 0 6 24 -1. + <_> + 17 0 3 24 2. + <_> + + <_> + 0 13 15 6 -1. + <_> + 5 13 5 6 3. + <_> + + <_> + 9 6 10 14 -1. + <_> + 14 6 5 7 2. + <_> + 9 13 5 7 2. + <_> + + <_> + 1 6 8 10 -1. + <_> + 1 6 4 5 2. + <_> + 5 11 4 5 2. + <_> + + <_> + 7 6 12 5 -1. + <_> + 7 6 6 5 2. + <_> + + <_> + 7 7 9 6 -1. + <_> + 10 7 3 6 3. + <_> + + <_> + 7 8 14 14 -1. + <_> + 14 8 7 7 2. + <_> + 7 15 7 7 2. + <_> + + <_> + 3 8 14 14 -1. + <_> + 3 8 7 7 2. + <_> + 10 15 7 7 2. + <_> + + <_> + 9 8 13 4 -1. + <_> + 9 10 13 2 2. + <_> + + <_> + 3 2 6 12 -1. + <_> + 3 2 3 6 2. + <_> + 6 8 3 6 2. + <_> + + <_> + 6 10 17 6 -1. + <_> + 6 13 17 3 2. + <_> + + <_> + 1 10 17 6 -1. + <_> + 1 13 17 3 2. + <_> + + <_> + 16 7 8 9 -1. + <_> + 16 10 8 3 3. + <_> + + <_> + 0 7 8 9 -1. + <_> + 0 10 8 3 3. + <_> + + <_> + 0 9 24 10 -1. + <_> + 12 9 12 5 2. + <_> + 0 14 12 5 2. + <_> + + <_> + 3 2 15 8 -1. + <_> + 8 2 5 8 3. + <_> + + <_> + 4 2 18 8 -1. + <_> + 10 2 6 8 3. + <_> + + <_> + 0 1 18 4 -1. + <_> + 0 1 9 2 2. + <_> + 9 3 9 2 2. + <_> + + <_> + 20 2 3 18 -1. + <_> + 21 2 1 18 3. + <_> + + <_> + 1 3 3 19 -1. + <_> + 2 3 1 19 3. + <_> + + <_> + 18 8 6 16 -1. + <_> + 20 8 2 16 3. + <_> + + <_> + 0 8 6 16 -1. + <_> + 2 8 2 16 3. + <_> + + <_> + 8 18 11 6 -1. + <_> + 8 20 11 2 3. + <_> + + <_> + 4 6 12 5 -1. + <_> + 8 6 4 5 3. + <_> + + <_> + 7 6 12 5 -1. + <_> + 11 6 4 5 3. + <_> + + <_> + 6 3 9 6 -1. + <_> + 9 3 3 6 3. + <_> + + <_> + 7 6 12 5 -1. + <_> + 7 6 6 5 2. + <_> + + <_> + 9 8 6 7 -1. + <_> + 12 8 3 7 2. + <_> + + <_> + 8 2 9 6 -1. + <_> + 11 2 3 6 3. + <_> + + <_> + 8 14 6 9 -1. + <_> + 8 17 6 3 3. + <_> + + <_> + 8 2 9 6 -1. + <_> + 11 2 3 6 3. + <_> + + <_> + 4 3 16 20 -1. + <_> + 4 3 8 10 2. + <_> + 12 13 8 10 2. + <_> + + <_> + 7 6 10 12 -1. + <_> + 12 6 5 6 2. + <_> + 7 12 5 6 2. + <_> + + <_> + 0 2 7 12 -1. + <_> + 0 6 7 4 3. + <_> + + <_> + 12 17 11 6 -1. + <_> + 12 19 11 2 3. + <_> + + <_> + 4 7 12 8 -1. + <_> + 4 7 6 4 2. + <_> + 10 11 6 4 2. + <_> + + <_> + 8 11 8 10 -1. + <_> + 12 11 4 5 2. + <_> + 8 16 4 5 2. + <_> + + <_> + 9 1 4 9 -1. + <_> + 11 1 2 9 2. + <_> + + <_> + 14 0 3 22 -1. + <_> + 15 0 1 22 3. + <_> + + <_> + 7 0 3 22 -1. + <_> + 8 0 1 22 3. + <_> + + <_> + 4 7 18 4 -1. + <_> + 13 7 9 2 2. + <_> + 4 9 9 2 2. + <_> + + <_> + 10 2 4 15 -1. + <_> + 10 7 4 5 3. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 0 0 18 13 -1. + <_> + 9 0 9 13 2. + <_> + + <_> + 16 0 3 24 -1. + <_> + 17 0 1 24 3. + <_> + + <_> + 5 0 3 24 -1. + <_> + 6 0 1 24 3. + <_> + + <_> + 10 15 5 8 -1. + <_> + 10 19 5 4 2. + <_> + + <_> + 2 18 18 2 -1. + <_> + 2 19 18 1 2. + <_> + + <_> + 2 8 20 3 -1. + <_> + 2 9 20 1 3. + <_> + + <_> + 7 6 9 6 -1. + <_> + 7 8 9 2 3. + <_> + + <_> + 3 2 19 10 -1. + <_> + 3 7 19 5 2. + <_> + + <_> + 2 7 19 3 -1. + <_> + 2 8 19 1 3. + <_> + + <_> + 15 6 9 4 -1. + <_> + 15 8 9 2 2. + <_> + + <_> + 2 2 18 8 -1. + <_> + 8 2 6 8 3. + <_> + + <_> + 10 9 14 4 -1. + <_> + 10 9 7 4 2. + <_> + + <_> + 4 4 6 16 -1. + <_> + 7 4 3 16 2. + <_> + + <_> + 15 8 9 16 -1. + <_> + 18 8 3 16 3. + <_> + + <_> + 0 8 9 16 -1. + <_> + 3 8 3 16 3. + <_> + + <_> + 18 0 6 14 -1. + <_> + 20 0 2 14 3. + <_> + + <_> + 0 0 6 14 -1. + <_> + 2 0 2 14 3. + <_> + + <_> + 15 0 6 22 -1. + <_> + 17 0 2 22 3. + <_> + + <_> + 3 0 6 22 -1. + <_> + 5 0 2 22 3. + <_> + + <_> + 12 2 12 20 -1. + <_> + 16 2 4 20 3. + <_> + + <_> + 0 2 12 20 -1. + <_> + 4 2 4 20 3. + <_> + + <_> + 11 6 4 9 -1. + <_> + 11 6 2 9 2. + <_> + + <_> + 9 0 6 16 -1. + <_> + 12 0 3 16 2. + <_> + + <_> + 12 1 3 12 -1. + <_> + 12 7 3 6 2. + <_> + + <_> + 3 4 18 6 -1. + <_> + 3 4 9 3 2. + <_> + 12 7 9 3 2. + <_> + + <_> + 5 5 16 8 -1. + <_> + 13 5 8 4 2. + <_> + 5 9 8 4 2. + <_> + + <_> + 0 13 10 6 -1. + <_> + 0 15 10 2 3. + <_> + + <_> + 8 14 9 6 -1. + <_> + 8 16 9 2 3. + <_> + + <_> + 6 2 9 6 -1. + <_> + 9 2 3 6 3. + <_> + + <_> + 14 1 10 8 -1. + <_> + 19 1 5 4 2. + <_> + 14 5 5 4 2. + <_> + + <_> + 9 1 3 12 -1. + <_> + 9 7 3 6 2. + <_> + + <_> + 6 4 12 9 -1. + <_> + 6 7 12 3 3. + <_> + + <_> + 6 5 12 6 -1. + <_> + 10 5 4 6 3. + <_> + + <_> + 1 1 8 5 -1. + <_> + 5 1 4 5 2. + <_> + + <_> + 12 12 6 8 -1. + <_> + 12 16 6 4 2. + <_> + + <_> + 3 12 12 6 -1. + <_> + 3 14 12 2 3. + <_> + + <_> + 9 18 12 6 -1. + <_> + 15 18 6 3 2. + <_> + 9 21 6 3 2. + <_> + + <_> + 4 13 6 6 -1. + <_> + 4 16 6 3 2. + <_> + + <_> + 11 3 7 18 -1. + <_> + 11 12 7 9 2. + <_> + + <_> + 3 9 18 3 -1. + <_> + 9 9 6 3 3. + <_> + + <_> + 5 3 19 2 -1. + <_> + 5 4 19 1 2. + <_> + + <_> + 4 2 12 6 -1. + <_> + 4 2 6 3 2. + <_> + 10 5 6 3 2. + <_> + + <_> + 9 6 6 9 -1. + <_> + 11 6 2 9 3. + <_> + + <_> + 8 6 6 9 -1. + <_> + 10 6 2 9 3. + <_> + + <_> + 16 9 5 15 -1. + <_> + 16 14 5 5 3. + <_> + + <_> + 3 9 5 15 -1. + <_> + 3 14 5 5 3. + <_> + + <_> + 6 6 14 6 -1. + <_> + 13 6 7 3 2. + <_> + 6 9 7 3 2. + <_> + + <_> + 8 6 3 14 -1. + <_> + 8 13 3 7 2. + <_> + + <_> + 0 16 24 5 -1. + <_> + 8 16 8 5 3. + <_> + + <_> + 0 20 20 3 -1. + <_> + 10 20 10 3 2. + <_> + + <_> + 5 10 18 2 -1. + <_> + 5 11 18 1 2. + <_> + + <_> + 0 6 6 10 -1. + <_> + 2 6 2 10 3. + <_> + + <_> + 2 1 20 3 -1. + <_> + 2 2 20 1 3. + <_> + + <_> + 9 13 6 11 -1. + <_> + 11 13 2 11 3. + <_> + + <_> + 9 15 6 8 -1. + <_> + 9 19 6 4 2. + <_> + + <_> + 9 12 6 9 -1. + <_> + 9 15 6 3 3. + <_> + + <_> + 5 11 18 2 -1. + <_> + 5 12 18 1 2. + <_> + + <_> + 2 6 15 6 -1. + <_> + 2 8 15 2 3. + <_> + + <_> + 6 0 18 3 -1. + <_> + 6 1 18 1 3. + <_> + + <_> + 5 0 3 18 -1. + <_> + 6 0 1 18 3. + <_> + + <_> + 18 3 6 10 -1. + <_> + 20 3 2 10 3. + <_> + + <_> + 0 3 6 10 -1. + <_> + 2 3 2 10 3. + <_> + + <_> + 10 5 8 9 -1. + <_> + 10 5 4 9 2. + <_> + + <_> + 6 5 8 9 -1. + <_> + 10 5 4 9 2. + <_> + + <_> + 3 2 20 3 -1. + <_> + 3 3 20 1 3. + <_> + + <_> + 5 2 13 4 -1. + <_> + 5 4 13 2 2. + <_> + + <_> + 17 0 7 14 -1. + <_> + 17 7 7 7 2. + <_> + + <_> + 0 0 7 14 -1. + <_> + 0 7 7 7 2. + <_> + + <_> + 9 11 10 6 -1. + <_> + 9 11 5 6 2. + <_> + + <_> + 5 11 10 6 -1. + <_> + 10 11 5 6 2. + <_> + + <_> + 11 6 3 18 -1. + <_> + 11 12 3 6 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 6 16 18 3 -1. + <_> + 6 17 18 1 3. + <_> + + <_> + 4 6 9 10 -1. + <_> + 4 11 9 5 2. + <_> + + <_> + 9 7 15 4 -1. + <_> + 9 9 15 2 2. + <_> + + <_> + 5 6 12 6 -1. + <_> + 5 6 6 3 2. + <_> + 11 9 6 3 2. + <_> + + <_> + 6 1 12 9 -1. + <_> + 6 4 12 3 3. + <_> + + <_> + 7 9 6 12 -1. + <_> + 7 9 3 6 2. + <_> + 10 15 3 6 2. + <_> + + <_> + 11 5 13 6 -1. + <_> + 11 7 13 2 3. + <_> + + <_> + 1 11 22 13 -1. + <_> + 12 11 11 13 2. + <_> + + <_> + 18 8 6 6 -1. + <_> + 18 11 6 3 2. + <_> + + <_> + 0 8 6 6 -1. + <_> + 0 11 6 3 2. + <_> + + <_> + 0 6 24 3 -1. + <_> + 0 7 24 1 3. + <_> + + <_> + 0 5 10 6 -1. + <_> + 0 7 10 2 3. + <_> + + <_> + 6 7 18 3 -1. + <_> + 6 8 18 1 3. + <_> + + <_> + 0 0 10 6 -1. + <_> + 0 2 10 2 3. + <_> + + <_> + 19 0 3 19 -1. + <_> + 20 0 1 19 3. + <_> + + <_> + 4 6 12 16 -1. + <_> + 4 6 6 8 2. + <_> + 10 14 6 8 2. + <_> + + <_> + 19 6 4 18 -1. + <_> + 21 6 2 9 2. + <_> + 19 15 2 9 2. + <_> + + <_> + 1 6 4 18 -1. + <_> + 1 6 2 9 2. + <_> + 3 15 2 9 2. + <_> + + <_> + 3 21 18 3 -1. + <_> + 3 22 18 1 3. + <_> + + <_> + 0 19 9 4 -1. + <_> + 0 21 9 2 2. + <_> + + <_> + 12 18 12 6 -1. + <_> + 18 18 6 3 2. + <_> + 12 21 6 3 2. + <_> + + <_> + 7 18 9 4 -1. + <_> + 7 20 9 2 2. + <_> + + <_> + 12 16 10 8 -1. + <_> + 17 16 5 4 2. + <_> + 12 20 5 4 2. + <_> + + <_> + 2 16 10 8 -1. + <_> + 2 16 5 4 2. + <_> + 7 20 5 4 2. + <_> + + <_> + 14 0 10 12 -1. + <_> + 19 0 5 6 2. + <_> + 14 6 5 6 2. + <_> + + <_> + 0 0 10 12 -1. + <_> + 0 0 5 6 2. + <_> + 5 6 5 6 2. + <_> + + <_> + 15 14 9 6 -1. + <_> + 15 16 9 2 3. + <_> + + <_> + 0 14 9 6 -1. + <_> + 0 16 9 2 3. + <_> + + <_> + 14 14 10 6 -1. + <_> + 14 16 10 2 3. + <_> + + <_> + 0 14 10 6 -1. + <_> + 0 16 10 2 3. + <_> + + <_> + 5 18 18 2 -1. + <_> + 5 19 18 1 2. + <_> + + <_> + 0 18 18 3 -1. + <_> + 0 19 18 1 3. + <_> + + <_> + 3 5 18 12 -1. + <_> + 12 5 9 6 2. + <_> + 3 11 9 6 2. + <_> + + <_> + 5 3 7 9 -1. + <_> + 5 6 7 3 3. + <_> + + <_> + 4 0 19 15 -1. + <_> + 4 5 19 5 3. + <_> + + <_> + 3 0 16 4 -1. + <_> + 3 2 16 2 2. + <_> + + <_> + 4 12 16 12 -1. + <_> + 4 12 8 12 2. + <_> + + <_> + 4 3 12 15 -1. + <_> + 10 3 6 15 2. + <_> + + <_> + 16 4 2 19 -1. + <_> + 16 4 1 19 2. + <_> + + <_> + 6 4 2 19 -1. + <_> + 7 4 1 19 2. + <_> + + <_> + 13 14 8 10 -1. + <_> + 17 14 4 5 2. + <_> + 13 19 4 5 2. + <_> + + <_> + 3 14 8 10 -1. + <_> + 3 14 4 5 2. + <_> + 7 19 4 5 2. + <_> + + <_> + 12 6 3 18 -1. + <_> + 12 12 3 6 3. + <_> + + <_> + 5 11 12 6 -1. + <_> + 5 11 6 3 2. + <_> + 11 14 6 3 2. + <_> + + <_> + 10 5 8 10 -1. + <_> + 14 5 4 5 2. + <_> + 10 10 4 5 2. + <_> + + <_> + 6 4 12 10 -1. + <_> + 6 4 6 5 2. + <_> + 12 9 6 5 2. + <_> + + <_> + 6 8 18 10 -1. + <_> + 15 8 9 5 2. + <_> + 6 13 9 5 2. + <_> + + <_> + 0 8 18 10 -1. + <_> + 0 8 9 5 2. + <_> + 9 13 9 5 2. + <_> + + <_> + 12 6 3 18 -1. + <_> + 12 12 3 6 3. + <_> + + <_> + 0 14 18 3 -1. + <_> + 0 15 18 1 3. + <_> + + <_> + 12 6 3 18 -1. + <_> + 12 12 3 6 3. + <_> + + <_> + 9 6 3 18 -1. + <_> + 9 12 3 6 3. + <_> + + <_> + 6 14 18 3 -1. + <_> + 6 15 18 1 3. + <_> + + <_> + 0 5 18 3 -1. + <_> + 0 6 18 1 3. + <_> + + <_> + 2 5 22 3 -1. + <_> + 2 6 22 1 3. + <_> + + <_> + 0 0 21 10 -1. + <_> + 7 0 7 10 3. + <_> + + <_> + 6 3 18 17 -1. + <_> + 12 3 6 17 3. + <_> + + <_> + 0 3 18 17 -1. + <_> + 6 3 6 17 3. + <_> + + <_> + 0 12 24 11 -1. + <_> + 8 12 8 11 3. + <_> + + <_> + 4 10 16 6 -1. + <_> + 4 13 16 3 2. + <_> + + <_> + 12 8 6 8 -1. + <_> + 12 12 6 4 2. + <_> + + <_> + 6 14 8 7 -1. + <_> + 10 14 4 7 2. + <_> + + <_> + 15 10 6 14 -1. + <_> + 18 10 3 7 2. + <_> + 15 17 3 7 2. + <_> + + <_> + 3 10 6 14 -1. + <_> + 3 10 3 7 2. + <_> + 6 17 3 7 2. + <_> + + <_> + 6 12 18 2 -1. + <_> + 6 13 18 1 2. + <_> + + <_> + 5 8 10 6 -1. + <_> + 5 10 10 2 3. + <_> + + <_> + 12 11 9 4 -1. + <_> + 12 13 9 2 2. + <_> + + <_> + 0 11 9 6 -1. + <_> + 0 13 9 2 3. + <_> + + <_> + 11 2 3 18 -1. + <_> + 12 2 1 18 3. + <_> + + <_> + 10 2 3 18 -1. + <_> + 11 2 1 18 3. + <_> + + <_> + 9 12 6 10 -1. + <_> + 11 12 2 10 3. + <_> + + <_> + 1 10 6 9 -1. + <_> + 1 13 6 3 3. + <_> + + <_> + 6 9 16 6 -1. + <_> + 14 9 8 3 2. + <_> + 6 12 8 3 2. + <_> + + <_> + 1 8 9 6 -1. + <_> + 1 10 9 2 3. + <_> + + <_> + 7 7 16 6 -1. + <_> + 7 9 16 2 3. + <_> + + <_> + 0 0 18 3 -1. + <_> + 0 1 18 1 3. + <_> + + <_> + 10 0 6 9 -1. + <_> + 12 0 2 9 3. + <_> + + <_> + 9 5 6 6 -1. + <_> + 12 5 3 6 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 8 0 6 9 -1. + <_> + 10 0 2 9 3. + <_> + + <_> + 9 1 6 9 -1. + <_> + 9 4 6 3 3. + <_> + + <_> + 1 0 18 9 -1. + <_> + 1 3 18 3 3. + <_> + + <_> + 0 3 24 3 -1. + <_> + 0 4 24 1 3. + <_> + + <_> + 6 14 9 4 -1. + <_> + 6 16 9 2 2. + <_> + + <_> + 8 9 8 10 -1. + <_> + 12 9 4 5 2. + <_> + 8 14 4 5 2. + <_> + + <_> + 5 2 13 9 -1. + <_> + 5 5 13 3 3. + <_> + + <_> + 4 4 16 9 -1. + <_> + 4 7 16 3 3. + <_> + + <_> + 4 4 14 9 -1. + <_> + 4 7 14 3 3. + <_> + + <_> + 8 5 9 6 -1. + <_> + 8 7 9 2 3. + <_> + + <_> + 1 7 16 6 -1. + <_> + 1 9 16 2 3. + <_> + + <_> + 10 5 13 9 -1. + <_> + 10 8 13 3 3. + <_> + + <_> + 1 5 13 9 -1. + <_> + 1 8 13 3 3. + <_> + + <_> + 0 4 24 6 -1. + <_> + 12 4 12 3 2. + <_> + 0 7 12 3 2. + <_> + + <_> + 1 14 10 9 -1. + <_> + 1 17 10 3 3. + <_> + + <_> + 5 17 18 3 -1. + <_> + 5 18 18 1 3. + <_> + + <_> + 0 16 18 3 -1. + <_> + 0 17 18 1 3. + <_> + + <_> + 9 17 9 6 -1. + <_> + 9 19 9 2 3. + <_> + + <_> + 1 20 22 4 -1. + <_> + 1 20 11 2 2. + <_> + 12 22 11 2 2. + <_> + + <_> + 8 14 8 6 -1. + <_> + 8 17 8 3 2. + <_> + + <_> + 8 6 8 15 -1. + <_> + 8 11 8 5 3. + <_> + + <_> + 5 4 18 3 -1. + <_> + 5 5 18 1 3. + <_> + + <_> + 9 3 5 10 -1. + <_> + 9 8 5 5 2. + <_> + + <_> + 6 8 12 3 -1. + <_> + 6 8 6 3 2. + <_> + + <_> + 2 6 18 6 -1. + <_> + 2 6 9 3 2. + <_> + 11 9 9 3 2. + <_> + + <_> + 10 6 4 18 -1. + <_> + 12 6 2 9 2. + <_> + 10 15 2 9 2. + <_> + + <_> + 7 5 6 6 -1. + <_> + 10 5 3 6 2. + <_> + + <_> + 14 5 2 18 -1. + <_> + 14 14 2 9 2. + <_> + + <_> + 8 5 2 18 -1. + <_> + 8 14 2 9 2. + <_> + + <_> + 9 2 10 6 -1. + <_> + 9 2 5 6 2. + <_> + + <_> + 3 1 18 12 -1. + <_> + 12 1 9 12 2. + <_> + + <_> + 5 2 17 22 -1. + <_> + 5 13 17 11 2. + <_> + + <_> + 4 0 12 6 -1. + <_> + 4 2 12 2 3. + <_> + + <_> + 6 9 16 6 -1. + <_> + 14 9 8 3 2. + <_> + 6 12 8 3 2. + <_> + + <_> + 9 0 5 18 -1. + <_> + 9 9 5 9 2. + <_> + + <_> + 12 0 6 9 -1. + <_> + 14 0 2 9 3. + <_> + + <_> + 6 0 6 9 -1. + <_> + 8 0 2 9 3. + <_> + + <_> + 9 1 6 12 -1. + <_> + 11 1 2 12 3. + <_> + + <_> + 5 9 13 4 -1. + <_> + 5 11 13 2 2. + <_> + + <_> + 5 8 19 3 -1. + <_> + 5 9 19 1 3. + <_> + + <_> + 9 9 6 8 -1. + <_> + 9 13 6 4 2. + <_> + + <_> + 11 9 4 15 -1. + <_> + 11 14 4 5 3. + <_> + + <_> + 2 0 6 14 -1. + <_> + 2 0 3 7 2. + <_> + 5 7 3 7 2. + <_> + + <_> + 15 1 6 14 -1. + <_> + 18 1 3 7 2. + <_> + 15 8 3 7 2. + <_> + + <_> + 3 1 6 14 -1. + <_> + 3 1 3 7 2. + <_> + 6 8 3 7 2. + <_> + + <_> + 3 20 18 4 -1. + <_> + 12 20 9 2 2. + <_> + 3 22 9 2 2. + <_> + + <_> + 5 0 4 20 -1. + <_> + 5 0 2 10 2. + <_> + 7 10 2 10 2. + <_> + + <_> + 16 8 8 12 -1. + <_> + 20 8 4 6 2. + <_> + 16 14 4 6 2. + <_> + + <_> + 0 8 8 12 -1. + <_> + 0 8 4 6 2. + <_> + 4 14 4 6 2. + <_> + + <_> + 13 13 10 8 -1. + <_> + 18 13 5 4 2. + <_> + 13 17 5 4 2. + <_> + + <_> + 1 13 10 8 -1. + <_> + 1 13 5 4 2. + <_> + 6 17 5 4 2. + <_> + + <_> + 15 8 4 15 -1. + <_> + 15 13 4 5 3. + <_> + + <_> + 5 8 4 15 -1. + <_> + 5 13 4 5 3. + <_> + + <_> + 6 11 16 12 -1. + <_> + 6 15 16 4 3. + <_> + + <_> + 2 11 16 12 -1. + <_> + 2 15 16 4 3. + <_> + + <_> + 14 12 7 9 -1. + <_> + 14 15 7 3 3. + <_> + + <_> + 10 1 3 21 -1. + <_> + 10 8 3 7 3. + <_> + + <_> + 13 11 9 4 -1. + <_> + 13 13 9 2 2. + <_> + + <_> + 3 10 17 9 -1. + <_> + 3 13 17 3 3. + <_> + + <_> + 13 8 8 15 -1. + <_> + 13 13 8 5 3. + <_> + + <_> + 3 8 8 15 -1. + <_> + 3 13 8 5 3. + <_> + + <_> + 11 14 10 8 -1. + <_> + 16 14 5 4 2. + <_> + 11 18 5 4 2. + <_> + + <_> + 0 18 22 6 -1. + <_> + 0 18 11 3 2. + <_> + 11 21 11 3 2. + <_> + + <_> + 0 16 24 4 -1. + <_> + 0 16 12 4 2. + <_> + + <_> + 6 20 12 3 -1. + <_> + 12 20 6 3 2. + <_> + + <_> + 18 12 6 12 -1. + <_> + 21 12 3 6 2. + <_> + 18 18 3 6 2. + <_> + + <_> + 0 12 6 12 -1. + <_> + 0 12 3 6 2. + <_> + 3 18 3 6 2. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 1 6 22 10 -1. + <_> + 1 6 11 5 2. + <_> + 12 11 11 5 2. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 18 18 2 -1. + <_> + 0 19 18 1 2. + <_> + + <_> + 3 15 19 3 -1. + <_> + 3 16 19 1 3. + <_> + + <_> + 0 13 18 3 -1. + <_> + 0 14 18 1 3. + <_> + + <_> + 15 17 9 6 -1. + <_> + 15 19 9 2 3. + <_> + + <_> + 0 17 9 6 -1. + <_> + 0 19 9 2 3. + <_> + + <_> + 12 17 9 6 -1. + <_> + 12 19 9 2 3. + <_> + + <_> + 3 17 9 6 -1. + <_> + 3 19 9 2 3. + <_> + + <_> + 16 2 3 20 -1. + <_> + 17 2 1 20 3. + <_> + + <_> + 0 13 24 8 -1. + <_> + 0 17 24 4 2. + <_> + + <_> + 9 1 6 22 -1. + <_> + 12 1 3 11 2. + <_> + 9 12 3 11 2. + diff --git a/user_defined_operations/functions/flip.py b/user_defined_operations/functions/flip.py new file mode 100644 index 00000000..59ee4f35 --- /dev/null +++ b/user_defined_operations/functions/flip.py @@ -0,0 +1,19 @@ +import time +import cv2 + + +def run(settings, message, input_params): + ipfilename = message + format = message.strip().split(".")[-1] + + t1 = time.time() + + opfilename = settings["opfile"] + str(t1) + "." + format + + img = cv2.imread(ipfilename) + + img = cv2.flip(img, 0) + + cv2.imwrite(opfilename, img) + + return (time.time() - t1), opfilename diff --git a/user_defined_operations/requirements.txt b/user_defined_operations/requirements.txt new file mode 100644 index 00000000..5ce1a8b4 --- /dev/null +++ b/user_defined_operations/requirements.txt @@ -0,0 +1,2 @@ +opencv-python==4.5.5.64 +zmq \ No newline at end of file diff --git a/user_defined_operations/settings.json b/user_defined_operations/settings.json new file mode 100644 index 00000000..ac75f78f --- /dev/null +++ b/user_defined_operations/settings.json @@ -0,0 +1,8 @@ +{ + "opfile": "/tmp/tmp_op_file", + "port": 5555, + "functions" : { + "facedetect" : "facedetect", + "flip": "flip" + } +} \ No newline at end of file diff --git a/user_defined_operations/udf_local.py b/user_defined_operations/udf_local.py new file mode 100644 index 00000000..bc051a94 --- /dev/null +++ b/user_defined_operations/udf_local.py @@ -0,0 +1,42 @@ +import os +import json +import zmq + +for entry in os.scandir("functions"): + if entry.is_file(): + string = f"from functions import {entry.name}"[:-3] + exec(string) + +with open("settings.json", "r") as settings_file: + settings_data = settings_file.read() + +# parse file +settings = json.loads(settings_data) + +context = zmq.Context() +socket = context.socket(zmq.REP) +socket.bind("tcp://*:" + str(settings["port"])) + +# print(globals()) +i = 0 +print("Started Listening...") +while True: + message = socket.recv() + + try: + print("Received {}".format(message)) + + message_received = message.decode("utf-8") + input_params = json.loads(message_received) + + udf = globals()[settings["functions"][input_params["id"]]] + + t, opfile = udf.run(settings, input_params["ipfile"], input_params) + + print(t, i, opfile) + socket.send_string(opfile) + i += 1 + except Exception as e: + print(e.with_traceback(None)) + socket.send_string("An error occurred while running the operation.") + break diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 90da8e48..bbef6ee1 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -1,4 +1,4 @@ cmake_minimum_required (VERSION 3.10) project(vdms-utils) -include_directories(include/comm include/chrono) -add_library(vdms-utils SHARED src/comm/ConnClient.cc src/comm/Connection.cc src/comm/Exception.cc src/comm/ConnServer.cc src/chrono/Chrono.cc) +include_directories(include/comm include/chrono include/stats) +add_library(vdms-utils SHARED src/comm/ConnClient.cc src/comm/Connection.cc src/comm/Exception.cc src/comm/ConnServer.cc src/chrono/Chrono.cc src/stats/SystemStats.cc) diff --git a/utils/include/chrono/Chrono.h b/utils/include/chrono/Chrono.h index 35bf8633..098cd505 100644 --- a/utils/include/chrono/Chrono.h +++ b/utils/include/chrono/Chrono.h @@ -44,13 +44,13 @@ #endif #ifdef CHRONO_TIMING - #define CHRONO_TIC(NAME) NAME.tic(); - #define CHRONO_TAC(NAME) NAME.tac(); - #define CHRONO_PRINT_LAST_MS(NAME) NAME.printLastTime_ms(); +#define CHRONO_TIC(NAME) NAME.tic(); +#define CHRONO_TAC(NAME) NAME.tac(); +#define CHRONO_PRINT_LAST_MS(NAME) NAME.printLastTime_ms(); #else - #define CHRONO_TIC(NAME) - #define CHRONO_TAC(NAME) - #define CHRONO_PRINT_LAST_MS(NAME) +#define CHRONO_TIC(NAME) +#define CHRONO_TAC(NAME) +#define CHRONO_PRINT_LAST_MS(NAME) #endif // *************************************************************************** @@ -58,148 +58,129 @@ // *************************************************************************** class Chrono { public: - Chrono(const std::string& name, const bool asyncEnabled=false); - Chrono(); - virtual ~Chrono(void); - - void tic(void); - void tac(void); - void reset(void); - void setEnabled(const bool val); - - struct ChronoStats{ - std::string name; - uint32_t counter; - float totalTime_ms; - float totalSquaredTime_ms2; - float averageTime_ms; - float stdDevTime_ms; - float lastTime_ms; - float minTime_ms; - float maxTime_ms; - }; - - const Chrono::ChronoStats& getElapsedStats(void) const - { - return elapsedStats; - } - - const Chrono::ChronoStats& getPeriodStats(void) const - { - return periodStats; - } - - uint32_t getTotalTime_ms(void) const { - return elapsedStats.totalTime_ms; - } - - uint32_t getTotalTime_us(void) const { - return elapsedStats.totalTime_ms*1000.0f; - } - - uint32_t getLastTime_ms(void) const { - return elapsedStats.lastTime_ms; - } - - uint32_t getLastTime_us(void) const { - return elapsedStats.lastTime_ms*1000.0f; - } - - uint32_t getAvgTime_ms(void) const { - return elapsedStats.averageTime_ms; - } - - uint32_t getAvgTime_us(void) const { - return elapsedStats.averageTime_ms*1000.0f; - } - - uint32_t getSTD_ms(void) const { - return elapsedStats.stdDevTime_ms; - } - - uint32_t getSTD_us(void) const { - return elapsedStats.stdDevTime_ms*1000.0f; - } - - void printTotalTime_ms(void) const { - std::cout << name << ": " << getTotalTime_ms() - << " [ms]" << std::endl; - } - - void printTotalTime_us(void) const { - std::cout << name << ": " << getTotalTime_us() - << " [us]" << std::endl; - } - - void printLastTime_ms(void) const { - std::cout << name << ": " << getLastTime_ms() - << " [ms]" << std::endl; - } - - void printLastTime_us(void) const { - std::cout << name << ": " << getLastTime_us() - << " [us]" << std::endl; - } - - void printAvgTime_ms(void) const { - std::cout << name << ": " << getAvgTime_ms() - << " [ms]" << std::endl; - } - - void printAvgTime_us(void) const { - std::cout << name << ": " << getAvgTime_us() - << " [us]" << std::endl; - } - - std::ostream& printStats(const Chrono::ChronoStats& stats, - std::ostream& os) const; - std::ostream& printAvgTime(const Chrono::ChronoStats& stats, - std::ostream& os) const; - std::ostream& printAvgTime(const Chrono::ChronoStats& stats, - std::ostream& os, const float ref) const; + Chrono(const std::string &name, const bool asyncEnabled = false); + Chrono(); + virtual ~Chrono(void); + + void tic(void); + void tac(void); + void reset(void); + void setEnabled(const bool val); + + struct ChronoStats { + std::string name; + uint32_t counter; + float totalTime_ms; + float totalSquaredTime_ms2; + float averageTime_ms; + float stdDevTime_ms; + float lastTime_ms; + float minTime_ms; + float maxTime_ms; + }; + + const Chrono::ChronoStats &getElapsedStats(void) const { + return elapsedStats; + } + + const Chrono::ChronoStats &getPeriodStats(void) const { return periodStats; } + + uint32_t getTotalTime_ms(void) const { return elapsedStats.totalTime_ms; } + + uint32_t getTotalTime_us(void) const { + return elapsedStats.totalTime_ms * 1000.0f; + } + + uint32_t getLastTime_ms(void) const { return elapsedStats.lastTime_ms; } + + uint32_t getLastTime_us(void) const { + return elapsedStats.lastTime_ms * 1000.0f; + } + + uint32_t getAvgTime_ms(void) const { return elapsedStats.averageTime_ms; } + + uint32_t getAvgTime_us(void) const { + return elapsedStats.averageTime_ms * 1000.0f; + } + + uint32_t getSTD_ms(void) const { return elapsedStats.stdDevTime_ms; } + + uint32_t getSTD_us(void) const { + return elapsedStats.stdDevTime_ms * 1000.0f; + } + + void printTotalTime_ms(void) const { + std::cout << name << ": " << getTotalTime_ms() << " [ms]" << std::endl; + } + + void printTotalTime_us(void) const { + std::cout << name << ": " << getTotalTime_us() << " [us]" << std::endl; + } + + void printLastTime_ms(void) const { + std::cout << name << ": " << getLastTime_ms() << " [ms]" << std::endl; + } + + void printLastTime_us(void) const { + std::cout << name << ": " << getLastTime_us() << " [us]" << std::endl; + } + + void printAvgTime_ms(void) const { + std::cout << name << ": " << getAvgTime_ms() << " [ms]" << std::endl; + } + + void printAvgTime_us(void) const { + std::cout << name << ": " << getAvgTime_us() << " [us]" << std::endl; + } + + std::ostream &printStats(const Chrono::ChronoStats &stats, + std::ostream &os) const; + std::ostream &printAvgTime(const Chrono::ChronoStats &stats, + std::ostream &os) const; + std::ostream &printAvgTime(const Chrono::ChronoStats &stats, std::ostream &os, + const float ref) const; protected: - std::string name; + std::string name; - bool enabled; - bool ticIdle; - uint32_t errors; + bool enabled; + bool ticIdle; + uint32_t errors; - ChronoStats elapsedStats; - ChronoStats periodStats; + ChronoStats elapsedStats; + ChronoStats periodStats; - void resetStats(ChronoStats& stats); - void updateStats(ChronoStats& stats); + void resetStats(ChronoStats &stats); + void updateStats(ChronoStats &stats); - virtual void doTic(void) = 0; - virtual void doTac(void) = 0; + virtual void doTic(void) = 0; + virtual void doTac(void) = 0; }; - // *************************************************************************** // Chrono Cpu Implementation // *************************************************************************** class ChronoCpu : public Chrono { public: - ChronoCpu(const std::string& name); - ChronoCpu(); - ~ChronoCpu(void); + ChronoCpu(const std::string &name); + ChronoCpu(); + ~ChronoCpu(void); protected: - timespec lastTicTime; - timespec ticTime; - timespec tacTime; + timespec lastTicTime; + timespec ticTime; + timespec tacTime; #ifdef __MACH__ - clock_serv_t cclock; - mach_timespec_t mts; + clock_serv_t cclock; + mach_timespec_t mts; #endif - uint32_t ticCounter; + uint32_t ticCounter; - virtual void doTic(void); - virtual void doTac(void); + virtual void doTic(void); + virtual void doTac(void); }; -#endif // CHRONO_H_ +#endif // CHRONO_H_ diff --git a/utils/include/comm/Connection.h b/utils/include/comm/Connection.h index 957baa10..9c09d6cc 100644 --- a/utils/include/comm/Connection.h +++ b/utils/include/comm/Connection.h @@ -29,90 +29,81 @@ #pragma once -#include #include "ExceptionComm.h" +#include namespace comm { -class Connection -{ +class Connection { public: + Connection(); + Connection(int socket_fd); + ~Connection(); - Connection(); - Connection(int socket_fd); - ~Connection(); + Connection(Connection &&); - Connection(Connection &&); + Connection &operator=(Connection &&); + Connection &operator=(const Connection &) = delete; + Connection(const Connection &) = delete; - Connection& operator=(Connection &&); - Connection& operator=(const Connection &) = delete; - Connection(const Connection &) = delete; + void send_message(const uint8_t *data, uint32_t size); + const std::basic_string &recv_message(); - void send_message(const uint8_t *data, uint32_t size); - const std::basic_string& recv_message(); + void shutdown(); - void shutdown(); - - void set_buffer_size_limit(uint32_t buffer_size_limit); + void set_buffer_size_limit(uint32_t buffer_size_limit); protected: + const unsigned MAX_PORT_NUMBER = 65535; + const unsigned MAX_RETRIES = 100; - const unsigned MAX_PORT_NUMBER = 65535; - const unsigned MAX_RETRIES = 100; - const unsigned DEFAULT_BUFFER_SIZE = (32*1024*1024); - const unsigned MAX_BUFFER_SIZE = (1024*1024*1024); + const unsigned DEFAULT_BUFFER_SIZE = (32 * 1024 * 1024); + const unsigned MAX_BUFFER_SIZE = (1024 * 1024 * 1024); - std::basic_string buffer_str; + std::basic_string buffer_str; - int _socket_fd; - uint32_t _buffer_size_limit{}; + int _socket_fd; + uint32_t _buffer_size_limit{}; }; // Implements a TCP/IP server -class ConnServer -{ +class ConnServer { public: - - ConnServer(int port); - ~ConnServer(); - ConnServer& operator=(const ConnServer &) = delete; - ConnServer (const ConnServer &) = delete; - Connection accept(); + ConnServer(int port); + ~ConnServer(); + ConnServer &operator=(const ConnServer &) = delete; + ConnServer(const ConnServer &) = delete; + Connection accept(); private: + const unsigned MAX_CONN_QUEUE = 2048; + const unsigned MAX_PORT_NUMBER = 65535; - const unsigned MAX_CONN_QUEUE = 2048; - const unsigned MAX_PORT_NUMBER = 65535; - - int _port; // Server port - int _socket_fd; + int _port; // Server port + int _socket_fd; }; // Implements a TCP/IP client -class ConnClient : public Connection -{ +class ConnClient : public Connection { public: + struct ServerAddress { + std::string addr; + int port; + }; - struct ServerAddress - { - std::string addr; - int port; - }; - - ConnClient(struct ServerAddress srv); - ConnClient(std::string addr, int port); - ConnClient& operator=(const ConnClient &) = delete; - ConnClient (const ConnClient &) = delete; + ConnClient(struct ServerAddress srv); + ConnClient(std::string addr, int port); + ConnClient &operator=(const ConnClient &) = delete; + ConnClient(const ConnClient &) = delete; private: + ConnClient(); + void connect(); - ConnClient(); - void connect(); - - ServerAddress _server; + ServerAddress _server; }; -}; +}; // namespace comm diff --git a/utils/include/comm/ExceptionComm.h b/utils/include/comm/ExceptionComm.h index bbca94a2..d644721f 100644 --- a/utils/include/comm/ExceptionComm.h +++ b/utils/include/comm/ExceptionComm.h @@ -33,62 +33,51 @@ namespace comm { - enum ExceptionCommType { - FATAL_Internal_Error, +enum ExceptionCommType { + FATAL_Internal_Error, - WriteFail, // For write/send failure - ReadFail, // For read/recv failure - BindFail, // Fail to bind a port - SocketFail, - ListentFail, + WriteFail, // For write/send failure + ReadFail, // For read/recv failure + BindFail, // Fail to bind a port + SocketFail, + ListentFail, - ServerAddError, - PortError, - ConnectionError, - ConnectionShutDown, + ServerAddError, + PortError, + ConnectionError, + ConnectionShutDown, - InvalidMessageSize, - Undefined = 100,// Any undefined error - }; - - struct ExceptionComm { - // Which exception - int num; // Exception number - const char *name; // Exception name + InvalidMessageSize, + Undefined = 100, // Any undefined error +}; - // Additional information - std::string msg; - int errno_val; +struct ExceptionComm { + // Which exception + int num; // Exception number + const char *name; // Exception name - // Where it was thrown - const char *file; // Source file name - int line; // Source line number + // Additional information + std::string msg; + int errno_val; - ExceptionComm(int exc, const char *exc_name, const char *f, int l) - : num(exc), name(exc_name), - msg(), errno_val(0), - file(f), line(l) - {} + // Where it was thrown + const char *file; // Source file name + int line; // Source line number - ExceptionComm(int exc, const char *exc_name, - const std::string &m, - const char *f, int l) - : num(exc), name(exc_name), - msg(m), errno_val(0), - file(f), line(l) - {} + ExceptionComm(int exc, const char *exc_name, const char *f, int l) + : num(exc), name(exc_name), msg(), errno_val(0), file(f), line(l) {} - ExceptionComm(int exc, const char *exc_name, - int err, const std::string &m, - const char *f, int l) - : num(exc), name(exc_name), - msg(m), errno_val(err), - file(f), line(l) - {} - }; + ExceptionComm(int exc, const char *exc_name, const std::string &m, + const char *f, int l) + : num(exc), name(exc_name), msg(m), errno_val(0), file(f), line(l) {} -#define ExceptionComm(name, ...) \ - ExceptionComm(comm::name, #name, ##__VA_ARGS__, __FILE__, __LINE__) + ExceptionComm(int exc, const char *exc_name, int err, const std::string &m, + const char *f, int l) + : num(exc), name(exc_name), msg(m), errno_val(err), file(f), line(l) {} }; +#define ExceptionComm(name, ...) \ + ExceptionComm(comm::name, #name, ##__VA_ARGS__, __FILE__, __LINE__) +}; // namespace comm + extern void print_exception(const comm::ExceptionComm &e, FILE *f = stdout); diff --git a/utils/include/stats/SystemStats.h b/utils/include/stats/SystemStats.h new file mode 100644 index 00000000..902a727d --- /dev/null +++ b/utils/include/stats/SystemStats.h @@ -0,0 +1,77 @@ +/** + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#pragma once + +#include +#include +#include +#include + +#include + +// *************************************************************************** +// SystemStats class +// *************************************************************************** + +struct MemoryStats { + long long total_virtual_memory; + long long virtual_memory_used; + long long virtual_memory_process; + long long total_physical_memory; + long long physical_memory_used; + long long physical_memory_process; +}; + +struct CPUStats { + double cpu_utilized; + double cpu_utilized_process; +}; + +class SystemStats { +public: + SystemStats(); + virtual ~SystemStats(void); + + MemoryStats memoryStats; + CPUStats cpuStats; + std::string logFileName; + + void cpu_utilization_init(); + void process_cpu_utilization_init(); + + void get_system_virtual_memory(); + void get_process_virtual_memory(); + void get_system_physical_memory(); + void get_process_physical_memory(); + void get_system_cpu_utilization(); + void get_process_cpu_utilization(); + + void log_stats(std::string pName); +}; \ No newline at end of file diff --git a/utils/src/api_schema/api_schema.json b/utils/src/api_schema/api_schema.json index cafcb948..ee17bdaa 100644 --- a/utils/src/api_schema/api_schema.json +++ b/utils/src/api_schema/api_schema.json @@ -204,6 +204,9 @@ { "$ref": "#/definitions/operationCrop" }, { "$ref": "#/definitions/operationFlip" }, { "$ref": "#/definitions/operationRotate" }, + { "$ref": "#/definitions/operationUser" }, + { "$ref": "#/definitions/operationSyncRemote" }, + { "$ref": "#/definitions/operationRemote" }, { "$ref": "#/definitions/operationCustom" } ] }, @@ -218,7 +221,10 @@ { "$ref": "#/definitions/operationThreshold" }, { "$ref": "#/definitions/operationResize" }, { "$ref": "#/definitions/operationCrop" }, - { "$ref": "#/definitions/operationInterval" } + { "$ref": "#/definitions/operationInterval" }, + { "$ref": "#/definitions/operationUser" }, + { "$ref": "#/definitions/operationRemote" }, + { "$ref": "#/definitions/operationSyncRemote" } ] }, "uniqueItems": false @@ -318,6 +324,38 @@ "additionalProperties": false }, + "operationSyncRemote" : { + "type": "object", + "properties": { + "type": { "enum": [ "syncremoteOp" ] }, + "url": { "type": [ "string" ] }, + "options": { "type": [ "object" ] } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + + "operationRemote" : { + "type": "object", + "properties": { + "type": { "enum": [ "remoteOp" ] }, + "url": { "type": [ "string" ] }, + "options": { "type": [ "object" ] } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + + "operationUser" : { + "type": "object", + "properties": { + "type": { "enum": [ "userOp" ] }, + "options": { "type": [ "object" ] } + }, + "required": ["type"], + "additionalProperties": false + }, + // Shapes "shapeRectangle": { diff --git a/utils/src/api_schema/createApiString.py b/utils/src/api_schema/createApiString.py index 7527ae14..409f129f 100644 --- a/utils/src/api_schema/createApiString.py +++ b/utils/src/api_schema/createApiString.py @@ -27,17 +27,17 @@ import sys import os -with open(sys.argv[1], 'r') as schema_file: +with open(sys.argv[1], "r") as schema_file: file = schema_file.readlines() - output = open(sys.argv[2],"w") - output.write("const std::string schema_json(\" ") + output = open(sys.argv[2], "w") + output.write('const std::string schema_json(" ') for line in file: - line = line.replace('\"', '\\\"') - line = line.replace('\n', '\\\n') + line = line.replace('"', '\\"') + line = line.replace("\n", "\\\n") if not line.find("//") != -1: output.write(line) - output.write("\");\n") \ No newline at end of file + output.write('");\n') diff --git a/utils/src/chrono/Chrono.cc b/utils/src/chrono/Chrono.cc index bfcee3b5..97462f29 100644 --- a/utils/src/chrono/Chrono.cc +++ b/utils/src/chrono/Chrono.cc @@ -40,212 +40,196 @@ using namespace std; // ***************************************************************************** // Public methods definitions // ***************************************************************************** -Chrono::Chrono(const string& name, const bool asyncEnabled) : - name (name) - ,enabled (true) -{ - elapsedStats.name = "elapsedStats"; - periodStats.name = "periodStats"; - reset(); +Chrono::Chrono(const string &name, const bool asyncEnabled) + : name(name), enabled(true) { + elapsedStats.name = "elapsedStats"; + periodStats.name = "periodStats"; + reset(); } -Chrono::Chrono() : Chrono("no_name") -{ -} +Chrono::Chrono() : Chrono("no_name") {} -Chrono::~Chrono(void) -{ -} +Chrono::~Chrono(void) {} -void Chrono::tic(void) -{ - if (!enabled){ - return; - } - - if (ticIdle){ - ticIdle = false; - doTic(); - } else{ - ++errors; - cerr << "Chrono::tic - " << name << ": Calling Chrono::tic with no matching Chrono::tag!" << endl; - } -} +void Chrono::tic(void) { + if (!enabled) { + return; + } -void Chrono::tac(void) -{ - if (!enabled){ - return; - } - - if (!ticIdle){ - ticIdle = true; - doTac(); - } else{ - ++errors; - cerr << "Chrono::tac - " << name << ": Calling Chrono::tac with no matching Chrono::tic!" << endl; - } + if (ticIdle) { + ticIdle = false; + doTic(); + } else { + ++errors; + cerr << "Chrono::tic - " << name + << ": Calling Chrono::tic with no matching Chrono::tag!" << endl; + } } -void Chrono::reset(void) -{ - ticIdle = true; - errors = 0; - resetStats(elapsedStats); - resetStats(periodStats); +void Chrono::tac(void) { + if (!enabled) { + return; + } + + if (!ticIdle) { + ticIdle = true; + doTac(); + } else { + ++errors; + cerr << "Chrono::tac - " << name + << ": Calling Chrono::tac with no matching Chrono::tic!" << endl; + } } -void Chrono::setEnabled(const bool val) -{ - enabled = val; +void Chrono::reset(void) { + ticIdle = true; + errors = 0; + resetStats(elapsedStats); + resetStats(periodStats); } -std::ostream& Chrono::printStats(const Chrono::ChronoStats& stats, std::ostream& os) const -{ - os.precision(2); - os << fixed; - os << name << ": " << stats.name << endl; - os << "\terrors: " << errors << endl; - os << "\ttotalTime: " << stats.totalTime_ms << " [ms]" << endl; - os << "\taverageTime: " << stats.averageTime_ms << " [ms]" << endl; - os << "\tstdDevTime: " << stats.stdDevTime_ms << " [ms]" << endl; - os << "\tlastTime: " << stats.lastTime_ms << " [ms]" << endl; - os << "\tminTime: " << stats.minTime_ms << " [ms]" << endl; - os << "\tmaxTime: " << stats.maxTime_ms << " [ms]" << endl; - - return os; +void Chrono::setEnabled(const bool val) { enabled = val; } + +std::ostream &Chrono::printStats(const Chrono::ChronoStats &stats, + std::ostream &os) const { + os.precision(2); + os << fixed; + os << name << ": " << stats.name << endl; + os << "\terrors: " << errors << endl; + os << "\ttotalTime: " << stats.totalTime_ms << " [ms]" << endl; + os << "\taverageTime: " << stats.averageTime_ms << " [ms]" << endl; + os << "\tstdDevTime: " << stats.stdDevTime_ms << " [ms]" << endl; + os << "\tlastTime: " << stats.lastTime_ms << " [ms]" << endl; + os << "\tminTime: " << stats.minTime_ms << " [ms]" << endl; + os << "\tmaxTime: " << stats.maxTime_ms << " [ms]" << endl; + + return os; } -std::ostream& Chrono::printAvgTime(const Chrono::ChronoStats& stats, std::ostream& os) const -{ - os.precision(2); - os << fixed; - os << name << ": " << stats.name << " -> " << "averageTime: " << stats.averageTime_ms << " [ms]" << endl; +std::ostream &Chrono::printAvgTime(const Chrono::ChronoStats &stats, + std::ostream &os) const { + os.precision(2); + os << fixed; + os << name << ": " << stats.name << " -> " + << "averageTime: " << stats.averageTime_ms << " [ms]" << endl; - return os; + return os; } -std::ostream& Chrono::printAvgTime(const Chrono::ChronoStats& stats, std::ostream& os, const float ref) const -{ - os.precision(2); - os << fixed; - os << name << ": " << stats.name << " -> " << "averageTime: " << stats.averageTime_ms << " [ms] ("; - os << (stats.averageTime_ms/ref*100.0f) << "%)" << endl; +std::ostream &Chrono::printAvgTime(const Chrono::ChronoStats &stats, + std::ostream &os, const float ref) const { + os.precision(2); + os << fixed; + os << name << ": " << stats.name << " -> " + << "averageTime: " << stats.averageTime_ms << " [ms] ("; + os << (stats.averageTime_ms / ref * 100.0f) << "%)" << endl; - return os; + return os; } // ***************************************************************************** // Private/Protected methods definitions // ***************************************************************************** -void Chrono::resetStats(ChronoStats& stats) -{ - stats.counter = 0; - stats.totalTime_ms = 0.0f; - stats.totalSquaredTime_ms2 = 0.0f; - stats.averageTime_ms = 0.0f; - stats.stdDevTime_ms = 0.0f; - stats.lastTime_ms = 0.0f; - stats.minTime_ms = 0.0f; - stats.maxTime_ms = 0.0f; -} - -void Chrono::updateStats(ChronoStats& stats) -{ - ++stats.counter; - stats.totalTime_ms += stats.lastTime_ms; - stats.totalSquaredTime_ms2 += stats.lastTime_ms * stats.lastTime_ms; - stats.averageTime_ms = stats.totalTime_ms / (float)stats.counter; - stats.stdDevTime_ms = sqrtf(stats.totalSquaredTime_ms2 / (float)stats.counter - stats.averageTime_ms * stats.averageTime_ms); - if (stats.counter > 1){ - stats.maxTime_ms = max(stats.lastTime_ms, stats.maxTime_ms); - stats.minTime_ms = min(stats.lastTime_ms, stats.minTime_ms); - } else{ - stats.maxTime_ms = stats.lastTime_ms; - stats.minTime_ms = stats.lastTime_ms; - } +void Chrono::resetStats(ChronoStats &stats) { + stats.counter = 0; + stats.totalTime_ms = 0.0f; + stats.totalSquaredTime_ms2 = 0.0f; + stats.averageTime_ms = 0.0f; + stats.stdDevTime_ms = 0.0f; + stats.lastTime_ms = 0.0f; + stats.minTime_ms = 0.0f; + stats.maxTime_ms = 0.0f; +} + +void Chrono::updateStats(ChronoStats &stats) { + ++stats.counter; + stats.totalTime_ms += stats.lastTime_ms; + stats.totalSquaredTime_ms2 += stats.lastTime_ms * stats.lastTime_ms; + stats.averageTime_ms = stats.totalTime_ms / (float)stats.counter; + stats.stdDevTime_ms = + sqrtf(stats.totalSquaredTime_ms2 / (float)stats.counter - + stats.averageTime_ms * stats.averageTime_ms); + if (stats.counter > 1) { + stats.maxTime_ms = max(stats.lastTime_ms, stats.maxTime_ms); + stats.minTime_ms = min(stats.lastTime_ms, stats.minTime_ms); + } else { + stats.maxTime_ms = stats.lastTime_ms; + stats.minTime_ms = stats.lastTime_ms; + } } // ***************************************************************************** // ChronoCpu Implementation // ***************************************************************************** -ChronoCpu::ChronoCpu(const string& name) : - Chrono (name) - ,ticCounter (0) -{ - memset((void*)&lastTicTime, 0, sizeof(lastTicTime)); - memset((void*)&ticTime, 0, sizeof(ticTime)); - memset((void*)&tacTime, 0, sizeof(tacTime)); +ChronoCpu::ChronoCpu(const string &name) : Chrono(name), ticCounter(0) { + memset((void *)&lastTicTime, 0, sizeof(lastTicTime)); + memset((void *)&ticTime, 0, sizeof(ticTime)); + memset((void *)&tacTime, 0, sizeof(tacTime)); #ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); #endif } -ChronoCpu::~ChronoCpu(void) -{ +ChronoCpu::~ChronoCpu(void) { #ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time - mach_port_deallocate(mach_task_self(), cclock); + mach_port_deallocate(mach_task_self(), cclock); #endif } -ChronoCpu::ChronoCpu() : ChronoCpu("no_name") -{ -} - +ChronoCpu::ChronoCpu() : ChronoCpu("no_name") {} // ***************************************************************************** // Private/Protected methods definitions // ***************************************************************************** -void ChronoCpu::doTic(void) -{ - lastTicTime = ticTime; +void ChronoCpu::doTic(void) { + lastTicTime = ticTime; #ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time - clock_get_time(cclock, &mts); - ticTime.tv_sec = mts.tv_sec; - ticTime.tv_nsec = mts.tv_nsec; + clock_get_time(cclock, &mts); + ticTime.tv_sec = mts.tv_sec; + ticTime.tv_nsec = mts.tv_nsec; #else - if (clock_gettime(CLOCK_REALTIME, &ticTime) != 0){ - ++errors; - cerr << "ChronoCpu::doTic - " << name << ": clock_gettime() failed!" << endl; - return; - } + if (clock_gettime(CLOCK_REALTIME, &ticTime) != 0) { + ++errors; + cerr << "ChronoCpu::doTic - " << name << ": clock_gettime() failed!" + << endl; + return; + } #endif - ++ticCounter; + ++ticCounter; - if (ticCounter > 1){ - float period_s = (float)(ticTime.tv_sec - lastTicTime.tv_sec); - float period_ns = (float)(ticTime.tv_nsec - lastTicTime.tv_nsec); - periodStats.lastTime_ms = period_s * 1e3f + period_ns / 1e6f; - updateStats(periodStats); - } + if (ticCounter > 1) { + float period_s = (float)(ticTime.tv_sec - lastTicTime.tv_sec); + float period_ns = (float)(ticTime.tv_nsec - lastTicTime.tv_nsec); + periodStats.lastTime_ms = period_s * 1e3f + period_ns / 1e6f; + updateStats(periodStats); + } } -void ChronoCpu::doTac(void) -{ +void ChronoCpu::doTac(void) { #ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - tacTime.tv_sec = mts.tv_sec; - tacTime.tv_nsec = mts.tv_nsec; + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + tacTime.tv_sec = mts.tv_sec; + tacTime.tv_nsec = mts.tv_nsec; #else - if (clock_gettime(CLOCK_REALTIME, &tacTime) != 0){ - ++errors; - cerr << "ChronoCpu::doTac - " << name << ": clock_gettime() failed!" << endl; - return; - } + if (clock_gettime(CLOCK_REALTIME, &tacTime) != 0) { + ++errors; + cerr << "ChronoCpu::doTac - " << name << ": clock_gettime() failed!" + << endl; + return; + } #endif - float elapsed_s = (float)(tacTime.tv_sec - ticTime.tv_sec); - float elapsed_ns = (float)(tacTime.tv_nsec - ticTime.tv_nsec); - elapsedStats.lastTime_ms = elapsed_s * 1e3f + elapsed_ns / 1e6f; - updateStats(elapsedStats); + float elapsed_s = (float)(tacTime.tv_sec - ticTime.tv_sec); + float elapsed_ns = (float)(tacTime.tv_nsec - ticTime.tv_nsec); + elapsedStats.lastTime_ms = elapsed_s * 1e3f + elapsed_ns / 1e6f; + updateStats(elapsedStats); } - diff --git a/utils/src/comm/ConnClient.cc b/utils/src/comm/ConnClient.cc index 57b6f0da..91258e6a 100644 --- a/utils/src/comm/ConnClient.cc +++ b/utils/src/comm/ConnClient.cc @@ -27,10 +27,10 @@ * */ -#include +#include #include +#include #include -#include #include @@ -38,56 +38,49 @@ using namespace comm; -ConnClient::ConnClient() -{ +ConnClient::ConnClient() { _server.port = 0; - //create TCP/IP socket - _socket_fd = socket(AF_INET, SOCK_STREAM, 0); + // create TCP/IP socket + _socket_fd = socket(AF_INET, SOCK_STREAM, 0); - if (_socket_fd < 0) { - throw ExceptionComm(SocketFail); - } + if (_socket_fd < 0) { + throw ExceptionComm(SocketFail); + } - int option = 1; // To set REUSEADDR to true - if (setsockopt(_socket_fd, SOL_SOCKET, - SO_REUSEADDR, &option, sizeof option) == -1) { - throw ExceptionComm(SocketFail); - } + int option = 1; // To set REUSEADDR to true + if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, &option, + sizeof option) == -1) { + throw ExceptionComm(SocketFail); + } } -ConnClient::ConnClient(ServerAddress srv) : - ConnClient(srv.addr, srv.port) -{ -} +ConnClient::ConnClient(ServerAddress srv) : ConnClient(srv.addr, srv.port) {} -ConnClient::ConnClient(std::string addr, int port) : ConnClient() -{ - if (port > MAX_PORT_NUMBER || port <= 0) { - throw ExceptionComm(PortError); - } +ConnClient::ConnClient(std::string addr, int port) : ConnClient() { + if (port > MAX_PORT_NUMBER || port <= 0) { + throw ExceptionComm(PortError); + } - _server.addr = addr; - _server.port = port; - connect(); + _server.addr = addr; + _server.port = port; + connect(); } -void ConnClient::connect() -{ - struct hostent *server = gethostbyname(_server.addr.c_str()); +void ConnClient::connect() { + struct hostent *server = gethostbyname(_server.addr.c_str()); - if (server == NULL) { - throw ExceptionComm(ServerAddError); - } + if (server == NULL) { + throw ExceptionComm(ServerAddError); + } - struct sockaddr_in svrAddr; - memset(&svrAddr, 0, sizeof(svrAddr)); - svrAddr.sin_family = AF_INET; + struct sockaddr_in svrAddr; + memset(&svrAddr, 0, sizeof(svrAddr)); + svrAddr.sin_family = AF_INET; - memcpy(&svrAddr.sin_addr.s_addr, server->h_addr, server->h_length); - svrAddr.sin_port = htons(_server.port); + memcpy(&svrAddr.sin_addr.s_addr, server->h_addr, server->h_length); + svrAddr.sin_port = htons(_server.port); - if (::connect(_socket_fd,(struct sockaddr *) &svrAddr, - sizeof(svrAddr)) < 0) { - throw ExceptionComm(ConnectionError); - } + if (::connect(_socket_fd, (struct sockaddr *)&svrAddr, sizeof(svrAddr)) < 0) { + throw ExceptionComm(ConnectionError); + } } diff --git a/utils/src/comm/ConnServer.cc b/utils/src/comm/ConnServer.cc index 7d0efd7a..71150bac 100644 --- a/utils/src/comm/ConnServer.cc +++ b/utils/src/comm/ConnServer.cc @@ -27,10 +27,10 @@ * */ -#include +#include #include +#include #include -#include #include @@ -38,66 +38,59 @@ using namespace comm; -ConnServer::ConnServer(int port): - _port(port) -{ - if (_port > MAX_PORT_NUMBER || _port <= 0 ) { - throw ExceptionComm(PortError); - } - - int ret; - - //create TCP/IP socket - _socket_fd = socket(AF_INET, SOCK_STREAM, 0); - - if (_socket_fd < 0) { - throw ExceptionComm(SocketFail); - } - - int option = 1; // To set REUSEADDR to true - ret = setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, - &option, sizeof(option)); - if (ret < 0) { - throw ExceptionComm(SocketFail); - } - - struct sockaddr_in svr_addr; - memset((char*) &svr_addr,0, sizeof(svr_addr)); - svr_addr.sin_family = AF_INET; - svr_addr.sin_addr.s_addr = INADDR_ANY; - svr_addr.sin_port = htons(_port); - - // bind socket : "assigning a name to a socket" - ret = ::bind(_socket_fd, (struct sockaddr *)&svr_addr, sizeof(svr_addr)); - if (ret < 0) { - throw ExceptionComm(BindFail); - } - - //mark socket as pasive - if (::listen(_socket_fd, MAX_CONN_QUEUE) == -1) { - throw ExceptionComm(ListentFail); - } +ConnServer::ConnServer(int port) : _port(port) { + if (_port > MAX_PORT_NUMBER || _port <= 0) { + throw ExceptionComm(PortError); + } + + int ret; + + // create TCP/IP socket + _socket_fd = socket(AF_INET, SOCK_STREAM, 0); + + if (_socket_fd < 0) { + throw ExceptionComm(SocketFail); + } + + int option = 1; // To set REUSEADDR to true + ret = + setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); + if (ret < 0) { + throw ExceptionComm(SocketFail); + } + + struct sockaddr_in svr_addr; + memset((char *)&svr_addr, 0, sizeof(svr_addr)); + svr_addr.sin_family = AF_INET; + svr_addr.sin_addr.s_addr = INADDR_ANY; + svr_addr.sin_port = htons(_port); + + // bind socket : "assigning a name to a socket" + ret = ::bind(_socket_fd, (struct sockaddr *)&svr_addr, sizeof(svr_addr)); + if (ret < 0) { + throw ExceptionComm(BindFail); + } + + // mark socket as pasive + if (::listen(_socket_fd, MAX_CONN_QUEUE) == -1) { + throw ExceptionComm(ListentFail); + } } -ConnServer::~ConnServer() -{ - ::close(_socket_fd); -} +ConnServer::~ConnServer() { ::close(_socket_fd); } -Connection ConnServer::accept() -{ - struct sockaddr_in clnt_addr; - socklen_t len = sizeof(clnt_addr); //store size of the address +Connection ConnServer::accept() { + struct sockaddr_in clnt_addr; + socklen_t len = sizeof(clnt_addr); // store size of the address - // This is where client connects. - // Server will stall here until incoming connection - // unless the socket is marked and nonblocking - int connfd = ::accept(_socket_fd, (struct sockaddr *)&clnt_addr, &len); + // This is where client connects. + // Server will stall here until incoming connection + // unless the socket is marked and nonblocking + int connfd = ::accept(_socket_fd, (struct sockaddr *)&clnt_addr, &len); - if (connfd < 0) { - throw ExceptionComm(ConnectionError); - } + if (connfd < 0) { + throw ExceptionComm(ConnectionError); + } - return Connection(connfd); + return Connection(connfd); } - diff --git a/utils/src/comm/Connection.cc b/utils/src/comm/Connection.cc index b1533ffc..5c3882c0 100644 --- a/utils/src/comm/Connection.cc +++ b/utils/src/comm/Connection.cc @@ -27,10 +27,10 @@ * */ +#include +#include #include #include -#include -#include #include @@ -38,132 +38,116 @@ using namespace comm; -Connection::Connection(): - _socket_fd(-1), _buffer_size_limit(DEFAULT_BUFFER_SIZE) -{ -} +Connection::Connection() + : _socket_fd(-1), _buffer_size_limit(DEFAULT_BUFFER_SIZE) {} -Connection::Connection(int socket_fd): - _socket_fd(socket_fd), _buffer_size_limit(DEFAULT_BUFFER_SIZE) -{ -} +Connection::Connection(int socket_fd) + : _socket_fd(socket_fd), _buffer_size_limit(DEFAULT_BUFFER_SIZE) {} -Connection::Connection(Connection &&c): - _buffer_size_limit(DEFAULT_BUFFER_SIZE) -{ - _socket_fd = c._socket_fd; - c._socket_fd = -1; +Connection::Connection(Connection &&c) + : _buffer_size_limit(DEFAULT_BUFFER_SIZE) { + _socket_fd = c._socket_fd; + c._socket_fd = -1; } -Connection& Connection::operator=(Connection &&c) -{ - _socket_fd = c._socket_fd; - c._socket_fd = -1; - return *this; +Connection &Connection::operator=(Connection &&c) { + _socket_fd = c._socket_fd; + c._socket_fd = -1; + return *this; } -Connection::~Connection() -{ - if (_socket_fd != -1) { - ::close(_socket_fd); - _socket_fd = -1; - } +Connection::~Connection() { + if (_socket_fd != -1) { + ::close(_socket_fd); + _socket_fd = -1; + } } -void Connection::shutdown() -{ - ::shutdown(_socket_fd, SHUT_RDWR); -} +void Connection::shutdown() { ::shutdown(_socket_fd, SHUT_RDWR); } -void Connection::set_buffer_size_limit(uint32_t buffer_size_limit) -{ - _buffer_size_limit = std::min(MAX_BUFFER_SIZE, std::max(DEFAULT_BUFFER_SIZE, buffer_size_limit)); +void Connection::set_buffer_size_limit(uint32_t buffer_size_limit) { + _buffer_size_limit = std::min( + MAX_BUFFER_SIZE, std::max(DEFAULT_BUFFER_SIZE, buffer_size_limit)); } -void Connection::send_message(const uint8_t *data, uint32_t size) -{ - if (size > MAX_BUFFER_SIZE) { - throw ExceptionComm(InvalidMessageSize); - } - else if (size > _buffer_size_limit) { - set_buffer_size_limit(size); - } +void Connection::send_message(const uint8_t *data, uint32_t size) { + if (size > MAX_BUFFER_SIZE) { + throw ExceptionComm(InvalidMessageSize); + } else if (size > _buffer_size_limit) { + set_buffer_size_limit(size); + } - // We need MSG_NOSIGNAL so we don't get SIGPIPE, and we can throw. - int ret = ::send(_socket_fd, (const char*)&size, sizeof(size), MSG_NOSIGNAL); + // We need MSG_NOSIGNAL so we don't get SIGPIPE, and we can throw. + int ret = ::send(_socket_fd, (const char *)&size, sizeof(size), MSG_NOSIGNAL); - if (ret != sizeof(size)) { - throw ExceptionComm(WriteFail); - } + if (ret != sizeof(size)) { + throw ExceptionComm(WriteFail); + } - int bytes_sent = 0; - while (bytes_sent < size) { - // We need MSG_NOSIGNAL so we don't get SIGPIPE, and we can throw. - int ret = ::send(_socket_fd, - (const char*)data + bytes_sent, - size - bytes_sent, MSG_NOSIGNAL); - if (ret < 0) { - throw ExceptionComm(WriteFail); - } - - bytes_sent += ret; + int bytes_sent = 0; + while (bytes_sent < size) { + // We need MSG_NOSIGNAL so we don't get SIGPIPE, and we can throw. + int ret = ::send(_socket_fd, (const char *)data + bytes_sent, + size - bytes_sent, MSG_NOSIGNAL); + if (ret < 0) { + throw ExceptionComm(WriteFail); } -} -const std::basic_string& Connection::recv_message() -{ - uint32_t recv_message_size; + bytes_sent += ret; + } +} - auto recv_and_check = [this](void* buffer, uint32_t size, int flags) - { - size_t bytes_recv = 0; +const std::basic_string &Connection::recv_message() { + uint32_t recv_message_size; - while (bytes_recv < size) { + auto recv_and_check = [this](void *buffer, uint32_t size, int flags) { + size_t bytes_recv = 0; - int ret = ::recv(_socket_fd, (void*)((char*)buffer + bytes_recv), - size - bytes_recv, flags); + while (bytes_recv < size) { - if (ret < 0) { - throw ExceptionComm(ReadFail); - } - // When a stream socket peer has performed an orderly shutdown, the - // return value will be 0 (the traditional "end-of-file" return). - else if (ret == 0) { - throw ExceptionComm(ConnectionShutDown); - } + int ret = ::recv(_socket_fd, (void *)((char *)buffer + bytes_recv), + size - bytes_recv, flags); - bytes_recv += ret; - } + if (ret < 0) { + throw ExceptionComm(ReadFail); + } + // When a stream socket peer has performed an orderly shutdown, the + // return value will be 0 (the traditional "end-of-file" return). + else if (ret == 0) { + throw ExceptionComm(ConnectionShutDown); + } + + bytes_recv += ret; + } - return bytes_recv; - }; + return bytes_recv; + }; - size_t bytes_recv = recv_and_check(&recv_message_size, sizeof(uint32_t), - MSG_WAITALL); + size_t bytes_recv = + recv_and_check(&recv_message_size, sizeof(uint32_t), MSG_WAITALL); - if (bytes_recv != sizeof(recv_message_size)) { - throw ExceptionComm(ReadFail); - } + if (bytes_recv != sizeof(recv_message_size)) { + throw ExceptionComm(ReadFail); + } - if (recv_message_size > MAX_BUFFER_SIZE) { - throw ExceptionComm(InvalidMessageSize); - } - else if (recv_message_size > _buffer_size_limit) { - set_buffer_size_limit(recv_message_size); - } + if (recv_message_size > MAX_BUFFER_SIZE) { + throw ExceptionComm(InvalidMessageSize); + } else if (recv_message_size > _buffer_size_limit) { + set_buffer_size_limit(recv_message_size); + } - buffer_str.resize(recv_message_size); + buffer_str.resize(recv_message_size); - uint8_t *buffer = (uint8_t*) buffer_str.data(); - bytes_recv = recv_and_check(buffer, recv_message_size, MSG_WAITALL); + uint8_t *buffer = (uint8_t *)buffer_str.data(); + bytes_recv = recv_and_check(buffer, recv_message_size, MSG_WAITALL); - if (recv_message_size != bytes_recv) { - throw ExceptionComm(ReadFail); - } + if (recv_message_size != bytes_recv) { + throw ExceptionComm(ReadFail); + } - if (recv_message_size != buffer_str.size()) { - throw ExceptionComm(ReadFail); - } + if (recv_message_size != buffer_str.size()) { + throw ExceptionComm(ReadFail); + } - return buffer_str; + return buffer_str; } diff --git a/utils/src/comm/Exception.cc b/utils/src/comm/Exception.cc index d6f96c4e..08550eed 100644 --- a/utils/src/comm/Exception.cc +++ b/utils/src/comm/Exception.cc @@ -32,11 +32,10 @@ #include "Connection.h" -void print_exception(const comm::ExceptionComm &e, FILE *f) -{ - fprintf(f, "[Exception] %s at %s:%d\n", e.name, e.file, e.line); - if (e.errno_val != 0) - fprintf(f, "%s: %s\n", e.msg.c_str(), strerror(e.errno_val)); - else if (!e.msg.empty()) - fprintf(f, "%s\n", e.msg.c_str()); +void print_exception(const comm::ExceptionComm &e, FILE *f) { + fprintf(f, "[Exception] %s at %s:%d\n", e.name, e.file, e.line); + if (e.errno_val != 0) + fprintf(f, "%s: %s\n", e.msg.c_str(), strerror(e.errno_val)); + else if (!e.msg.empty()) + fprintf(f, "%s\n", e.msg.c_str()); } diff --git a/utils/src/stats/SystemStats.cc b/utils/src/stats/SystemStats.cc new file mode 100644 index 00000000..33fc4ea0 --- /dev/null +++ b/utils/src/stats/SystemStats.cc @@ -0,0 +1,306 @@ +/** + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "sys/sysinfo.h" +#include "sys/times.h" +#include "sys/types.h" +#include "sys/vtimes.h" + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" + +#include +#include +#include + +#include "SystemStats.h" + +using namespace std; + +static unsigned long long lastTotalUser, lastTotalUserLow, lastTotalSys, + lastTotalIdle; +static clock_t lastCPU, lastSysCPU, lastUserCPU; +static int numProcessors; + +// ***************************************************************************** +// Public methods definitions +// ***************************************************************************** + +SystemStats::SystemStats() { + memoryStats = { + 0, 0, 0, 0, 0, 0, + }; + + cpuStats = { + 0.0, + 0.0, + }; + + auto time_now = std::chrono::system_clock::now(); + std::chrono::duration utc_time = time_now.time_since_epoch(); + + logFileName = "/tmp/vdms_system_stats_" + std::to_string(utc_time.count()); + + process_cpu_utilization_init(); + cpu_utilization_init(); +} + +SystemStats::~SystemStats(void) {} + +// ***************************************************************************** +// Memory Statistics +// ***************************************************************************** + +void SystemStats::get_system_virtual_memory() { + struct sysinfo memoryInfo; + sysinfo(&memoryInfo); + + long long totalVirtualMemory = memoryInfo.totalram; + + totalVirtualMemory += memoryInfo.totalswap; + totalVirtualMemory *= memoryInfo.mem_unit; + + long long virtualMemoryUsed = memoryInfo.totalram - memoryInfo.freeram; + + virtualMemoryUsed += memoryInfo.totalswap - memoryInfo.freeswap; + virtualMemoryUsed *= memoryInfo.mem_unit; + + memoryStats.total_virtual_memory = totalVirtualMemory; + memoryStats.virtual_memory_used = virtualMemoryUsed; +} + +int parseLine(char *line) { + int i = strlen(line); + const char *p = line; + while (*p < '0' || *p > '9') + p++; + line[i - 3] = '\0'; + i = atoi(p); + return i; +} + +void SystemStats::get_process_virtual_memory() { + FILE *file = fopen("/proc/self/status", "r"); + int virtualMemoryProcess = -1; + char line[128]; + + if (file != NULL) { + while (fgets(line, 128, file) != NULL) { + if (strncmp(line, "VmSize:", 7) == 0) { + virtualMemoryProcess = parseLine(line); + break; + } + } + fclose(file); + } + + memoryStats.virtual_memory_process = virtualMemoryProcess; +} + +void SystemStats::get_system_physical_memory() { + struct sysinfo memoryInfo; + sysinfo(&memoryInfo); + + long long totalPhysicalMemory = memoryInfo.totalram; + totalPhysicalMemory *= memoryInfo.mem_unit; + + long long physicalMemoryUsed = memoryInfo.totalram - memoryInfo.freeram; + physicalMemoryUsed *= memoryInfo.mem_unit; + + memoryStats.total_physical_memory = totalPhysicalMemory; + memoryStats.physical_memory_used = physicalMemoryUsed; +} + +void SystemStats::get_process_physical_memory() { + FILE *file = fopen("/proc/self/status", "r"); + int physicalMemoryProcess = -1; + char line[128]; + + if (file != NULL) { + while (fgets(line, 128, file) != NULL) { + if (strncmp(line, "VmRSS:", 6) == 0) { + physicalMemoryProcess = parseLine(line); + break; + } + } + fclose(file); + } + + memoryStats.physical_memory_process = physicalMemoryProcess; +} + +// ***************************************************************************** +// CPU Statistics +// ***************************************************************************** + +void SystemStats::cpu_utilization_init() { + FILE *file = fopen("/proc/stat", "r"); + if (file != NULL) { + if (fscanf(file, "cpu %llu %llu %llu %llu", &lastTotalUser, + &lastTotalUserLow, &lastTotalSys, &lastTotalIdle) != 4) { + printf("Error reading /proc/stats\n"); + } + fclose(file); + } +} + +void SystemStats::process_cpu_utilization_init() { + FILE *file; + struct tms timeSample; + char line[128]; + + lastCPU = times(&timeSample); + lastSysCPU = timeSample.tms_stime; + lastUserCPU = timeSample.tms_utime; + + file = fopen("/proc/cpuinfo", "r"); + numProcessors = 0; + if (file != NULL) { + while (fgets(line, 128, file) != NULL) { + if (strncmp(line, "processor", 9) == 0) + numProcessors++; + } + fclose(file); + } +} + +void SystemStats::get_system_cpu_utilization() { + double cpuUtilization; + FILE *file; + unsigned long long totalUser, totalUserLow, totalSys, totalIdle, total; + + file = fopen("/proc/stat", "r"); + + if (file != NULL) { + if (fscanf(file, "cpu %llu %llu %llu %llu", &totalUser, &totalUserLow, + &totalSys, &totalIdle) != 4) { + printf("Error reading /proc/stats\n"); + } + fclose(file); + + if (totalUser < lastTotalUser || totalUserLow < lastTotalUserLow || + totalSys < lastTotalSys || totalIdle < lastTotalIdle) { + // Overflow detection. Just skip this value. + cpuUtilization = -1.0; + } else { + total = (totalUser - lastTotalUser) + (totalUserLow - lastTotalUserLow) + + (totalSys - lastTotalSys); + cpuUtilization = total; + total += (totalIdle - lastTotalIdle); + if (total != 0) { + cpuUtilization /= total; + cpuUtilization *= 100; + } else { + cpuUtilization = -1.0; + } + } + + lastTotalUser = totalUser; + lastTotalUserLow = totalUserLow; + lastTotalSys = totalSys; + lastTotalIdle = totalIdle; + } else { + cpuUtilization = -1.0; + } + + cpuStats.cpu_utilized = cpuUtilization; +} + +void SystemStats::get_process_cpu_utilization() { + struct tms timeSample; + clock_t now; + double cpuUtilization; + + now = times(&timeSample); + if (now <= lastCPU || timeSample.tms_stime < lastSysCPU || + timeSample.tms_utime < lastUserCPU) { + // Overflow detection. Just skip this value. + cpuUtilization = -1.0; + } else { + cpuUtilization = (timeSample.tms_stime - lastSysCPU) + + (timeSample.tms_utime - lastUserCPU); + // std::cout<< "Utilization Debug: " << cpuUtilization << " " << + // timeSample.tms_stime << " " << lastSysCPU << " " << timeSample.tms_utime + // << " " << lastUserCPU << " " << now << " " << lastCPU << std::endl; + cpuUtilization /= (now - lastCPU); + cpuUtilization /= numProcessors; + cpuUtilization *= 100; + } + lastCPU = now; + lastSysCPU = timeSample.tms_stime; + lastUserCPU = timeSample.tms_utime; + + cpuStats.cpu_utilized_process = cpuUtilization; +} + +// ***************************************************************************** +// Logging Functions +// ***************************************************************************** + +void SystemStats::log_stats(std::string pname) { + get_system_virtual_memory(); + get_process_virtual_memory(); + get_system_physical_memory(); + get_process_physical_memory(); + get_system_cpu_utilization(); + get_process_cpu_utilization(); + + std::ofstream statsFile; + + statsFile.open(logFileName.data(), std::ios_base::app); + + auto time_now = std::chrono::system_clock::now(); + std::chrono::duration utc_time = time_now.time_since_epoch(); + std::string currentTime = std::to_string(utc_time.count()); + + statsFile << "Systems Statistics at " + currentTime + " for module " + pname + + "\n"; + statsFile << "Memory Statistics: \n"; + statsFile << "Total Virtual Memory: " + + std::to_string(memoryStats.total_virtual_memory) + "\n"; + statsFile << "Virtual Memory Used: " + + std::to_string(memoryStats.virtual_memory_used) + "\n"; + statsFile << "Virtual Memory Process: " + + std::to_string(memoryStats.virtual_memory_process) + "\n"; + statsFile << "Total Physical Memory: " + + std::to_string(memoryStats.total_physical_memory) + "\n"; + statsFile << "Physical Memory Used: " + + std::to_string(memoryStats.physical_memory_used) + "\n"; + statsFile << "Physical Memory Process: " + + std::to_string(memoryStats.physical_memory_process) + "\n"; + statsFile << "CPU Statistics: \n"; + statsFile << "Total CPU Utilization: " + + std::to_string(cpuStats.cpu_utilized) + "\n"; + statsFile << "Process CPU Utilization: " + + std::to_string(cpuStats.cpu_utilized_process) + "\n"; + statsFile << "\n"; + + statsFile.close(); +} \ No newline at end of file diff --git a/utils/test/comm/UnitTests.cc b/utils/test/comm/UnitTests.cc index da5227ad..5c771222 100644 --- a/utils/test/comm/UnitTests.cc +++ b/utils/test/comm/UnitTests.cc @@ -30,225 +30,192 @@ #include #include -#include "gtest/gtest.h" #include "Connection.h" +#include "gtest/gtest.h" #define SERVER_PORT_INTERCHANGE 43444 -#define SERVER_PORT_MULTIPLE 43444 +#define SERVER_PORT_MULTIPLE 43444 #define NUMBER_OF_MESSAGES 20 typedef std::basic_string BytesBuffer; // Ping-pong messages between server and client -TEST(CommTest, SyncMessages) -{ - std::string client_to_server("testing this awesome comm library with " \ - "come random data"); - std::string server_to_client("this awesome library seems to work :)"); - - std::thread server_thread([client_to_server, server_to_client]() - { - comm::ConnServer server(SERVER_PORT_INTERCHANGE); - comm::Connection conn_server(server.accept()); - - for (int i = 0; i < NUMBER_OF_MESSAGES; ++i) { - //Recieve something - BytesBuffer message_received = conn_server.recv_message(); - std::string recv_message ((char*)message_received.data()); - ASSERT_EQ(0, recv_message.compare(client_to_server)); - - //Send something - conn_server.send_message((const uint8_t*)server_to_client.c_str(), - server_to_client.length()); - } - }); - - server_thread.detach(); - - comm::ConnClient conn_client("localhost", SERVER_PORT_INTERCHANGE); - - for (int i = 0; i < NUMBER_OF_MESSAGES; ++i){ - // Send something - conn_client.send_message((const uint8_t*)client_to_server.c_str(), - client_to_server.length()); - - // Receive something - BytesBuffer message_received = conn_client.recv_message(); - std::string recv_message ((char*)message_received.data()); - ASSERT_EQ(0, recv_message.compare(server_to_client)); +TEST(CommTest, SyncMessages) { + std::string client_to_server("testing this awesome comm library with " + "come random data"); + std::string server_to_client("this awesome library seems to work :)"); + + std::thread server_thread([client_to_server, server_to_client]() { + comm::ConnServer server(SERVER_PORT_INTERCHANGE); + comm::Connection conn_server(server.accept()); + + for (int i = 0; i < NUMBER_OF_MESSAGES; ++i) { + // Recieve something + BytesBuffer message_received = conn_server.recv_message(); + std::string recv_message((char *)message_received.data()); + ASSERT_EQ(0, recv_message.compare(client_to_server)); + + // Send something + conn_server.send_message((const uint8_t *)server_to_client.c_str(), + server_to_client.length()); } + }); + + server_thread.detach(); + + comm::ConnClient conn_client("localhost", SERVER_PORT_INTERCHANGE); + + for (int i = 0; i < NUMBER_OF_MESSAGES; ++i) { + // Send something + conn_client.send_message((const uint8_t *)client_to_server.c_str(), + client_to_server.length()); + + // Receive something + BytesBuffer message_received = conn_client.recv_message(); + std::string recv_message((char *)message_received.data()); + ASSERT_EQ(0, recv_message.compare(server_to_client)); + } } -// Both client and server send all messages firsts and then check the received messages. -TEST(CommTest, AsyncMessages) -{ - std::string client_to_server("client sends some random data"); - std::string server_to_client("this library seems to work :)"); - - std::thread server_thread([client_to_server, server_to_client]() - { - comm::ConnServer server(SERVER_PORT_MULTIPLE); - comm::Connection conn_server(server.accept()); - - for (int i = 0; i < NUMBER_OF_MESSAGES; ++i) { - //Send something - conn_server.send_message((const uint8_t*)server_to_client.c_str(), - server_to_client.length()); - } - - for (int i = 0; i < NUMBER_OF_MESSAGES; ++i){ - //Recieve something - BytesBuffer message_received = conn_server.recv_message(); - std::string recv_message ((char*)message_received.data()); - ASSERT_EQ(0, recv_message.compare(client_to_server)); - } - }); - server_thread.detach(); - - comm::ConnClient conn_client("localhost", SERVER_PORT_MULTIPLE); - - for (int i = 0; i < NUMBER_OF_MESSAGES; ++i){ - // Send something - conn_client.send_message((const uint8_t*)(client_to_server).c_str(), - (client_to_server).length()); - } +// Both client and server send all messages firsts and then check the received +// messages. +TEST(CommTest, AsyncMessages) { + std::string client_to_server("client sends some random data"); + std::string server_to_client("this library seems to work :)"); + + std::thread server_thread([client_to_server, server_to_client]() { + comm::ConnServer server(SERVER_PORT_MULTIPLE); + comm::Connection conn_server(server.accept()); - for (int i = 0; i < NUMBER_OF_MESSAGES; ++i){ + for (int i = 0; i < NUMBER_OF_MESSAGES; ++i) { + // Send something + conn_server.send_message((const uint8_t *)server_to_client.c_str(), + server_to_client.length()); + } - // Receive something - BytesBuffer message_received = conn_client.recv_message(); - std::string recv_message ((char*)message_received.data()); - ASSERT_EQ(0, recv_message.compare(server_to_client)); + for (int i = 0; i < NUMBER_OF_MESSAGES; ++i) { + // Recieve something + BytesBuffer message_received = conn_server.recv_message(); + std::string recv_message((char *)message_received.data()); + ASSERT_EQ(0, recv_message.compare(client_to_server)); } + }); + server_thread.detach(); + + comm::ConnClient conn_client("localhost", SERVER_PORT_MULTIPLE); + + for (int i = 0; i < NUMBER_OF_MESSAGES; ++i) { + // Send something + conn_client.send_message((const uint8_t *)(client_to_server).c_str(), + (client_to_server).length()); + } + + for (int i = 0; i < NUMBER_OF_MESSAGES; ++i) { + + // Receive something + BytesBuffer message_received = conn_client.recv_message(); + std::string recv_message((char *)message_received.data()); + ASSERT_EQ(0, recv_message.compare(server_to_client)); + } } // Server accepts connection and then goes down, client tries to send. -TEST(CommTest, ServerShutdownSend) -{ - std::string client_to_server("testing this awesome comm library " \ - "with some random data"); - std::string server_to_client("this awesome library seems to work :)"); - - std::thread server_thread([client_to_server, server_to_client]() - { - comm::ConnServer server(SERVER_PORT_INTERCHANGE); - comm::Connection conn_server(server.accept()); - }); - - comm::ConnClient conn_client("localhost", SERVER_PORT_INTERCHANGE); - - server_thread.join(); // Here the server will close the port. - - ASSERT_THROW( - conn_client.send_message((const uint8_t*)client_to_server.c_str(), - client_to_server.length()), - comm::ExceptionComm - ); +TEST(CommTest, ServerShutdownSend) { + std::string client_to_server("testing this awesome comm library " + "with some random data"); + std::string server_to_client("this awesome library seems to work :)"); + + std::thread server_thread([client_to_server, server_to_client]() { + comm::ConnServer server(SERVER_PORT_INTERCHANGE); + comm::Connection conn_server(server.accept()); + }); + + comm::ConnClient conn_client("localhost", SERVER_PORT_INTERCHANGE); + + server_thread.join(); // Here the server will close the port. + + ASSERT_THROW( + conn_client.send_message((const uint8_t *)client_to_server.c_str(), + client_to_server.length()), + comm::ExceptionComm); } // Server accepts connection and then goes down, client tries to recv. -TEST(CommTest, ServerShutdownRecv) -{ - std::string client_to_server("testing this awesome comm " \ - "library with some random data"); - - std::thread server_thread([client_to_server](){ +TEST(CommTest, ServerShutdownRecv) { + std::string client_to_server("testing this awesome comm " + "library with some random data"); - comm::ConnServer server(SERVER_PORT_INTERCHANGE); - comm::Connection conn_server(server.accept()); - }); + std::thread server_thread([client_to_server]() { + comm::ConnServer server(SERVER_PORT_INTERCHANGE); + comm::Connection conn_server(server.accept()); + }); - comm::ConnClient conn_client("localhost", SERVER_PORT_INTERCHANGE); + comm::ConnClient conn_client("localhost", SERVER_PORT_INTERCHANGE); - server_thread.join(); // Here the server will close the port. + server_thread.join(); // Here the server will close the port. - ASSERT_THROW( - BytesBuffer message_received = conn_client.recv_message(), - comm::ExceptionComm - ); + ASSERT_THROW(BytesBuffer message_received = conn_client.recv_message(), + comm::ExceptionComm); } -TEST(CommTest, SendArrayInts) -{ - int arr[10] = {22, 568, 254, 784, 452, 458, 235, 124, 1425, 1542}; - std::thread server_thread([arr]() - { - comm::ConnServer server(SERVER_PORT_INTERCHANGE); - comm::Connection conn_server(server.accept()); +TEST(CommTest, SendArrayInts) { + int arr[10] = {22, 568, 254, 784, 452, 458, 235, 124, 1425, 1542}; + std::thread server_thread([arr]() { + comm::ConnServer server(SERVER_PORT_INTERCHANGE); + comm::Connection conn_server(server.accept()); - conn_server.send_message((uint8_t*)arr, sizeof(arr)); - }); + conn_server.send_message((uint8_t *)arr, sizeof(arr)); + }); - server_thread.detach(); + server_thread.detach(); - comm::ConnClient conn_client("localhost", SERVER_PORT_INTERCHANGE); - BytesBuffer message_received = conn_client.recv_message(); + comm::ConnClient conn_client("localhost", SERVER_PORT_INTERCHANGE); + BytesBuffer message_received = conn_client.recv_message(); - int* arr_recv = (int*)message_received.data(); - for (int i = 0; i < 10; ++i) { - ASSERT_EQ(arr[i], arr_recv[i]); - } + int *arr_recv = (int *)message_received.data(); + for (int i = 0; i < 10; ++i) { + ASSERT_EQ(arr[i], arr_recv[i]); + } } -TEST(CommTest, MoveCopy) -{ - comm::Connection a; - comm::Connection conn_server; - conn_server = std::move(a); // Testing copy with move works +TEST(CommTest, MoveCopy) { + comm::Connection a; + comm::Connection conn_server; + conn_server = std::move(a); // Testing copy with move works } -TEST(CommTest, Unreachable) -{ - ASSERT_THROW ( - comm::ConnClient conn_client("unreachable.com.ar.something", 5555), - comm::ExceptionComm - ); - - ASSERT_THROW ( - comm::ConnClient conn_client("localhost", -1), - comm::ExceptionComm - ); +TEST(CommTest, Unreachable) { + ASSERT_THROW( + comm::ConnClient conn_client("unreachable.com.ar.something", 5555), + comm::ExceptionComm); + + ASSERT_THROW(comm::ConnClient conn_client("localhost", -1), + comm::ExceptionComm); } -TEST(CommTest, ServerWrongPort) -{ - ASSERT_THROW ( - comm::ConnServer conn_server(-22), - comm::ExceptionComm - ); - - ASSERT_THROW ( - comm::ConnServer conn_server(0), - comm::ExceptionComm - ); +TEST(CommTest, ServerWrongPort) { + ASSERT_THROW(comm::ConnServer conn_server(-22), comm::ExceptionComm); + + ASSERT_THROW(comm::ConnServer conn_server(0), comm::ExceptionComm); } -TEST(CommTest, ClientWrongAddrOrPort) -{ - ASSERT_THROW ( - comm::ConnClient conn_client("", 3424), - comm::ExceptionComm - ); - - ASSERT_THROW ( - comm::ConnClient conn_client("intel.com", -32), - comm::ExceptionComm - ); - - ASSERT_THROW ( - comm::ConnClient conn_client("intel.com", 0), - comm::ExceptionComm - ); +TEST(CommTest, ClientWrongAddrOrPort) { + ASSERT_THROW(comm::ConnClient conn_client("", 3424), comm::ExceptionComm); + + ASSERT_THROW(comm::ConnClient conn_client("intel.com", -32), + comm::ExceptionComm); + + ASSERT_THROW(comm::ConnClient conn_client("intel.com", 0), + comm::ExceptionComm); } -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); - // To make GoogleTest silent: - // if (true) { - // auto& listeners = ::testing::UnitTest::GetInstance()->listeners(); - // delete listeners.Release(listeners.default_result_printer()); - // } - return RUN_ALL_TESTS(); + // To make GoogleTest silent: + // if (true) { + // auto& listeners = ::testing::UnitTest::GetInstance()->listeners(); + // delete listeners.Release(listeners.default_result_printer()); + // } + return RUN_ALL_TESTS(); }