diff --git a/.docker/release b/.docker/release deleted file mode 100755 index 700cb2fc56e5f34a81204feb68b7feaf59a9bc86..0000000000000000000000000000000000000000 --- a/.docker/release +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -USER="fairdataaustria" -VERSION=$1 - -# usage -if [ $# -ne 1 ]; then - echo "USAGE: ./release VERSION" - echo " (e.g. 1.0.0-alpha)" - exit 1 -fi - -# check tag exists -TAG=$(git tag -n | awk '{print $1}' | grep -o "^v${VERSION}\$") -if [ -z $TAG ]; then - echo "FAIL: could not find version 'v${VERSION}' in git tags" - exit 2 -fi - -# build -git checkout ${VERSION} -docker-compose build fda-metadata-db -docker-compose build --parallel - -# login -echo "Authentication required for user ${USER} at docker.io (docker hub)" -docker login docker.io -u $USER - -# tag -IMAGE=$(ls -d fda-*) -for DIR in $IMAGE -do -# CHECK=$(docker images "${USER}/${IMAGE}:${VERSION}" -q) -# if [ ! -z $CHECK ]; then -# echo "CHECK ${DIR}: tag ${USER}/${IMAGE}:${VERSION} already exists locally" -# exit 3 -# fi - echo "TAG ${DIR}" - docker tag ${IMAGE}:latest ${USER}/${IMAGE}:${VERSION} - docker push ${USER}/${IMAGE}:${VERSION} -done diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000000000000000000000000000000000..26ae9e5171ec6fb79a3d65eb7cc78b00d7768ea3 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +ZENODO_API_KEY= +API=http://fda-gateway-service:9095 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 92686cefe4d9ddcdb3768f98a57b4d098d9c980d..6407e9234e2cc53309ea3fb4e421d3d0119c4f16 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,31 +18,90 @@ stages: - build - test-frontend - test-backend + - registry + - deploy + +build-backend-metadata: + stage: build + script: + - "make build-backend-metadata" + +build-backend-authentication: + stage: build + needs: + - build-backend-metadata + script: + - "make build-backend-authentication" + +build-backend-citation: + stage: build + needs: + - build-backend-metadata + script: + - "make build-backend-citation" + +build-backend-container: + stage: build + needs: + - build-backend-metadata + script: + - "make build-backend-container" + +build-backend-database: + stage: build + needs: + - build-backend-metadata + script: + - "make build-backend-database" + +build-backend-discovery: + stage: build + needs: + - build-backend-metadata + script: + - "make build-backend-discovery" + +build-backend-gateway: + stage: build + needs: + - build-backend-metadata + script: + - "make build-backend-gateway" + +build-backend-query: + stage: build + needs: + - build-backend-metadata + script: + - "make build-backend-query" + +build-backend-table: + stage: build + needs: + - build-backend-metadata + script: + - "make build-backend-table" build-docker: stage: build script: - - "docker image pull postgres:latest || true" - - "docker image pull mysql:latest || true" - - "docker image pull mariadb:latest || true" - - "docker image pull rabbitmq:3-alpine || true" - - "docker-compose down || true" - - "docker container stop $(docker container ls -aq) || true" - - "docker container rm $(docker container ls -aq) || true" - - "docker volume rm $(docker volume ls -q) || true" - - "docker-compose build" - -build-metadata-db: + - make build-docker + +build-frontend: stage: build script: - - "mvn -f fda-metadata-db/pom.xml clean install" # local maven2 repository + - make build-frontend -test-frontend-ui: +test-frontend: stage: test-frontend + dependencies: + - build-docker + - build-frontend + needs: + - build-docker + - build-frontend script: - - "npm --prefix ./fda-ui install" - - "docker-compose up -d" - - "npm --prefix ./fda-ui run test" + - make test-frontend artifacts: when: always paths: @@ -53,15 +112,13 @@ test-frontend-ui: test-backend-container: stage: test-backend - script: - - "./fda-container-service/rest-service/src/test/resources/integration-test.before" - - "mvn -f fda-container-service/pom.xml clean test verify" - - "./fda-container-service/rest-service/src/test/resources/integration-test.after" - - cat ./fda-container-service/report/target/site/jacoco-aggregate/index.html needs: - - build-metadata-db + - build-backend-container dependencies: - - build-metadata-db + - build-backend-container + script: + - make test-backend-container + - cat ./fda-container-service/report/target/site/jacoco-aggregate/index.html artifacts: when: always paths: @@ -73,15 +130,13 @@ test-backend-container: test-backend-database: stage: test-backend - script: - - "./fda-database-service/rest-service/src/test/resources/integration-test.before" - - "mvn -f fda-database-service/pom.xml clean test verify" - - "./fda-database-service/rest-service/src/test/resources/integration-test.after" - - cat ./fda-database-service/report/target/site/jacoco-aggregate/index.html needs: - - build-metadata-db + - build-backend-database dependencies: - - build-metadata-db + - build-backend-database + script: + - mvn -f fda-database-service/pom.xml clean test verify + - cat ./fda-database-service/report/target/site/jacoco-aggregate/index.html artifacts: when: always paths: @@ -93,25 +148,49 @@ test-backend-database: test-backend-discovery: stage: test-backend + needs: + - build-backend-discovery + dependencies: + - build-backend-discovery script: - - "mvn -f fda-discovery-service/pom.xml clean test verify" + - mvn -f fda-discovery-service/pom.xml clean test verify + - cat ./fda-discovery-service/report/target/site/jacoco-aggregate/index.html + artifacts: + when: always + paths: + - fda-discovery-service/rest-service/target/site/jacoco/jacoco.xml + - fda-discovery-service/rest-service/target/site/jacoco/index.html + reports: + junit: + - fda-discovery-service/rest-service/target/surefire-reports/TEST-*.xml test-backend-gateway: stage: test-backend + needs: + - build-backend-gateway + dependencies: + - build-backend-gateway script: - - "mvn -f fda-gateway-service/pom.xml clean test verify" + - mvn -f fda-gateway-service/pom.xml clean test verify + - cat ./fda-gateway-service/report/target/site/jacoco-aggregate/index.html + artifacts: + when: always + paths: + - fda-gateway-service/rest-service/target/site/jacoco/jacoco.xml + - fda-gateway-service/rest-service/target/site/jacoco/index.html + reports: + junit: + - fda-gateway-service/rest-service/target/surefire-reports/TEST-*.xml test-backend-query: stage: test-backend - script: - - "./fda-query-service/rest-service/src/test/resources/integration-test.before" - - "mvn -f fda-query-service/pom.xml clean test verify" - - "./fda-query-service/rest-service/src/test/resources/integration-test.after" - - cat ./fda-query-service/report/target/site/jacoco-aggregate/index.html needs: - - build-metadata-db + - build-backend-query dependencies: - - build-metadata-db + - build-backend-query + script: + - mvn -f fda-query-service/pom.xml clean test verify + - cat ./fda-query-service/report/target/site/jacoco-aggregate/index.html artifacts: when: always paths: @@ -123,15 +202,13 @@ test-backend-query: test-backend-table: stage: test-backend - script: - - "./fda-table-service/rest-service/src/test/resources/integration-test.before" - - "mvn -f fda-table-service/pom.xml clean test verify" - - "./fda-table-service/rest-service/src/test/resources/integration-test.after" - - cat ./fda-table-service/report/target/site/jacoco-aggregate/index.html needs: - - build-metadata-db + - build-backend-table dependencies: - - build-metadata-db + - build-backend-table + script: + - mvn -f fda-table-service/pom.xml clean test verify + - cat ./fda-table-service/report/target/site/jacoco-aggregate/index.html artifacts: when: always paths: @@ -143,15 +220,13 @@ test-backend-table: test-backend-citation: stage: test-backend + needs: + - build-backend-citation + dependencies: + - build-backend-citation script: - - ./fda-citation-service/rest-service/src/test/resources/integration-test.before - "ZENODO_API_KEY=${ZENODO_API_KEY} mvn -f fda-citation-service/pom.xml clean test verify" - - ./fda-citation-service/rest-service/src/test/resources/integration-test.after - cat ./fda-citation-service/report/target/site/jacoco-aggregate/index.html - needs: - - build-metadata-db - dependencies: - - build-metadata-db artifacts: when: always paths: @@ -160,3 +235,92 @@ test-backend-citation: reports: junit: - fda-citation-service/rest-service/target/surefire-reports/TEST-*.xml + +test-backend-authentication: + stage: test-backend + needs: + - build-backend-authentication + dependencies: + - build-backend-authentication + script: + - mvn -f fda-authentication-service/pom.xml clean test verify + - cat ./fda-authentication-service/report/target/site/jacoco-aggregate/index.html + artifacts: + when: always + paths: + - fda-authentication-service/rest-service/target/site/jacoco/jacoco.xml + - fda-authentication-service/rest-service/target/site/jacoco/index.html + reports: + junit: + - fda-authentication-service/rest-service/target/surefire-reports/TEST-*.xml + +registry-stable: + stage: registry + only: + - master + needs: + - test-frontend + - test-backend-authentication + - test-backend-citation + - test-backend-container + - test-backend-database + - test-backend-discovery + - test-backend-gateway + - test-backend-query + - test-backend-table + dependencies: + - test-frontend + - test-backend-authentication + - test-backend-citation + - test-backend-container + - test-backend-database + - test-backend-discovery + - test-backend-gateway + - test-backend-query + - test-backend-table + script: + - make registry-stable + +registry-staging: + stage: registry + environment: + name: staging + url: https://staging.ossdip.at + only: + - dev + needs: + - test-frontend + - test-backend-authentication + - test-backend-citation + - test-backend-container + - test-backend-database + - test-backend-discovery + - test-backend-gateway + - test-backend-query + - test-backend-table + dependencies: + - test-frontend + - test-backend-authentication + - test-backend-citation + - test-backend-container + - test-backend-database + - test-backend-discovery + - test-backend-gateway + - test-backend-query + - test-backend-table + script: + - make registry-staging + +deploy-stable: + stage: deploy + environment: + name: stable + url: https://dbrepo.ossdip.at + only: + - master + needs: + - registry-stable + dependencies: + - registry-stable + script: + - make deploy-stable diff --git a/.gitlab-ci/.mavenrc b/.gitlab-ci/.mavenrc new file mode 100644 index 0000000000000000000000000000000000000000..1ae84fa8932e7122dee1c3e48847b45ca981f9ef --- /dev/null +++ b/.gitlab-ci/.mavenrc @@ -0,0 +1 @@ +JAVA_HOME="/usr/lib/jvm/jre-11-openjdk/" \ No newline at end of file diff --git a/.gitlab-ci/dependencies b/.gitlab-ci/dependencies new file mode 100755 index 0000000000000000000000000000000000000000..f08cbfd9e2a7e93f7aeac5c7a489797c065f8843 --- /dev/null +++ b/.gitlab-ci/dependencies @@ -0,0 +1,3 @@ +#!/bin/bash +sudo dnf install -y git vim net-tools chromium libdrm maven make java-11-openjdk java-11-openjdk-devel crontabs +sudo dnf module install -y nodejs:14 \ No newline at end of file diff --git a/.gitlab-ci/deploy b/.gitlab-ci/deploy new file mode 100755 index 0000000000000000000000000000000000000000..4d35912f457b7f83da00c671ff0835a5a7f073eb --- /dev/null +++ b/.gitlab-ci/deploy @@ -0,0 +1,6 @@ +#!/bin/bash +scp ./.rhel-prod/install_cert dbrepo.ossdip.at: +scp ./.rhel-prod/docker-compose.yml dbrepo.ossdip.at: +ssh dbrepo.ossdip.at "docker-compose down" +ssh dbrepo.ossdip.at "ENV=${ENV} ./install_cert" +ssh dbrepo.ossdip.at "ENV=${ENV} docker-compose up -d" \ No newline at end of file diff --git a/.gitlab-ci/frontend/install_cert b/.gitlab-ci/frontend/install_cert new file mode 100755 index 0000000000000000000000000000000000000000..c455ebd8091c932a4736d2d5892742246132e554 --- /dev/null +++ b/.gitlab-ci/frontend/install_cert @@ -0,0 +1,22 @@ +#!/bin/bash +CA_PATH="/etc/letsencrypt/live/dbrepo.ossdip.at" +CERT_PATH="./fda-ui/.prod/" +USER="rocky" + +if [ "$ENV" != "prod" ]; then + echo "WARN: environment must be prod" + exit 0 +fi + +sudo certbot certonly --standalone --preferred-challenges http -d dbrepo.ossdip.at \ + -m martin.weise@tuwien.ac.at --agree-tos --keep-until-expiring + +sudo cp "${CA_PATH}/cert.pem" "${CERT_PATH}" +sudo cp "${CA_PATH}/privkey.pem" "${CERT_PATH}" + +mv ./fda-ui/secure.conf ./fda-ui/.prod/default.conf + +mkdir -p "${CERT_PATH}" +sudo chown -R "${USER}:docker" "${CERT_PATH}" + +ls -la "${CERT_PATH}" diff --git a/.gitlab/license.svg b/.gitlab-ci/license.svg similarity index 100% rename from .gitlab/license.svg rename to .gitlab-ci/license.svg diff --git a/.gitlab/build-full b/.gitlab/build-full deleted file mode 100755 index e33381aa9cc771c7882dde956eefcad8bfe27e36..0000000000000000000000000000000000000000 --- a/.gitlab/build-full +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/fish -docker-compose down -docker container stop (docker container ls -aq) -docker container rm (docker container ls -aq) -docker-compose build fda-metadata-db -docker-compose build -docker volume rm (docker volume ls -q) diff --git a/.gitlab/calc-image-sizes b/.gitlab/calc-image-sizes deleted file mode 100755 index a5f2dacd344dfadf153fa8785e70507bac3d7207..0000000000000000000000000000000000000000 --- a/.gitlab/calc-image-sizes +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -SUM=$(docker image ls | grep "fda-" | awk '{print $7}' | grep -Po '\d{1,}' | awk '{s+=$1} END {print s}') -echo "TOTAL fda-* image size ${SUM} MB" \ No newline at end of file diff --git a/.gitlab/gen-frontend-api b/.gitlab/gen-frontend-api deleted file mode 100644 index 5fb2ab087eaf3eda0a60f5396268f96efd4f838d..0000000000000000000000000000000000000000 --- a/.gitlab/gen-frontend-api +++ /dev/null @@ -1 +0,0 @@ -# npm install -g swagger-node-codegen \ No newline at end of file diff --git a/.gitlab/gen-wiki b/.gitlab/gen-wiki deleted file mode 100755 index 8a66877376e32a1538e968a2d1a3e16a81c04203..0000000000000000000000000000000000000000 --- a/.gitlab/gen-wiki +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# DESCRIPTION: script to generate the markdown documentation of some services for the wiki -# WHEN: merge to master - -# dependencies -docker pull quay.io/goswagger/swagger > /dev/null - -echo -e "\e[96m1\e[39m) Spin-up the services" -docker-compose up -d > /dev/null 2>&1 - -echo -e "\e[96m2\e[39m) Generate markdown documentations" - -echo "Generating docs for ./fda-container-service" -wget http://localhost:9091/v2/api-docs -O swagger.json > /dev/null 2>&1 -docker run --rm -it --user $(id -u):$(id -g) -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger generate markdown --skip-validation -q -mv markdown.md container.md - -echo "Generating docs for ./fda-database-service" -wget http://localhost:9092/v2/api-docs -O swagger.json > /dev/null 2>&1 -docker run --rm -it --user $(id -u):$(id -g) -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger generate markdown --skip-validation -q -mv markdown.md database.md - -echo "Generating docs for ./fda-query-service" -wget http://localhost:9093/v2/api-docs -O swagger.json > /dev/null 2>&1 -docker run --rm -it --user $(id -u):$(id -g) -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger generate markdown --skip-validation -q -mv markdown.md query.md - -echo "Generating docs for ./fda-table-service" -wget http://localhost:9094/v2/api-docs -O swagger.json > /dev/null 2>&1 -docker run --rm -it --user $(id -u):$(id -g) -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger generate markdown --skip-validation -q -mv markdown.md table.md \ No newline at end of file diff --git a/.gitlab/pre-merge-test b/.gitlab/pre-merge-test deleted file mode 100755 index ddb7f27d600d1ccbdc983b1b0e39646bd44d4ff2..0000000000000000000000000000000000000000 --- a/.gitlab/pre-merge-test +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -# DESCRIPTION: script to check if the current code base passes all tests before submitting to pipeline -# WHEN: merge to dev, master - -SERVICES="container - database - discovery - gateway - query - table" - -# 1) Docker -echo -e "\e[96m1\e[39m) Docker" -echo "Building all" -docker-compose build > /dev/null 2>&1 - -if [[ $? -ne 0 ]]; then - echo -e "... \e[91mNOT OK\e[39m" -else - echo -e "... \e[92mOK\e[39m" -fi - -# 2) Maven -echo -e "\e[96m2\e[39m) Maven" - -mvn -f ./fda-metadata-db/pom.xml clean install > /dev/null 2>&1 - -for service in $SERVICES; do - echo "Testing ./fda-${service}-service" - RESULT=$(mvn -f "./fda-${service}-service/pom.xml" clean test verify | grep -o "FAILURE") - if [[ $RESULT ]]; then - echo -e "... \e[91mNOT OK\e[39m" - else - echo -e "... \e[92mOK\e[39m" - fi -done - -# 3) Runtime -echo -e "\e[96m3\e[39m) Runtime" -echo "Execute Docker runtime, look for errors" -docker-compose up diff --git a/.rhel-prod/crontab b/.rhel-prod/crontab new file mode 100644 index 0000000000000000000000000000000000000000..bbc97b1a429e174b4a42e99503e70098f1acb441 --- /dev/null +++ b/.rhel-prod/crontab @@ -0,0 +1,2 @@ +0 2 * * * /usr/bin/make -C /home/rocky/fda-services teardown +1 2 * * * /usr/bin/make -C /home/rocky/fda-services run \ No newline at end of file diff --git a/.rhel-prod/docker-compose.yml b/.rhel-prod/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..699690517230ead569d1c7ba3d461daec10ba8ab --- /dev/null +++ b/.rhel-prod/docker-compose.yml @@ -0,0 +1,325 @@ +version: "3.6" + +volumes: + fda-metadata-db-data: + fda-broker-service-data: + +networks: + fda-public: + name: fda-public + driver: bridge + ipam: + config: + - subnet: 172.29.0.0/16 + driver_opts: + com.docker.network.driver.mtu: 1450 + fda-userdb: + name: fda-userdb + driver: bridge + ipam: + config: + - subnet: 172.28.0.0/16 + driver_opts: + com.docker.network.driver.mtu: 1450 + +services: + + fda-metadata-db: + restart: on-failure + container_name: fda-metadata-db + hostname: fda-metadata-db + build: + context: ./fda-metadata-db + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-metadata-db + networks: + - fda-public + volumes: + - fda-metadata-db-data:/var/lib/postgresql/data + ports: + - "5432:5432" + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: fda + + fda-discovery-service: + restart: on-failure + container_name: fda-discovery-service + hostname: fda-discovery-service + build: + context: ./fda-discovery-service + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-discovery-service + networks: + - fda-public + environment: + SPRING_PROFILES_ACTIVE: docker + ports: + - "9090:9090" + + fda-gateway-service: + restart: on-failure + container_name: fda-gateway-service + hostname: fda-gateway-service + build: + context: ./fda-gateway-service + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-gateway-service + networks: + fda-public: + aliases: + - fda-gateway-service + environment: + SPRING_PROFILES_ACTIVE: docker + ports: + - "9095:9095" + depends_on: + fda-discovery-service: + condition: service_healthy + logging: + driver: json-file + + fda-database-service: + restart: on-failure + container_name: fda-database-service + hostname: fda-database-service + build: + context: ./fda-database-service + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-database-service + networks: + - fda-userdb + - fda-public + environment: + SPRING_PROFILES_ACTIVE: docker + ports: + - "9092:9092" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + fda-discovery-service: + condition: service_healthy + fda-broker-service: + condition: service_healthy + fda-metadata-db: + condition: service_healthy + logging: + driver: json-file + + fda-container-service: + restart: on-failure + container_name: fda-container-service + hostname: fda-container-service + build: + context: ./fda-container-service + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-container-service + networks: + - fda-public + environment: + SPRING_PROFILES_ACTIVE: docker,seed + ports: + - "9091:9091" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + fda-discovery-service: + condition: service_healthy + fda-metadata-db: + condition: service_healthy + logging: + driver: json-file + + fda-authentication-service: + restart: on-failure + container_name: fda-authentication-service + hostname: fda-authentication-service + build: + context: ./fda-authentication-service + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-authentication-service + networks: + - fda-public + volumes: + - /tmp:/tmp + environment: + SERVER_NAME: dbrepo.ossdip.at + SPRING_PROFILES_ACTIVE: docker + KEY_STORE_PASSWORD: ${KEY_STORE_PASSWORD} + KEY_STORE_LOCATION: /tmp/dbrepo.jks + KEY_STORE_TYPE: jks + ports: + - "9097:9097" + depends_on: + fda-discovery-service: + condition: service_healthy + logging: + driver: json-file + + fda-query-service: + restart: on-failure + container_name: fda-query-service + hostname: fda-query-service + build: + context: ./fda-query-service + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-query-service + networks: + - fda-public + - fda-userdb + environment: + SPRING_PROFILES_ACTIVE: docker + ports: + - "9093:9093" + volumes: + - /tmp:/tmp + depends_on: + fda-discovery-service: + condition: service_healthy + fda-container-service: + condition: service_healthy + fda-metadata-db: + condition: service_healthy + logging: + driver: json-file + + fda-table-service: + restart: on-failure + container_name: fda-table-service + hostname: fda-table-service + build: + context: ./fda-table-service + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-table-service + networks: + - fda-public + - fda-userdb + environment: + SPRING_PROFILES_ACTIVE: docker + multipart.location: /tmp + ports: + - "9094:9094" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /tmp:/tmp + depends_on: + fda-metadata-db: + condition: service_healthy + fda-discovery-service: + condition: service_healthy + fda-broker-service: + condition: service_healthy + + fda-citation-service: + restart: on-failure + container_name: fda-citation-service + hostname: fda-citation-service + build: + context: ./fda-citation-service + args: + CI_JOB_STAGE: "${CI_JOB_STAGE}" + image: fda-citation-service + networks: + - fda-public + environment: + SPRING_PROFILES_ACTIVE: docker + ZENODO_API_KEY: "${ZENODO_API_KEY}" + ports: + - "9096:9096" + depends_on: + fda-metadata-db: + condition: service_healthy + fda-discovery-service: + condition: service_healthy + fda-table-service: + condition: service_healthy + + fda-analyse-service: + restart: on-failure + container_name: fda-analyse-service + hostname: fda-analyse-service + build: ./fda-analyse-service + image: fda-analyse-service + networks: + - fda-public + - fda-userdb + command: sh -c "/wait && flask run" # docker-compose should not test the implementation + environment: + EUREKA_SERVER: http://fda-discovery-service:9090/eureka + ports: + - "5000:5000" + volumes: + - /tmp:/tmp + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + fda-discovery-service: + condition: service_healthy + fda-database-service: + condition: service_healthy + logging: + driver: json-file + + fda-broker-service: + restart: on-failure + container_name: fda-broker-service + hostname: fda-broker-service + build: ./fda-broker-service + image: fda-broker-service + networks: + - fda-public + ports: + - "5672:5672" + - "15672:15672" + volumes: + - fda-broker-service-data:/var/lib/rabbitmq/ + + fda-search-service: + restart: always + container_name: fda-search-service + hostname: fda-search-service + image: elasticsearch:7.13.4 + networks: + - fda-public + environment: + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + - logger.level=WARN + depends_on: + fda-discovery-service: + condition: service_healthy + fda-table-service: + condition: service_healthy + ports: + - "9200:9200" + - "9600:9600" + + fda-ui: + restart: on-failure + container_name: fda-ui + hostname: fda-ui + build: ./fda-ui + image: fda-ui + networks: + - fda-public + ports: + - "443:443" + - "3000:3000" + volumes: + - /certs:/certs + - /tmp:/tmp + depends_on: + fda-gateway-service: + condition: service_healthy + environment: + HOST: 0.0.0.0 + API: http://fda-gateway-service:9095 + NGINX_PORT: "${NGINX_PORT:-3000}" \ No newline at end of file diff --git a/.rhel-prod/install_cert b/.rhel-prod/install_cert new file mode 100755 index 0000000000000000000000000000000000000000..0d13b68c7a4a26c533833f8f075bcb0f73b63427 --- /dev/null +++ b/.rhel-prod/install_cert @@ -0,0 +1,21 @@ +#!/bin/bash +CERT_STORE_LOCATION="/tmp/cert.p12" +KEY_STORE_LOCATION="/tmp/dbrepo.jks" +KEY_STORE_PASS="dbrepo" +CERT_LOCATION="/etc/letsencrypt/live/dbrepo.ossdip.at" + +# REQUEST +sudo certbot certonly --standalone --preferred-challenges http -d dbrepo.ossdip.at \ + -m martin.weise@tuwien.ac.at --agree-tos --keep-until-expiring + +# CONVERT PKCS12 +sudo openssl pkcs12 -export -out "${CERT_STORE_LOCATION}" -in "${CERT_LOCATION}/cert.pem" \ + -inkey "${CERT_LOCATION}/privkey.pem" -passout "pass:${KEY_STORE_PASS}" + +# FIX PERMISSIONS +sudo chmod 644 "${CERT_STORE_LOCATION}" + +# IMPORT +keytool -importkeystore -deststorepass "${KEY_STORE_PASS}" -destkeypass "${KEY_STORE_PASS}" \ + -destkeystore "${KEY_STORE_LOCATION}" -srckeystore "${CERT_STORE_LOCATION}" -srcstoretype PKCS12 \ + -srcstorepass "${KEY_STORE_PASS}" -alias 1 \ No newline at end of file diff --git a/.rhel-prod/teardown b/.rhel-prod/teardown new file mode 100755 index 0000000000000000000000000000000000000000..9939ece2c690568cdd8c98462434f3d797f83e31 --- /dev/null +++ b/.rhel-prod/teardown @@ -0,0 +1,4 @@ +#!/bin/bash +docker container stop $(docker container ls -aq) || true +docker container rm $(docker container ls -aq) || true +docker volume rm $(docker volume ls -q) || true \ No newline at end of file diff --git a/fda-discovery-service/src/main/resources/config.properties b/.rhel-registry/certs/.gitkeep similarity index 100% rename from fda-discovery-service/src/main/resources/config.properties rename to .rhel-registry/certs/.gitkeep diff --git a/.rhel-registry/docker-compose.yml b/.rhel-registry/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..3da6cd5373e583164d4e22f99fd9d6a4c351e352 --- /dev/null +++ b/.rhel-registry/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3.6" + +services: + + fda-registry-service: + restart: on-failure + container_name: fda-registry-service + hostname: fda-registry-service + image: registry:2 + volumes: + - ./certs:/certs + ports: + - "443:443" + - "5000:5000" + environment: + REGISTRY_HTTP_ADDR: 0.0.0.0:443 + REGISTRY_HTTP_TLS_CERTIFICATE: /certs/fullchain.pem + REGISTRY_HTTP_TLS_KEY: /certs/privkey.pem diff --git a/.rhel-registry/install_cert b/.rhel-registry/install_cert new file mode 100755 index 0000000000000000000000000000000000000000..c5c58224e65052434affa28dda8b9bf46b2091a4 --- /dev/null +++ b/.rhel-registry/install_cert @@ -0,0 +1,20 @@ +#!/bin/bash +CA_PATH="/etc/letsencrypt/live/docker.ossdip.at" +CERT_PATH="./.rhel-registry/certs" +USER="rocky" + +if [ "$ENV" != "prod" ]; then + echo "WARN: environment must be prod" + exit 0 +fi + +sudo certbot certonly --standalone --preferred-challenges http -d docker.ossdip.at \ + -m martin.weise@tuwien.ac.at --agree-tos --keep-until-expiring + +sudo cp "${CA_PATH}/privkey.pem" "${CERT_PATH}" +sudo cp "${CA_PATH}/fullchain.pem" "${CERT_PATH}" + +mkdir -p "${CERT_PATH}" +sudo chown -R "${USER}:docker" "${CERT_PATH}" + +ls -la "${CERT_PATH}" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..856aa3cbb489e77fb952f9099bee50f5d9694ebc --- /dev/null +++ b/Makefile @@ -0,0 +1,175 @@ +REGISTRY=docker.ossdip.at + +all: + +config-backend: + ./.rhel-prod/install_cert + +config-registry: + ./.rhel-registry/install_cert + +config-frontend: + ./.gitlab-ci/frontend/install_cert + +config-docker: + docker image pull -q postgres:13.4-alpine || true > /dev/null + docker image pull -q mysql:8.0 || true > /dev/null + docker image pull -q mariadb:10.5 || true > /dev/null + docker image pull -q rabbitmq:3-alpine || true > /dev/null + +config: config-backend config-docker config-frontend + +build-backend-metadata: + mvn -f ./fda-metadata-db/pom.xml clean install + +build-backend-authentication: + mvn -f ./fda-authentication-service/pom.xml clean package -DskipTests + +build-backend-citation: + mvn -f ./fda-citation-service/pom.xml clean package -DskipTests + +build-backend-container: + mvn -f ./fda-container-service/pom.xml clean package -DskipTests + +build-backend-database: + mvn -f ./fda-database-service/pom.xml clean package -DskipTests + +build-backend-discovery: + mvn -f ./fda-discovery-service/pom.xml clean package -DskipTests + +build-backend-gateway: + mvn -f ./fda-gateway-service/pom.xml clean package -DskipTests + +build-backend-query: + mvn -f ./fda-query-service/pom.xml clean package -DskipTests + +build-backend-table: + mvn -f ./fda-table-service/pom.xml clean package -DskipTests + +build-backend: build-backend-metadata build-backend-authentication build-backend-citation build-backend-container build-backend-database build-backend-discovery build-backend-gateway build-backend-query build-backend-table + +build-docker: config-docker + docker-compose build fda-metadata-db + docker-compose build + +build-frontend: + npm --prefix ./fda-ui install + npm --prefix ./fda-ui run build + +build: clean build-backend build-frontend build-docker + +test-backend: test-backend-auth test-backend-citation test-backend-container test-backend-database test-backend-discovery test-backend-gateway test-backend-query test-backend-table + +test-backend-auth: + mvn -f ./fda-authentication-service/pom.xml clean test verify + +test-backend-citation: config-docker + mvn -f ./fda-citation-service/pom.xml clean test verify + +test-backend-container: config-docker + mvn -f ./fda-container-service/pom.xml clean test verify + +test-backend-database: config-docker + mvn -f ./fda-database-service/pom.xml clean test verify + +test-backend-discovery: + mvn -f ./fda-discovery-service/pom.xml clean test verify + +test-backend-gateway: + mvn -f ./fda-gateway-service/pom.xml clean test verify + +test-backend-query: config-docker + mvn -f ./fda-query-service/pom.xml clean test verify + +test-backend-table: config-docker + mvn -f ./fda-table-service/pom.xml clean test verify + +test-frontend: clean build-frontend + npm --prefix ./fda-ui install + docker-compose up -d + npm --prefix ./fda-ui run test + +test: test-backend test-frontend + +run-backend: + docker-compose up -d fda-container-service fda-database-service fda-query-service fda-table-service fda-authentication-service + +run-frontend: + docker-compose up -d fda-ui + +run: + docker-compose up -d + +run-sandbox: + docker-compose -f docker-compose.prod.yml up -d + +deploy-registry: config-registry + docker-compose -f ./.rhel-registry/docker-compose.yml up -d + +registry-stable-tag: config build test + docker tag fda-metadata-db:latest ${REGISTRY}/fda-metadata-db + docker tag fda-authentication-service:latest ${REGISTRY}/fda-authentication-service + docker tag fda-broker-service:latest ${REGISTRY}/fda-broker-service + docker tag fda-citation-service:latest ${REGISTRY}/fda-citation-service + docker tag fda-container-service:latest ${REGISTRY}/fda-container-service + docker tag fda-database-service:latest ${REGISTRY}/fda-database-service + docker tag fda-discovery-service:latest ${REGISTRY}/fda-discovery-service + docker tag fda-gateway-service:latest ${REGISTRY}/fda-gateway-service + docker tag fda-query-service:latest ${REGISTRY}/fda-query-service + docker tag fda-table-service:latest ${REGISTRY}/fda-table-service + +registry-stable-push: registry-stable-tag registry-stable-tag + docker push ${REGISTRY}/fda-metadata-db + docker push ${REGISTRY}/fda-authentication-service + docker push ${REGISTRY}/fda-broker-service + docker push ${REGISTRY}/fda-citation-service + docker push ${REGISTRY}/fda-container-service + docker push ${REGISTRY}/fda-database-service + docker push ${REGISTRY}/fda-discovery-service + docker push ${REGISTRY}/fda-query-service + docker push ${REGISTRY}/fda-table-service + +registry-stable: registry-stable-tag registry-stable-push + +registry-staging-tag: config build test + docker tag fda-metadata-db:staging ${REGISTRY}/fda-metadata-db + docker tag fda-authentication-service:staging ${REGISTRY}/fda-authentication-service + docker tag fda-broker-service:staging ${REGISTRY}/fda-broker-service + docker tag fda-citation-service:staging ${REGISTRY}/fda-citation-service + docker tag fda-container-service:staging ${REGISTRY}/fda-container-service + docker tag fda-database-service:staging ${REGISTRY}/fda-database-service + docker tag fda-discovery-service:staging ${REGISTRY}/fda-discovery-service + docker tag fda-gateway-service:staging ${REGISTRY}/fda-gateway-service + docker tag fda-query-service:staging ${REGISTRY}/fda-query-service + docker tag fda-table-service:staging ${REGISTRY}/fda-table-service + +registry-staging-push: registry-staging-tag registry-staging-tag + docker push ${REGISTRY}/fda-metadata-db + docker push ${REGISTRY}/fda-authentication-service + docker push ${REGISTRY}/fda-broker-service + docker push ${REGISTRY}/fda-citation-service + docker push ${REGISTRY}/fda-container-service + docker push ${REGISTRY}/fda-database-service + docker push ${REGISTRY}/fda-discovery-service + docker push ${REGISTRY}/fda-query-service + docker push ${REGISTRY}/fda-table-service + +registry-staging: registry-staging-tag registry-staging-push + +logs: + docker-compose -f docker-compose.prod.yml logs + +clean: + docker-compose down + docker volume rm fda-services_fda-metadata-db-data || true + +teardown: + ./.rhel-prod/teardown + +re-deploy: teardown deploy-staging + +deploy-stable: registry-stable + ENV=prod NGINX_PORT=443 ./.gitlab-ci/deploy + +deploy-staging: registry-staging + ENV=prod NGINX_PORT=443 ./.gitlab-ci/deploy diff --git a/README.md b/README.md index 011a8f124c5d5819f157609bbc8b3ad5bff3ac42..bc60fe11da0b182c95d48a5b84da2e18efbb7084 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,43 @@ [](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/commits/master) [](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/commits/master) -[](http://creativecommons.org/licenses/by/4.0/) +[](http://creativecommons.org/licenses/by/4.0/) # FAIR Data Austria Database Repository -## Install +## Build -Obtain the newest +Local development minimum requirements: -## Build +- Ubuntu 18.04 LTS (Rocky Linux is also supported) +- Apache Maven 3.0.0 +- OpenJDK 11.0.0 +- Docker Engine 20.10.0 +- Docker Compose 1.28.0 Everything is handled by compose, just build it by running: ```bash docker-compose build ``` -Local development minimum requirements: -- Ubuntu 18.04 LTS (RPM-based operating systems are also tested) -- Apache Maven 3.0.0 -- OpenJDK 11.0.0 +## Run + +To use the citation service you need to provide a +[Zenodo API token](https://zenodo.org/account/settings/applications/tokens/new/). Create a `.env` file at the project +root. A sample file is available at `.env.example` + +```bash +ZENODO_API_KEY= +API=http://fda-gateway-service:9095 +``` + +Add to your `/etc/hosts` for executing the tests: + +```bash +172.29.0.6 fda-gateway-service +``` + +## Development The backend endpoints are accessible in the browser: @@ -39,16 +57,7 @@ Other: - [Discovery Endpoint](http://localhost:9090/) (Eureka) - [Gateway Endpoint](http://localhost:9095/swagger-ui/) (Webflux) -## Deployment - -Local deployment minimum versions: - -- Docker Engine 20.10.0 -- Docker Compose 1.28.0 - -## Deployment - -The pipeline is set-up to build and test all commits. A commit to dev or master branch triggers additional jobs. +## Contribute Contributions are always welcome and encouraged, simply fork the repository and contact [Andreas Rauber](http://www.ifs.tuwien.ac.at/~andi/). diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000000000000000000000000000000000000..5b5a37ffb8653f474a68c219674769776dc88405 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,304 @@ +version: "3.6" + +volumes: + fda-metadata-db-data: + fda-broker-service-data: + +networks: + fda-public: + name: fda-public + driver: bridge + ipam: + config: + - subnet: 172.29.0.0/16 + driver_opts: + com.docker.network.driver.mtu: 1450 + fda-userdb: + name: fda-userdb + driver: bridge + ipam: + config: + - subnet: 172.28.0.0/16 + driver_opts: + com.docker.network.driver.mtu: 1450 + +services: + + fda-metadata-db: + restart: on-failure + container_name: fda-metadata-db + hostname: fda-metadata-db + build: ./fda-metadata-db + image: fda-metadata-db + networks: + - fda-public + volumes: + - fda-metadata-db-data:/var/lib/postgresql/data + ports: + - "5432:5432" + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: fda + + fda-discovery-service: + restart: on-failure + container_name: fda-discovery-service + hostname: fda-discovery-service + build: ./fda-discovery-service + image: fda-discovery-service + networks: + - fda-public + environment: + SPRING_PROFILES_ACTIVE: docker + ports: + - "9090:9090" + + fda-gateway-service: + restart: on-failure + container_name: fda-gateway-service + hostname: fda-gateway-service + build: ./fda-gateway-service + image: fda-gateway-service + networks: + fda-public: + aliases: + - fda-gateway-service + environment: + SPRING_PROFILES_ACTIVE: docker + ports: + - "9095:9095" + depends_on: + fda-container-service: + condition: service_healthy + fda-database-service: + condition: service_healthy + fda-table-service: + condition: service_healthy + fda-query-service: + condition: service_healthy + logging: + driver: json-file + + fda-database-service: + restart: on-failure + container_name: fda-database-service + hostname: fda-database-service + build: ./fda-database-service + image: fda-database-service + networks: + - fda-userdb + - fda-public + environment: + SPRING_PROFILES_ACTIVE: docker,seeder,sandbox + ports: + - "9092:9092" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + fda-discovery-service: + condition: service_healthy + fda-broker-service: + condition: service_healthy + fda-metadata-db: + condition: service_healthy + fda-container-service: + condition: service_healthy + logging: + driver: json-file + + fda-container-service: + restart: on-failure + container_name: fda-container-service + hostname: fda-container-service + build: ./fda-container-service + image: fda-container-service + networks: + - fda-public + environment: + SPRING_PROFILES_ACTIVE: docker,seeder,sandbox + ports: + - "9091:9091" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + fda-discovery-service: + condition: service_healthy + fda-metadata-db: + condition: service_healthy + logging: + driver: json-file + +# fda-authentication-service: +# restart: on-failure +# container_name: fda-authentication-service +# hostname: fda-authentication-service +# build: ./fda-authentication-service +# image: fda-authentication-service +# networks: +# - fda-public +# volumes: +# - /tmp:/tmp +# environment: +# SERVER_NAME: dbrepo.local +# SPRING_PROFILES_ACTIVE: docker +# KEY_STORE_PASSWORD: ${KEY_STORE_PASSWORD} +# ports: +# - "9097:9097" +# depends_on: +# fda-discovery-service: +# condition: service_healthy +# logging: +# driver: json-file + + fda-query-service: + restart: on-failure + container_name: fda-query-service + hostname: fda-query-service + build: ./fda-query-service + image: fda-query-service + networks: + - fda-public + - fda-userdb + environment: + SPRING_PROFILES_ACTIVE: docker + ports: + - "9093:9093" + volumes: + - /tmp:/tmp + depends_on: + fda-discovery-service: + condition: service_healthy + fda-container-service: + condition: service_healthy + fda-metadata-db: + condition: service_healthy + logging: + driver: json-file + + fda-table-service: + restart: on-failure + container_name: fda-table-service + hostname: fda-table-service + build: ./fda-table-service + image: fda-table-service + networks: + - fda-public + - fda-userdb + environment: + SPRING_PROFILES_ACTIVE: docker + multipart.location: /tmp + ports: + - "9094:9094" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /tmp:/tmp + depends_on: + fda-metadata-db: + condition: service_healthy + fda-discovery-service: + condition: service_healthy + fda-broker-service: + condition: service_healthy + fda-database-service: + condition: service_healthy + +# fda-citation-service: +# restart: on-failure +# container_name: fda-citation-service +# hostname: fda-citation-service +# build: ./fda-citation-service +# image: fda-citation-service +# networks: +# - fda-public +# environment: +# SPRING_PROFILES_ACTIVE: docker +# ZENODO_API_KEY: "${ZENODO_API_KEY}" +# ports: +# - "9096:9096" +# depends_on: +# fda-metadata-db: +# condition: service_healthy +# fda-discovery-service: +# condition: service_healthy +# fda-table-service: +# condition: service_healthy + + fda-analyse-service: + restart: on-failure + container_name: fda-analyse-service + hostname: fda-analyse-service + build: ./fda-analyse-service + image: fda-analyse-service + networks: + - fda-public + - fda-userdb + command: sh -c "/wait && flask run" # docker-compose should not test the implementation + environment: + EUREKA_SERVER: http://fda-discovery-service:9090/eureka/ + ports: + - "5000:5000" + volumes: + - /tmp:/tmp + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + fda-discovery-service: + condition: service_healthy + fda-database-service: + condition: service_healthy + logging: + driver: json-file + + fda-broker-service: + restart: on-failure + container_name: fda-broker-service + hostname: fda-broker-service + build: ./fda-broker-service + image: fda-broker-service + networks: + - fda-public + ports: + - "5672:5672" + - "15672:15672" + volumes: + - fda-broker-service-data:/var/lib/rabbitmq/ + + fda-search-service: + restart: always + container_name: fda-search-service + hostname: fda-search-service + image: elasticsearch:7.13.4 + networks: + - fda-public + environment: + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + - logger.level=WARN + depends_on: + fda-discovery-service: + condition: service_healthy + fda-table-service: + condition: service_healthy + ports: + - "9200:9200" + - "9600:9600" + + fda-ui: + restart: on-failure + container_name: fda-ui + hostname: fda-ui + build: ./fda-ui + image: fda-ui + networks: + - fda-public + ports: + - "443:3000" + volumes: + - "./fda-ui/.prod:/certs" + depends_on: + fda-gateway-service: + condition: service_healthy + environment: + HOST: 0.0.0.0 + API: http://fda-gateway-service:9095 + SECURE: https diff --git a/docker-compose.yml b/docker-compose.yml index 0db075af6ce3bccd46a9daee77c1625632be4572..e2214ac2a2f97b026b5b2d924e16bf9aba61db30 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,12 +11,16 @@ networks: ipam: config: - subnet: 172.29.0.0/16 + driver_opts: + com.docker.network.driver.mtu: 1450 fda-userdb: name: fda-userdb driver: bridge ipam: config: - subnet: 172.28.0.0/16 + driver_opts: + com.docker.network.driver.mtu: 1450 services: @@ -31,7 +35,7 @@ services: volumes: - fda-metadata-db-data:/var/lib/postgresql/data ports: - - 5432:5432 + - "5432:5432" environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres @@ -48,7 +52,7 @@ services: environment: SPRING_PROFILES_ACTIVE: docker ports: - - 9090:9090 + - "9090:9090" fda-gateway-service: restart: on-failure @@ -57,13 +61,21 @@ services: build: ./fda-gateway-service image: fda-gateway-service networks: - - fda-public + fda-public: + aliases: + - fda-gateway-service environment: SPRING_PROFILES_ACTIVE: docker ports: - - 9095:9095 + - "9095:9095" depends_on: - fda-discovery-service: + fda-container-service: + condition: service_healthy + fda-database-service: + condition: service_healthy + fda-table-service: + condition: service_healthy + fda-query-service: condition: service_healthy logging: driver: json-file @@ -78,9 +90,9 @@ services: - fda-userdb - fda-public environment: - SPRING_PROFILES_ACTIVE: docker + SPRING_PROFILES_ACTIVE: docker,seeder ports: - - 9092:9092 + - "9092:9092" volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: @@ -90,6 +102,8 @@ services: condition: service_healthy fda-metadata-db: condition: service_healthy + fda-container-service: + condition: service_healthy logging: driver: json-file @@ -102,9 +116,9 @@ services: networks: - fda-public environment: - SPRING_PROFILES_ACTIVE: docker,seed + SPRING_PROFILES_ACTIVE: docker,seeder ports: - - 9091:9091 + - "9091:9091" volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: @@ -115,6 +129,28 @@ services: logging: driver: json-file +# fda-authentication-service: +# restart: on-failure +# container_name: fda-authentication-service +# hostname: fda-authentication-service +# build: ./fda-authentication-service +# image: fda-authentication-service +# networks: +# - fda-public +# volumes: +# - /tmp:/tmp +# environment: +# SERVER_NAME: dbrepo.local +# SPRING_PROFILES_ACTIVE: docker +# KEY_STORE_PASSWORD: ${KEY_STORE_PASSWORD} +# ports: +# - "9097:9097" +# depends_on: +# fda-discovery-service: +# condition: service_healthy +# logging: +# driver: json-file + fda-query-service: restart: on-failure container_name: fda-query-service @@ -127,7 +163,7 @@ services: environment: SPRING_PROFILES_ACTIVE: docker ports: - - 9093:9093 + - "9093:9093" volumes: - /tmp:/tmp depends_on: @@ -153,7 +189,7 @@ services: SPRING_PROFILES_ACTIVE: docker multipart.location: /tmp ports: - - 9094:9094 + - "9094:9094" volumes: - /var/run/docker.sock:/var/run/docker.sock - /tmp:/tmp @@ -164,27 +200,31 @@ services: condition: service_healthy fda-broker-service: condition: service_healthy - - fda-citation-service: - restart: on-failure - container_name: fda-citation-service - hostname: fda-citation-service - build: ./fda-citation-service - image: fda-citation-service - networks: - - fda-public - environment: - SPRING_PROFILES_ACTIVE: docker - ZENODO_API_KEY: "${ZENODO_API_KEY}" - ports: - - 9096:9096 - depends_on: - fda-metadata-db: - condition: service_healthy - fda-discovery-service: - condition: service_healthy - fda-table-service: + fda-database-service: condition: service_healthy + fda-search-service: + condition: service_started + +# fda-citation-service: +# restart: on-failure +# container_name: fda-citation-service +# hostname: fda-citation-service +# build: ./fda-citation-service +# image: fda-citation-service +# networks: +# - fda-public +# environment: +# SPRING_PROFILES_ACTIVE: docker +# ZENODO_API_KEY: "${ZENODO_API_KEY}" +# ports: +# - "9096:9096" +# depends_on: +# fda-metadata-db: +# condition: service_healthy +# fda-discovery-service: +# condition: service_healthy +# fda-table-service: +# condition: service_healthy fda-analyse-service: restart: on-failure @@ -197,9 +237,9 @@ services: - fda-userdb command: sh -c "/wait && flask run" # docker-compose should not test the implementation environment: - EUREKA_SERVER: http://fda-discovery-service:9090/eureka + EUREKA_SERVER: http://fda-discovery-service:9090/eureka/ ports: - - 5000:5000 + - "5000:5000" volumes: - /tmp:/tmp - /var/run/docker.sock:/var/run/docker.sock @@ -220,8 +260,8 @@ services: networks: - fda-public ports: - - 5672:5672 - - 15672:15672 + - "5672:5672" + - "15672:15672" volumes: - fda-broker-service-data:/var/lib/rabbitmq/ @@ -237,6 +277,9 @@ services: - discovery.type=single-node - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - logger.level=WARN + depends_on: + fda-discovery-service: + condition: service_healthy ports: - 9200:9200 - 9600:9600 @@ -252,24 +295,12 @@ services: networks: - fda-public ports: - - 3000:3000 + - "3000:3000" volumes: - - /tmp:/tmp + - "./fda-ui/.prod:/certs" depends_on: - fda-discovery-service: - condition: service_healthy - fda-container-service: - condition: service_healthy - fda-table-service: - condition: service_healthy - fda-query-service: - condition: service_healthy - fda-analyse-service: + fda-gateway-service: condition: service_healthy environment: HOST: 0.0.0.0 - API_CONTAINER: http://fda-container-service:9091 - API_IMAGE: http://fda-container-service:9091 - API_DATABASE: http://fda-database-service:9092 - API_TABLES: http://fda-table-service:9094 - API_ANALYSE: http://fda-analyse-service:5000 + API: http://fda-gateway-service:9095 diff --git a/fda-analyse-service/app.py b/fda-analyse-service/app.py index 934a3707df5e81b2a0a20ce1f78bf4f4b816fea0..b3fcc7021ac2b4aea1ef39c85518b3315fc45068 100644 --- a/fda-analyse-service/app.py +++ b/fda-analyse-service/app.py @@ -61,7 +61,7 @@ template = dict( app.json_encoder = LazyJSONEncoder swagger = Swagger(app, config=swagger_config, template=template) -@app.route('/determinedt', methods=["POST"], endpoint='analyze_determinedt') +@app.route('/api/analyse/determinedt', methods=["POST"], endpoint='analyze_determinedt') @swag_from('/as-yml/determinedt.yml') def determinedt(): input_json = request.get_json() @@ -84,7 +84,7 @@ def determinedt(): res = {"success": False, "message": "Unknown error"} return jsonify(res), 200 -@app.route('/determinepk', methods=["POST"], endpoint='analyze_determinepk') +@app.route('/api/analyse/determinepk', methods=["POST"], endpoint='analyze_determinepk') @swag_from('/as-yml/determinepk.yml') def determinepk(): input_json = request.get_json() @@ -99,7 +99,7 @@ def determinepk(): res = {"success": False, "message": "Unknown error"} return jsonify(res), 200 -@app.route('/checkcsv', methods=["POST"], endpoint='analyze_checkcsv') +@app.route('/api/analyse/checkcsv', methods=["POST"], endpoint='analyze_checkcsv') @swag_from('/as-yml/checkcsv.yml') def checkcsv(): input_json = request.get_json() @@ -121,7 +121,7 @@ def checkcsv(): res = {"success": False, "message": "Unknown error"} return jsonify(res), 200 -@app.route('/update_mdb_db', methods=["POST"], endpoint='mdb_update_db') +@app.route('/api/analyse/update_mdb_db', methods=["POST"], endpoint='mdb_update_db') @swag_from('/as-yml/importdb.yml') def importdb(): input_json = request.get_json() @@ -136,7 +136,7 @@ def importdb(): res = {"success": False, "message": "Unknown error"} return jsonify(res), 200 -@app.route('/update_mdb_tbl', methods=["POST"], endpoint='mdb_update_tbl') +@app.route('/api/analyse/update_mdb_tbl', methods=["POST"], endpoint='mdb_update_tbl') @swag_from('/as-yml/importtbl.yml') def importtbl(): input_json = request.get_json() @@ -148,7 +148,7 @@ def importtbl(): res = {"success": False, "message": "Unknown error"} return jsonify(res), 200 -@app.route('/update_mdb_db_ispublic', methods=["POST"], endpoint='mdb_ispublic') +@app.route('/api/analyse/update_mdb_db_ispublic', methods=["POST"], endpoint='mdb_ispublic') @swag_from('/as-yml/updateispub.yml') def updateispublic(): input_json = request.get_json() @@ -161,7 +161,7 @@ def updateispublic(): res = {"success": False, "message": "Unknown error"} return jsonify(res), 200 -@app.route('/update_mdb_columns_num_siunit', methods=["POST"], endpoint='mdb_columns_num') +@app.route('/api/analyse/update_mdb_columns_num_siunit', methods=["POST"], endpoint='mdb_columns_num') @swag_from('/as-yml/updatesiunit.yml') def updatesiunit(): input_json = request.get_json() @@ -176,7 +176,7 @@ def updatesiunit(): res = {"success": False, "message": "Unknown error"} return jsonify(res), 200 -@app.route('/update_mdb_data_provenance', methods=["POST"], endpoint='mdb_update_data_provenance') +@app.route('/api/analyse/update_mdb_data_provenance', methods=["POST"], endpoint='mdb_update_data_provenance') @swag_from('/as-yml/updatedata.yml') def updatesdataprovenance(): input_json = request.get_json() @@ -189,7 +189,7 @@ def updatesdataprovenance(): res = {"success": False, "message": "Unknown error"} return jsonify(res), 200 -#@app.route('/insert_mdb_col', methods=["POST"], endpoint='mdb_insert_col') +#@app.route('/api/analyse/insert_mdb_col', methods=["POST"], endpoint='mdb_insert_col') #@swag_from('/as-yml/importcol.yml') #def importcol(): # input_json = request.get_json() @@ -202,7 +202,7 @@ def updatesdataprovenance(): # res = {"success": False, "message": "Unknown error"} # return jsonify(res), 200 -@app.route('/update_mdb_col', methods=["POST"], endpoint='mdb_update_col') +@app.route('/api/analyse/update_mdb_col', methods=["POST"], endpoint='mdb_update_col') @swag_from('/as-yml/updatecol.yml') def updatecol(): input_json = request.get_json() @@ -219,6 +219,8 @@ def updatecol(): rest_server_port = 5000 eureka_client.init(eureka_server=os.getenv('EUREKA_SERVER', 'http://localhost:9090/eureka/'), app_name="fda-analyse-service", + instance_ip="fda-analyse-service", + instance_host="fda-analyse-service", instance_port=rest_server_port) if __name__ == '__main__': diff --git a/fda-authentication-service/.gitignore b/fda-authentication-service/.gitignore index 862815a0c53788c70306117181f3ab764b56597b..caf6b59191b85bda2b8cd37128c2593625d286f5 100644 --- a/fda-authentication-service/.gitignore +++ b/fda-authentication-service/.gitignore @@ -1,2 +1,39 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### Generated ### ready +*.p12 *.key +*.pem + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/fda-authentication-service/.mvn/wrapper/MavenWrapperDownloader.java b/fda-authentication-service/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000000000000000000000000000000000..a45eb6ba269cd38f8965cef786729790945d9537 --- /dev/null +++ b/fda-authentication-service/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,118 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/fda-authentication-service/.mvn/wrapper/maven-wrapper.jar b/fda-authentication-service/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 Binary files /dev/null and b/fda-authentication-service/.mvn/wrapper/maven-wrapper.jar differ diff --git a/fda-authentication-service/.mvn/wrapper/maven-wrapper.properties b/fda-authentication-service/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..642d572ce90e5085986bdd9c9204b9404f028084 --- /dev/null +++ b/fda-authentication-service/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/fda-authentication-service/Dockerfile b/fda-authentication-service/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..43605f434eb13de8f638218c7ffc7ad16b3ec1d7 --- /dev/null +++ b/fda-authentication-service/Dockerfile @@ -0,0 +1,35 @@ +###### FIRST STAGE ###### +FROM fda-metadata-db:latest as dependency +MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> + +###### SECOND STAGE ###### +FROM maven:slim as build + +COPY ./pom.xml ./ + +RUN mvn -fn -B dependency:go-offline > /dev/null + +COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tuwien + +COPY ./rest-service ./rest-service +COPY ./services ./services +COPY ./report ./report + +ARG CI_JOB_STAGE + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null + +###### THIRD STAGE ###### +FROM openjdk:11-jre-slim as runtime + +VOLUME /tmp + +COPY --from=build ./rest-service/target/rest-service-*.jar ./rest-service.jar +COPY ./service_ready /usr/bin + +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready + +EXPOSE 9091 + +ENTRYPOINT ["java", "-jar", "./rest-service.jar"] diff --git a/fda-authentication-service/README.md b/fda-authentication-service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..94b71d2f46c71cb10dce42c1265895949889fe74 --- /dev/null +++ b/fda-authentication-service/README.md @@ -0,0 +1,27 @@ +# Authentication Service + +Uses SAML2.0 + +## Run + +The container needs the environment variable set with the Key Store password, put it in your `~/.bashrc`: + +```bash +export KEY_STORE_PASSWORD=... +``` + +or for fish in your `~/.config/fish/config.fish`: + +```fish +set KEY_STORE_PASSWORD "..." +``` + +## Key Store + +The key store is a secure container that contains the SSL/TLS certificate: + +1. Let's Encrypt private key for `dbrepo.ossdip.at` with alias `1` + +## Development + +Context metadata for IdP: `http://localhost:9097/saml/metadata` \ No newline at end of file diff --git a/fda-authentication-service/mvnw b/fda-authentication-service/mvnw new file mode 100755 index 0000000000000000000000000000000000000000..a16b5431b4c3cab50323a3f558003fd0abd87dad --- /dev/null +++ b/fda-authentication-service/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/fda-authentication-service/mvnw.cmd b/fda-authentication-service/mvnw.cmd new file mode 100644 index 0000000000000000000000000000000000000000..c8d43372c986d97911cdc21bd87e0cbe3d83bdda --- /dev/null +++ b/fda-authentication-service/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/fda-authentication-service/pom.xml b/fda-authentication-service/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..c5d0c26a1c948db651b74c7bbf95d24a02a0ea2f --- /dev/null +++ b/fda-authentication-service/pom.xml @@ -0,0 +1,193 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.3.10.RELEASE</version> + </parent> + + <groupId>at.tuwien</groupId> + <artifactId>fda-authentication-service</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>fda-authentication-service</name> + <description>Demo project for Spring Boot</description> + + <packaging>pom</packaging> + <modules> + <module>rest-service</module> + <module>services</module> + <module>report</module> + </modules> + + <properties> + <java.version>11</java.version> + <spring-cloud.version>3.0.1</spring-cloud.version> + <mapstruct.version>1.4.2.Final</mapstruct.version> + <swagger.version>2.1.7</swagger.version> + <springfox.version>3.0.0</springfox.version> + <jacoco.version>0.8.7</jacoco.version> + <spring-saml.version>1.0.10.RELEASE</spring-saml.version> + <javax-rs.version>2.1.1</javax-rs.version> + <opensaml.version>2.6.4</opensaml.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-validation</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-bootstrap</artifactId> + <version>${spring-cloud.version}</version> + </dependency> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + <version>${javax-rs.version}</version> + </dependency> + <!-- SAML --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security.extensions</groupId> + <artifactId>spring-security-saml2-core</artifactId> + <version>${spring-saml.version}</version> + <exclusions> + <!-- override since 2.6.6 is not available anymore --> + <exclusion> + <groupId>org.opensaml</groupId> + <artifactId>opensaml</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.opensaml</groupId> + <artifactId>opensaml</artifactId> + <version>${opensaml.version}</version> + </dependency> + <dependency> + <groupId>de.dentrassi.crypto</groupId> + <artifactId>pem-keystore</artifactId> + <version>2.2.0</version> + </dependency> + <!-- Entity and API --> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>fda-metadata-db-api</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>fda-metadata-db-entites</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> + <!-- Testing --> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-vintage-engine</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + </dependency> + <!-- IDE --> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + <!-- Mapping --> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct.version}</version> + <optional>true</optional><!-- IntelliJ --> + </dependency> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct</artifactId> + <version>${mapstruct.version}</version> + </dependency> + <!-- Swagger --> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-boot-starter</artifactId> + <version>${springfox.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${springfox.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-spring-web</artifactId> + <version>${springfox.version}</version> + </dependency> + <dependency> + <groupId>io.swagger.core.v3</groupId> + <artifactId>swagger-annotations</artifactId> + <version>${swagger.version}</version> + </dependency> + <dependency> + <groupId>io.swagger.core.v3</groupId> + <artifactId>swagger-models</artifactId> + <version>${swagger.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <configuration> + <excludes> + <exclude>at/tuwien/utils/**/*</exclude> + <exclude>at/tuwien/seeder/**/*</exclude> + <exclude>at/tuwien/mapper/**/*</exclude> + <exclude>at/tuwien/exception/**/*</exclude> + <exclude>at/tuwien/config/**/*</exclude> + <exclude>**/FdaContainerManagingApplication.class</exclude> + </excludes> + </configuration> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>report</id> + <phase>verify</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/fda-authentication-service/report/pom.xml b/fda-authentication-service/report/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..30e855d217b850a8559b3df28e8fc77e2c5fa0ae --- /dev/null +++ b/fda-authentication-service/report/pom.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.tuwien</groupId> + <artifactId>fda-authentication-service</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>report</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>fda-authentication-service-report</name> + <description> + This module is only intended for the pipeline coverage report. See the detailed report in the + respective modules + </description> + + <properties> + <jacoco.version>0.8.7</jacoco.version> + </properties> + + <dependencies> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>rest-service</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>services</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <executions> + <execution> + <id>report-aggregate</id> + <phase>verify</phase> + <goals> + <goal>report-aggregate</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-authentication-service/rest-service/pom.xml b/fda-authentication-service/rest-service/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ad8b781613e5e7243c1ec6fc13661b6f734803f3 --- /dev/null +++ b/fda-authentication-service/rest-service/pom.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.tuwien</groupId> + <artifactId>fda-authentication-service</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>rest-service</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>fda-authentication-service-rest-service</name> + + <properties> + <jacoco.version>0.8.7</jacoco.version> + </properties> + + <dependencies> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>services</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal><!-- to make it exuteable with $ java -jar ./app.jar --> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-authentication-service/rest-service/src/main/java/at/tuwien/FdaAuthenticationServiceApplication.java b/fda-authentication-service/rest-service/src/main/java/at/tuwien/FdaAuthenticationServiceApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..9ee4a655b6ef187a92caba9d225d3788e0563de2 --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/java/at/tuwien/FdaAuthenticationServiceApplication.java @@ -0,0 +1,21 @@ +package at.tuwien; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import springfox.documentation.oas.annotations.EnableOpenApi; + +@EnableOpenApi +@EnableWebSecurity +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) +public class FdaAuthenticationServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(FdaAuthenticationServiceApplication.class, args); + } + +} diff --git a/fda-authentication-service/rest-service/src/main/java/at/tuwien/config/SamlConfig.java b/fda-authentication-service/rest-service/src/main/java/at/tuwien/config/SamlConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..378fa0dc92c56cc6e224661cd17e5b47a62f5a74 --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/java/at/tuwien/config/SamlConfig.java @@ -0,0 +1,305 @@ +package at.tuwien.config; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.velocity.app.VelocityEngine; +import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; +import org.opensaml.saml2.metadata.provider.MetadataProvider; +import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.xml.parse.StaticBasicParserPool; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.saml.*; +import org.springframework.security.saml.context.SAMLContextProvider; +import org.springframework.security.saml.context.SAMLContextProviderLB; +import org.springframework.security.saml.key.JKSKeyManager; +import org.springframework.security.saml.key.KeyManager; +import org.springframework.security.saml.log.SAMLDefaultLogger; +import org.springframework.security.saml.log.SAMLLogger; +import org.springframework.security.saml.metadata.*; +import org.springframework.security.saml.parser.ParserPoolHolder; +import org.springframework.security.saml.processor.HTTPPostBinding; +import org.springframework.security.saml.processor.HTTPRedirectDeflateBinding; +import org.springframework.security.saml.processor.SAMLBinding; +import org.springframework.security.saml.processor.SAMLProcessorImpl; +import org.springframework.security.saml.util.VelocityFactory; +import org.springframework.security.saml.websso.*; +import org.springframework.security.web.*; +import org.springframework.security.web.access.channel.ChannelProcessingFilter; +import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(securedEnabled = true) +public class SamlConfig extends WebSecurityConfigurerAdapter { + + @Value("${fda.idp.metadata}") + private String idpProviderMetadata; + + @Value("${fda.base-url}") + private String baseUrl; + + @Value("${server.ssl.key-store}") + private String samlKeystoreLocation; + + @Value("${server.name}") + private String serverName; + + @Value("${server.port}") + private String serverPort; + + @Value("${server.ssl.key-alias}") + private String samlKeystoreAlias; + + @Value("${server.ssl.key-store-password}") + private String samlKeystorePassword; + + @Bean + public static SAMLBootstrap sAMLBootstrap() { + return new SAMLBootstrap(); + } + + @Bean + public VelocityEngine velocityEngine() { + return VelocityFactory.getEngine(); + } + + @Bean(initMethod = "initialize") + public StaticBasicParserPool parserPool() { + return new StaticBasicParserPool(); + } + + @Bean(name = "parserPoolHolder") + public ParserPoolHolder parserPoolHolder() { + return new ParserPoolHolder(); + } + + @Bean + public MultiThreadedHttpConnectionManager multiThreadedHttpConnectionManager() { + return new MultiThreadedHttpConnectionManager(); + } + + @Bean + public HttpClient httpClient() { + return new HttpClient(multiThreadedHttpConnectionManager()); + } + + @Bean + public SAMLAuthenticationProvider samlAuthenticationProvider() { + final SAMLAuthenticationProvider samlAuthenticationProvider = new SAMLAuthenticationProvider(); + samlAuthenticationProvider.setForcePrincipalAsString(false); + return samlAuthenticationProvider; + } + + @Bean + public WebSSOProfileConsumer webSSOprofileConsumer() { + return new WebSSOProfileConsumerImpl(); + } + + @Bean + public WebSSOProfileConsumerHoKImpl hokWebSSOprofileConsumer() { + return new WebSSOProfileConsumerHoKImpl(); + } + + @Bean + public WebSSOProfile webSSOprofile() { + return new WebSSOProfileImpl(); + } + + @Bean + public SingleLogoutProfile logoutProfile() { + return new SingleLogoutProfileImpl(); + } + + @Bean + public WebSSOProfileOptions defaultWebSSOProfileOptions() { + final WebSSOProfileOptions webSSOProfileOptions = new WebSSOProfileOptions(); + webSSOProfileOptions.setIncludeScoping(false); + return webSSOProfileOptions; + } + + @Bean + public SAMLEntryPoint samlEntryPoint() { + final SAMLEntryPoint samlEntryPoint = new SAMLEntryPoint(); + samlEntryPoint.setDefaultProfileOptions(defaultWebSSOProfileOptions()); + return samlEntryPoint; + } + + @Bean + public ExtendedMetadata extendedMetadata() { + final ExtendedMetadata extendedMetadata = new ExtendedMetadata(); + extendedMetadata.setIdpDiscoveryEnabled(true); + extendedMetadata.setSignMetadata(false); + return extendedMetadata; + } + + @Bean + public SAMLDiscovery samlIDPDiscovery() { + return new SAMLDiscovery(); + } + + @Bean + public ExtendedMetadataDelegate extendedMetadataProvider() throws MetadataProviderException, IOException { + ExtendedMetadataDelegate extendedMetadataDelegate = new ExtendedMetadataDelegate(pivotalTestMetadataProvider(), + extendedMetadata()); + extendedMetadataDelegate.setMetadataTrustCheck(true); + extendedMetadataDelegate.setMetadataRequireSignature(false); + return extendedMetadataDelegate; + } + + @Bean + public CachingMetadataManager metadata(ExtendedMetadataDelegate extendedMetadataDelegate) throws MetadataProviderException { + final List<MetadataProvider> providers = new ArrayList<>(); + providers.add(extendedMetadataDelegate); + return new CachingMetadataManager(providers); + } + + @Bean + public MetadataDisplayFilter metadataDisplayFilter() { + return new MetadataDisplayFilter(); + } + + @Bean + public SAMLProcessingFilter samlWebSSOProcessingFilter() throws Exception { + final SAMLProcessingFilter samlWebSSOProcessingFilter = new SAMLProcessingFilter(); + samlWebSSOProcessingFilter.setAuthenticationManager(authenticationManager()); + return samlWebSSOProcessingFilter; + } + + @Bean + public MetadataGeneratorFilter metadataGeneratorFilter() { + return new MetadataGeneratorFilter(metadataGenerator()); + } + + @Bean + public SimpleUrlLogoutSuccessHandler successLogoutHandler() { + final SimpleUrlLogoutSuccessHandler successLogoutHandler = new SimpleUrlLogoutSuccessHandler(); + successLogoutHandler.setDefaultTargetUrl("/"); + return successLogoutHandler; + } + + @Bean + public HTTPPostBinding httpPostBinding() { + return new HTTPPostBinding(parserPool(), velocityEngine()); + } + + @Bean + public HTTPRedirectDeflateBinding httpRedirectDeflateBinding() { + return new HTTPRedirectDeflateBinding(parserPool()); + } + + @Bean + public SAMLProcessorImpl processor() { + final Collection<SAMLBinding> bindings = new ArrayList<>(); + bindings.add(httpRedirectDeflateBinding()); + bindings.add(httpPostBinding()); + return new SAMLProcessorImpl(bindings); + } + + @Bean + public FilterChainProxy samlFilter() throws Exception { + final List<SecurityFilterChain> chains = new ArrayList<>(); + chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"), + samlEntryPoint())); + chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"), + metadataDisplayFilter())); + chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"), + samlWebSSOProcessingFilter())); + chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/discovery/**"), + samlIDPDiscovery())); + return new FilterChainProxy(chains); + } + + @Bean + public SAMLLogger samlLogger() { + return new SAMLDefaultLogger(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.requiresChannel() + .anyRequest().requiresSecure(); + http.httpBasic() + .authenticationEntryPoint(samlEntryPoint()); + http.csrf() + .disable(); + http.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class) + .addFilterAfter(samlFilter(), BasicAuthenticationFilter.class); + /* allow metadata and saml stuff */ + http.authorizeRequests() + .antMatchers("/saml/**").permitAll() + .antMatchers("/health").permitAll() + .antMatchers("/error").permitAll() + .anyRequest().authenticated(); + } + + @Bean + public MetadataProvider pivotalTestMetadataProvider() throws MetadataProviderException, IOException { + final DefaultResourceLoader loader = new DefaultResourceLoader(); + final Resource storeFile = loader.getResource("classpath:saml/sp_metadata.xml"); + final File tuMetadata = storeFile.getFile(); + final FilesystemMetadataProvider provider = new FilesystemMetadataProvider(tuMetadata); + provider.setParserPool(parserPool()); + return provider; + } + + @Bean + public MetadataGenerator metadataGenerator() { + final MetadataGenerator metadataGenerator = new MetadataGenerator(); + metadataGenerator.setEntityId("at:tuwien"); + metadataGenerator.setRequestSigned(false); + metadataGenerator.setExtendedMetadata(extendedMetadata()); + metadataGenerator.setIncludeDiscoveryExtension(false); + metadataGenerator.setKeyManager(keyManager()); + metadataGenerator.setEntityBaseURL(baseUrl); + metadataGenerator.setWantAssertionSigned(false); + return metadataGenerator; + } + + @Bean + public SAMLContextProvider contextProvider() { + final SAMLContextProviderLB contextProvider = new SAMLContextProviderLB(); + contextProvider.setScheme("https"); + contextProvider.setServerName(serverName + ":" + serverPort); + contextProvider.setContextPath("/"); + return contextProvider; + } + + @Bean + public PortMapper portMapper() { + final Map<String, String> portMappings = new HashMap<>(); + portMappings.put(serverPort, serverPort); + final PortMapperImpl portMapper = new PortMapperImpl(); + portMapper.setPortMappings(portMappings); + return portMapper; + } + + @Bean + public KeyManager keyManager() { + final DefaultResourceLoader loader = new DefaultResourceLoader(); + final Resource storeFile = loader.getResource(samlKeystoreLocation); + final Map<String, String> passwords = new HashMap<>(); + passwords.put(samlKeystoreAlias, samlKeystorePassword); + passwords.put("saml", samlKeystorePassword); + return new JKSKeyManager(storeFile, samlKeystorePassword, passwords, samlKeystoreAlias); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(samlAuthenticationProvider()); + } +} \ No newline at end of file diff --git a/fda-authentication-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java b/fda-authentication-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..3b75e9eabbf34ca8cd3f02791705eb9310b6e80e --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java @@ -0,0 +1,38 @@ +package at.tuwien.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.oas.annotations.EnableOpenApi; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +import java.util.Collections; + +@Configuration +@EnableOpenApi +public class SwaggerConfig { + + @Bean + public Docket databaseApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .paths(PathSelectors.ant("/api/**")) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfo("FDA-Authentication-Managing API", + "Service that authenticates agains SAML endpoints", + "1.0", + null, + new Contact("Ao.Univ.Prof. Andreas Rauber", "http://www.ifs.tuwien.ac.at/~andi/", "rauber@ifs.tuwien.ac.at"), + "API license", + null, + Collections.emptyList()); + } + +} diff --git a/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/AuthenticationEndpoint.java b/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/AuthenticationEndpoint.java new file mode 100644 index 0000000000000000000000000000000000000000..6f18b89c8ae13ab63952a205c51f52dba23694d1 --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/AuthenticationEndpoint.java @@ -0,0 +1,22 @@ +package at.tuwien.endpoints; + +import lombok.extern.log4j.Log4j2; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; + +@RestController("/api/auth") +@Log4j2 +public class AuthenticationEndpoint { + + @GetMapping("/") + public String index() { + return "Index"; + } + + @GetMapping("/info") + public ResponseEntity<Object> info(Authentication authentication) { + return ResponseEntity.ok(authentication.getName()); + } + +} \ No newline at end of file diff --git a/fda-authentication-service/rest-service/src/main/resources/application-docker.yml b/fda-authentication-service/rest-service/src/main/resources/application-docker.yml new file mode 100644 index 0000000000000000000000000000000000000000..15fc96eb8cc647830eb920c46bd030895d0b26f7 --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/resources/application-docker.yml @@ -0,0 +1,53 @@ +spring: + main.banner-mode: off + datasource: + url: jdbc:postgresql://fda-metadata-db:5432/fda + driver-class-name: org.postgresql.Driver + username: postgres + password: postgres + jpa: + show-sql: false + database-platform: org.hibernate.dialect.PostgreSQLDialect + hibernate: + ddl-auto: validate + open-in-view: false + application: + name: fda-authentication-service + cloud: + discovery.enabled: false + loadbalancer.ribbon.enabled: false + security: + saml2: + relyingparty: + registration: + tu-saml: + identityprovider: + entity-id: at:tuwien +# signing.credentials: +# - certificate-location: +# private-key-location: + verification.credentials: + - certificate-location: classpath:ssl/tu.cer + singlesignon.url: https://idp.zid.tuwien.ac.at/simplesaml/saml2/idp/SSOService.php + singlesignon.sign-request: false +server: + port: 9097 + name: ${SERVER_NAME} + ssl: + enabled: true + key-alias: 1 + key-store: classpath:ssl/dbrepo.jks + key-store-password: ${KEY_STORE_PASSWORD} + key-store-type: jks +logging: + pattern.console: "%d %highlight(%-5level) %msg%n" + level: + root: warn + at.tuwien.: debug +eureka: + instance.hostname: fda-authentication-service + client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/ +fda: + ready.path: /ready + idp.metadata: https://idp.zid.tuwien.ac.at/saml2 + base-url: https://dbrepo.ossdip.at:9097 \ No newline at end of file diff --git a/fda-authentication-service/rest-service/src/main/resources/application.yml b/fda-authentication-service/rest-service/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..f6a6585597cd4cc19d8984a222089dd02235cab2 --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/resources/application.yml @@ -0,0 +1,53 @@ +spring: + main.banner-mode: off + datasource: + url: jdbc:postgresql://localhost:5432/fda + driver-class-name: org.postgresql.Driver + username: postgres + password: postgres + jpa: + show-sql: false + database-platform: org.hibernate.dialect.PostgreSQLDialect + hibernate: + ddl-auto: validate + open-in-view: false + application: + name: fda-authentication-service + cloud: + discovery.enabled: false + loadbalancer.ribbon.enabled: false + security: + saml2: + relyingparty: + registration: + tu-saml: + identityprovider: + entity-id: at:tuwien +# signing.credentials: +# - certificate-location: +# private-key-location: + verification.credentials: + - certificate-location: classpath:ssl/tu.cer + singlesignon.url: https://idp.zid.tuwien.ac.at/simplesaml/saml2/idp/SSOService.php + singlesignon.sign-request: true +server: + port: 9097 + name: ${SERVER_NAME} + ssl: + enabled: true + key-alias: 1 + key-store: classpath:ssl/dbrepo.jks + key-store-password: ${KEY_STORE_PASSWORD} + key-store-type: jks +logging: + pattern.console: "%d %highlight(%-5level) %msg%n" + level: + root: warn + at.tuwien.: debug +eureka: + instance.hostname: fda-authentication-service + client.serviceUrl.defaultZone: http://localhost:9090/eureka/ +fda: + ready.path: /ready + idp.metadata: https://idp.zid.tuwien.ac.at/saml2 + base-url: https://dbrepo.ossdip.at:9097 \ No newline at end of file diff --git a/fda-authentication-service/rest-service/src/main/resources/bin/install_saml_keys b/fda-authentication-service/rest-service/src/main/resources/bin/install_saml_keys new file mode 100755 index 0000000000000000000000000000000000000000..2ee83f9cfd11ea8a5ab700d17b49e94e0feeaf1c --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/resources/bin/install_saml_keys @@ -0,0 +1,8 @@ +#!/bin/bash +SIGN_KEYS_LOCATION="./rest-service/src/main/resources/saml" + +# CREATE SIGNING KEYS +openssl req -newkey rsa:4096 -new \ + -subj "/C=AT/ST=Vienna/L=Vienna/O=TU Wien/OU=Zentrum für Forschungsdatenmanagement/CN=FAIR Data Austria" \ + -nodes -x509 -days 3650 -keyout "${SIGN_KEYS_LOCATION}/saml_sign_priv.key" \ + -out "${SIGN_KEYS_LOCATION}/saml_sign_public.cer" \ No newline at end of file diff --git a/fda-authentication-service/rest-service/src/main/resources/bin/install_selfsigned_cert b/fda-authentication-service/rest-service/src/main/resources/bin/install_selfsigned_cert new file mode 100755 index 0000000000000000000000000000000000000000..5a71e6a934428d5d7df90d8d6765169bde63a2d8 --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/resources/bin/install_selfsigned_cert @@ -0,0 +1,43 @@ +#!/bin/bash +KEY_STORE_LOCATION="/tmp/dbrepo.p12" +JKS_LOCATION="/tmp/dbrepo.jks" +KEY_STORE_ALIAS="1" +KEY_STORE_PASS="dbrepo" + +SSL_PASS="dbrepo" + +TU_ALIAS="tu" + +SAML_STORE_LOCATION="/tmp/saml.p12" +SAML_ALIAS="saml" +SAML_KEY="/tmp/saml_sign.key" +SAML_CERTIFICATE="/tmp/saml_sign.pem" +SAML_PASS="dbrepo" + +# GENERATE SSL PRIVATE KEY AND PUBLIC KEY IN KEYSTORE +echo "Generate self-signed certificate ..." +keytool -genkey -keyalg RSA -alias "${KEY_STORE_ALIAS}" -storetype PKCS12 \ + -dname "cn=FAIR Data Austria, ou=Zentrum für Forschungsdatenmanagement, o=TU Wien, c=AT, l=Vienna, st=Austria" \ + -keystore "${KEY_STORE_LOCATION}" -storepass "${KEY_STORE_PASS}" -validity 3650 \ + -keysize 4096 > /dev/null 2>&1 + +# CONVERT PKCS12 KEYSTORE TO JKS +echo "Convert to .jks ..." +keytool -importkeystore -srckeystore "${KEY_STORE_LOCATION}" -destkeystore "${JKS_LOCATION}" -srcstoretype PKCS12 \ + -deststoretype jks -srcstorepass "${KEY_STORE_PASS}" -deststorepass "${KEY_STORE_PASS}" \ + -srcalias "${KEY_STORE_ALIAS}" -destalias "${KEY_STORE_ALIAS}" -srckeypass "${SSL_PASS}" \ + -destkeypass "${SSL_PASS}" + +# COMBINE CERTIFICATE AND PRIVATE KEY +echo "Import SAML keys ..." +openssl pkcs12 -export -out "${SAML_STORE_LOCATION}" -in "${SAML_CERTIFICATE}" -inkey "${SAML_KEY}" \ + -passout "pass:${SAML_PASS}" +keytool -importkeystore -srckeystore "${SAML_STORE_LOCATION}" -destkeystore "${JKS_LOCATION}" -srcstoretype PKCS12 \ + -trustcacerts -noprompt -deststoretype jks -srcstorepass "${KEY_STORE_PASS}" -deststorepass "${KEY_STORE_PASS}" \ + -srcalias "1" -destalias "${SAML_ALIAS}" -srckeypass "${SAML_PASS}" \ + -destkeypass "${SAML_PASS}" + +# IMPORT TU WIEN CERTIFICATE +echo "Import TU certificate ..." +keytool -importcert -trustcacerts -noprompt -keystore "${JKS_LOCATION}" -storepass "${KEY_STORE_PASS}" \ + -alias "${TU_ALIAS}" -file ./fda-authentication-service/rest-service/src/main/resources/saml/tu.cer diff --git a/fda-authentication-service/rest-service/src/main/resources/saml/dbrepo.jks b/fda-authentication-service/rest-service/src/main/resources/saml/dbrepo.jks new file mode 100755 index 0000000000000000000000000000000000000000..d848a46d328b43aaf0c6f062ac9eaccfd54764bf Binary files /dev/null and b/fda-authentication-service/rest-service/src/main/resources/saml/dbrepo.jks differ diff --git a/fda-authentication-service/rest-service/src/main/resources/saml/sp_metadata.xml b/fda-authentication-service/rest-service/src/main/resources/saml/sp_metadata.xml new file mode 100644 index 0000000000000000000000000000000000000000..92150d3be8426e6a36ef7c1da47aa09950c56542 --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/resources/saml/sp_metadata.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" validUntil="2021-11-14T08:52:19Z" cacheDuration="PT604800S" entityID="at:tuwien" ID="pfx8af29355-cf6e-b1f2-3624-7381e4de4ebe"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> + <ds:Reference URI="#pfx8af29355-cf6e-b1f2-3624-7381e4de4ebe"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>7sdg0oGKivb4Scou7O0SGJzI0G8=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>GHuxE4g0OCnzMN2RDlerdcwHNjXcyhFQUhccAlHxT3c8uu+70A+ki1bbOdH8BPuMmRXpUUEhguL5d81DtSY4P6P/0Yj7UOF7/0qOZpiBxUnD82xh42SX3QzjZ7xxqkJYvUXPyeJJ3xD4tjBfcYHZJiYEjAUcd2yYJg8/EBpGWg+VwpJ5wPkBK0NSOZDGTEHTwNufkOxBbUWcvfrMxp1nFwCC/EHfx5S+njJ1yy1u18CPUejCxs9jzSdMZ6PCTx0k+W5DTezouImClYC4CeZERtxrO0W3wVJfGkyDNDXjlktM7q/1TlIFxqnZ8SDaQ1TknJu/4bYmuPlTibE08J7M/VG8ZjLYkK09bhWOqVtyxwIsoMiuSYdBI9FeNErDbaMVyjmN5YiJZVb7BdOZ8ezVZJ9rL6udxplXClgvGPZBw80CEFP/n2JyHmBkBvKOIkffmTmSNRqbL59lVt6hgFVggQBCrDpyfCe62xro9xzFDNCw7ecKYCvu/2PNJhV9HaCwy86/t9Ml5BvM3COecB6Ya3w17iGvZY4jXTUlBiyIk5s89hr9FOlTHkPiU1bfGgooIMOzciXiMpIsQzXqQAsFuEc4+Wl0+t/i4W1dPf97m0gIO2zCoQLMsYCD/WsLbqFN6ulw3mZaK/GHf3dBECLy2msoGn6XUVpa0guzoCTuET8=</ds:SignatureValue> + <ds:KeyInfo><ds:X509Data><ds:X509Certificate>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</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature> + <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> + <md:KeyDescriptor use="signing"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>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</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:KeyDescriptor use="encryption"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>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</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dbrepo.ossdip.at:9097/api/auth" index="1"/> + </md:SPSSODescriptor> + <md:Organization> + <md:OrganizationName xml:lang="en-US">Technische Universität Wien</md:OrganizationName> + <md:OrganizationDisplayName xml:lang="en-US">TU Wien</md:OrganizationDisplayName> + <md:OrganizationURL xml:lang="en-US">https://tuwien.ac.at/</md:OrganizationURL> + </md:Organization> + <md:ContactPerson contactType="technical"> + <md:GivenName>Martin Weise</md:GivenName> + <md:EmailAddress>martin.weise@tuwien.ac.at</md:EmailAddress> + </md:ContactPerson> + <md:ContactPerson contactType="support"> + <md:GivenName>Andreas Rauber</md:GivenName> + <md:EmailAddress>andreas.rauber@tuwien.ac.at</md:EmailAddress> + </md:ContactPerson> +</md:EntityDescriptor> \ No newline at end of file diff --git a/fda-authentication-service/rest-service/src/main/resources/saml/tu.cer b/fda-authentication-service/rest-service/src/main/resources/saml/tu.cer new file mode 100644 index 0000000000000000000000000000000000000000..f60c10a46bd6517a50330eb9b8e57af477ad20a4 --- /dev/null +++ b/fda-authentication-service/rest-service/src/main/resources/saml/tu.cer @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnTCCAoWgAwIBAgIJALst+VObcXe1MA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNV +BAYTAkFUMQ8wDQYDVQQIDAZWaWVubmExDTALBgNVBAcMBFdpZW4xEDAOBgNVBAoM +B1RVIFdpZW4xDDAKBgNVBAsMA1pJRDEWMBQGA1UEAwwNc2ltcGxlU0FNTHBocDAe +Fw0xNDA0MDkwOTMxMjRaFw0yNDA0MDgwOTMxMjRaMGUxCzAJBgNVBAYTAkFUMQ8w +DQYDVQQIDAZWaWVubmExDTALBgNVBAcMBFdpZW4xEDAOBgNVBAoMB1RVIFdpZW4x +DDAKBgNVBAsMA1pJRDEWMBQGA1UEAwwNc2ltcGxlU0FNTHBocDCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANz8s2nk5tAVH9uCgpR6CCSQN3G9zHLRPaZq +0SA7LE8tzbSiBFeOM6JuN4Er3P81pwDPzeIN6Qfmi5Fi5/mdBr2jiNZxH2anwhf6 +GpRqA6ckP2c3+1fj5vJPX557XdBpf/SlbcS4H0dCQTFZwPmQN1cbvZ5nPg2jT+Gi +LJv5X2ugfviG2eaM9HTMuWbwSrGMqM3gJz/GYq6mp6llRJ7PgM6/jY4dLcBQ64Xu ++8yr2SJ2bDKyJwfYZIUqcyPhjJOcgj10EnZbJAPzSDDQ2yjBC5btBrO6yIGDwZm4 +lEJ4JshFDHLNbbiK78R5WlZD7gO+vaeT1069wl3ptGHT86dLQXUCAwEAAaNQME4w +HQYDVR0OBBYEFJ5pkC4zjbtkq5dUo7N+GfDLam4AMB8GA1UdIwQYMBaAFJ5pkC4z +jbtkq5dUo7N+GfDLam4AMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +ADIEncg+saezDSlvcsXvA8ZTd40/pKX2zbvWAU6PlVlT9zmkBMBevrxlodh5bSCr +fRQyjsd8GaJGLfiZf+KuXmd9xj35J9Gz10VlZf6Pp+8scjayFesDnfMoA/GvywJU +qZBMAvsa9LrSsA5c07NOiwcyWtXnS11zz3NFtX06OynAAmvlJHklSWhsJIBV+i5I +YMfV7jzYOI8wmulTRWK3Pycr6PLM1wQD7Pf8xl8nuxyQ8tPG+4gzUeHW9LkJNflN +Oa1Bb+XMAIj1ZiwQyLWOuo6n2u5reN24gU0jMi/Vy4dhn5oU6Ve86nwITKKm/S+E +OM8k5b+uOzI3g939xkINDpc= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/fda-gateway-service/src/main/resources/config.properties b/fda-authentication-service/rest-service/src/main/resources/ssl/.gitkeep similarity index 100% rename from fda-gateway-service/src/main/resources/config.properties rename to fda-authentication-service/rest-service/src/main/resources/ssl/.gitkeep diff --git a/fda-authentication-service/rest-service/src/main/resources/ssl/dbrepo.jks b/fda-authentication-service/rest-service/src/main/resources/ssl/dbrepo.jks new file mode 100644 index 0000000000000000000000000000000000000000..3d3d4410f97145f2d9c0ba1752981ca01dca0137 Binary files /dev/null and b/fda-authentication-service/rest-service/src/main/resources/ssl/dbrepo.jks differ diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ca3cc021b68ad199c04f3b01fb7459f01eeed71d --- /dev/null +++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -0,0 +1,245 @@ +package at.tuwien; + +import at.tuwien.api.container.ContainerBriefDto; +import at.tuwien.api.container.ContainerCreateRequestDto; +import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.container.image.*; +import at.tuwien.api.container.network.IpAddressDto; +import at.tuwien.entities.container.Container; +import at.tuwien.entities.container.image.ContainerImage; +import at.tuwien.entities.container.image.ContainerImageEnvironmentItem; +import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType; +import org.springframework.test.context.TestPropertySource; + +import java.math.BigInteger; +import java.time.Instant; +import java.util.List; + +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.HOURS; + +@TestPropertySource(locations = "classpath:application.properties") +public abstract class BaseUnitTest { + + public final static Long IMAGE_1_ID = 1L; + public final static String IMAGE_1_REPOSITORY = "postgres"; + public final static String IMAGE_1_TAG = "13-alpine"; + public final static String IMAGE_1_HASH = "83b40f2726e5"; + public final static Integer IMAGE_1_PORT = 5432; + public final static String IMAGE_1_DIALECT = "org.hibernate.dialect.PostgreSQLDialect"; + public final static String IMAGE_1_DRIVER = "org.postgresql.Driver"; + public final static String IMAGE_1_JDBC = "postgresql"; + public final static Long IMAGE_1_SIZE = 12000L; + public final static String IMAGE_1_LOGO = "AAAA"; + public final static Instant IMAGE_1_BUILT = Instant.now().minus(40, HOURS); + public final static List<ContainerImageEnvironmentItem> IMAGE_1_ENV = List.of(ContainerImageEnvironmentItem.builder() + .key("POSTGRES_USER") + .value("postgres") + .type(ContainerImageEnvironmentItemType.USERNAME) + .build(), + ContainerImageEnvironmentItem.builder() + .key("POSTGRES_PASSWORD") + .value("postgres") + .type(ContainerImageEnvironmentItemType.PASSWORD) + .build()); + public final static ImageEnvItemDto[] IMAGE_1_ENV_DTO = List.of(ImageEnvItemDto.builder() + .key("POSTGRES_USER") + .value("postgres") + .type(ImageEnvItemTypeDto.USERNAME) + .build(), + ImageEnvItemDto.builder() + .key("POSTGRES_PASSWORD") + .value("postgres") + .type(ImageEnvItemTypeDto.PASSWORD) + .build()) + .toArray(new ImageEnvItemDto[0]); + public final static List<String> IMAGE_1_ENVIRONMENT = List.of("POSTGRES_USER=postgres", + "POSTGRES_PASSWORD=postgres"); + + public final static Long IMAGE_2_ID = 2L; + public final static String IMAGE_2_REPOSITORY = "redis"; + public final static String IMAGE_2_TAG = "latest"; + public final static String IMAGE_2_HASH = "f877e80bb9ef"; + public final static Integer IMAGE_2_PORT = 6379; + public final static String IMAGE_2_DIALECT = "org.hibernate.dialect.SQLServerDialect"; + public final static String IMAGE_2_DRIVER = "redis.clients.Jedis"; + public final static String IMAGE_2_JDBC = "redis"; + public final static Long IMAGE_2_SIZE = 24000L; + public final static String IMAGE_2_LOGO = "BBBB"; + public final static Instant IMAGE_2_BUILT = Instant.now().minus(9, DAYS); + public final static List<ContainerImageEnvironmentItem> IMAGE_2_ENV = List.of(ContainerImageEnvironmentItem.builder() + .key("POSTGRES_USER") + .value("postgres") + .type(ContainerImageEnvironmentItemType.USERNAME) + .build(), + ContainerImageEnvironmentItem.builder() + .key("POSTGRES_PASSWORD") + .value("postgres") + .type(ContainerImageEnvironmentItemType.PASSWORD) + .build()); + public final static ImageEnvItemDto[] IMAGE_2_ENV_DTO = List.of(ImageEnvItemDto.builder() + .key("POSTGRES_USER") + .value("postgres") + .type(ImageEnvItemTypeDto.USERNAME) + .build(), + ImageEnvItemDto.builder() + .key("POSTGRES_PASSWORD") + .value("postgres") + .type(ImageEnvItemTypeDto.PASSWORD) + .build()) + .toArray(new ImageEnvItemDto[0]); + + public final static ContainerImage IMAGE_1 = ContainerImage.builder() + .id(IMAGE_1_ID) + .repository(IMAGE_1_REPOSITORY) + .tag(IMAGE_1_TAG) + .hash(IMAGE_1_HASH) + .jdbcMethod(IMAGE_1_JDBC) + .dialect(IMAGE_1_DIALECT) + .driverClass(IMAGE_1_DRIVER) + .containers(List.of()) + .compiled(IMAGE_1_BUILT) + .size(IMAGE_1_SIZE) + .environment(IMAGE_1_ENV) + .defaultPort(IMAGE_1_PORT) + .logo(IMAGE_1_LOGO) + .build(); + + public final static ImageDto IMAGE_1_DTO = ImageDto.builder() + .repository(IMAGE_1_REPOSITORY) + .tag(IMAGE_1_TAG) + .hash(IMAGE_1_HASH) + .jdbcMethod(IMAGE_1_JDBC) + .dialect(IMAGE_1_DIALECT) + .driverClass(IMAGE_1_DRIVER) + .compiled(IMAGE_1_BUILT) + .size(BigInteger.valueOf(IMAGE_1_SIZE)) + .environment(IMAGE_1_ENV_DTO) + .defaultPort(IMAGE_1_PORT) + .logo(IMAGE_2_LOGO) + .build(); + + public final static ContainerImage IMAGE_2 = ContainerImage.builder() + .id(IMAGE_2_ID) + .repository(IMAGE_2_REPOSITORY) + .tag(IMAGE_2_TAG) + .hash(IMAGE_2_HASH) + .jdbcMethod(IMAGE_2_JDBC) + .dialect(IMAGE_2_DIALECT) + .driverClass(IMAGE_2_DRIVER) + .containers(List.of()) + .compiled(IMAGE_2_BUILT) + .size(IMAGE_2_SIZE) + .environment(IMAGE_2_ENV) + .defaultPort(IMAGE_2_PORT) + .logo(IMAGE_2_LOGO) + .build(); + + public final static ImageDto IMAGE_2_DTO = ImageDto.builder() + .repository(IMAGE_2_REPOSITORY) + .tag(IMAGE_2_TAG) + .hash(IMAGE_2_HASH) + .jdbcMethod(IMAGE_2_JDBC) + .dialect(IMAGE_2_DIALECT) + .driverClass(IMAGE_2_DRIVER) + .size(BigInteger.valueOf(IMAGE_2_SIZE)) + .compiled(IMAGE_2_BUILT) + .environment(IMAGE_2_ENV_DTO) + .defaultPort(IMAGE_2_PORT) + .logo(IMAGE_2_LOGO) + .build(); + + public final static Long CONTAINER_1_ID = 1L; + public final static String CONTAINER_1_HASH = "deadbeef"; + public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1; + public final static String CONTAINER_1_NAME = "fda-userdb-u01"; + public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01"; + public final static String CONTAINER_1_DATABASE = "univie"; + public final static String CONTAINER_1_IP = "172.28.0.5"; + public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS); + + public final static Long CONTAINER_2_ID = 2L; + public static String CONTAINER_2_HASH = "0ff1ce"; + public final static ContainerImage CONTAINER_2_IMAGE = IMAGE_2; + public final static String CONTAINER_2_NAME = "fda-userdb-t01"; + public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-t01"; + public final static String CONTAINER_2_DATABASE = "tuw"; + public final static String CONTAINER_2_IP = "172.28.0.6"; + public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS); + + public final static Container CONTAINER_1 = Container.builder() + .id(CONTAINER_1_ID) + .name(CONTAINER_1_NAME) + .internalName(CONTAINER_1_INTERNALNAME) + .image(CONTAINER_1_IMAGE) + .hash(CONTAINER_1_HASH) + .containerCreated(CONTAINER_1_CREATED) + .build(); + + public final static Container CONTAINER_2 = Container.builder() + .id(CONTAINER_2_ID) + .name(CONTAINER_2_NAME) + .internalName(CONTAINER_2_INTERNALNAME) + .image(CONTAINER_2_IMAGE) + .hash(CONTAINER_2_HASH) + .containerCreated(CONTAINER_2_CREATED) + .build(); + + public final static ContainerDto CONTAINER_1_DTO = ContainerDto.builder() + .name(CONTAINER_1_NAME) + .image(IMAGE_1_DTO) + .hash(CONTAINER_1_HASH) + .ipAddress(IpAddressDto.builder() + .ipv4(CONTAINER_1_IP) + .build()) + .created(CONTAINER_1_CREATED) + .build(); + + public final static ContainerBriefDto CONTAINER_1_BRIEF_DTO = ContainerBriefDto.builder() + .name(CONTAINER_1_NAME) + .internalName(CONTAINER_1_INTERNALNAME) + .hash(CONTAINER_1_HASH) + .build(); + + public final static ImageBriefDto IMAGE_1_BRIEFDTO = ImageBriefDto.builder() + .repository(IMAGE_1_REPOSITORY) + .tag(IMAGE_1_TAG) + .build(); + + public final static ContainerDto CONTAINER_2_DTO = ContainerDto.builder() + .name(CONTAINER_2_NAME) + .image(IMAGE_2_DTO) + .hash(CONTAINER_2_HASH) + .ipAddress(IpAddressDto.builder() + .ipv4(CONTAINER_2_IP) + .build()) + .created(CONTAINER_2_CREATED) + .build(); + + public final static ContainerBriefDto CONTAINER_2_BRIEF_DTO = ContainerBriefDto.builder() + .id(CONTAINER_2_ID) + .name(CONTAINER_2_NAME) + .internalName(CONTAINER_2_INTERNALNAME) + .hash(CONTAINER_2_HASH) + .build(); + + public final static ImageCreateDto IMAGE_1_CREATE_DTO = ImageCreateDto.builder() + .repository(IMAGE_1_REPOSITORY) + .tag(IMAGE_1_TAG) + .environment(IMAGE_1_ENV_DTO) + .defaultPort(IMAGE_1_PORT) + .build(); + + public final static ImageCreateDto IMAGE_2_CREATE_DTO = ImageCreateDto.builder() + .repository(IMAGE_2_REPOSITORY) + .tag(IMAGE_2_TAG) + .environment(IMAGE_2_ENV_DTO) + .defaultPort(IMAGE_2_PORT) + .build(); + + public final static ContainerCreateRequestDto CONTAINER_1_CREATE_DTO = ContainerCreateRequestDto.builder() + .repository(IMAGE_1_REPOSITORY) + .tag(IMAGE_1_TAG) + .name(CONTAINER_1_NAME) + .build(); +} diff --git a/fda-authentication-service/rest-service/src/test/resources/application.properties b/fda-authentication-service/rest-service/src/test/resources/application.properties new file mode 100644 index 0000000000000000000000000000000000000000..8b9d935e60bed9cd1df3a05987fdbf6e98b2bc36 --- /dev/null +++ b/fda-authentication-service/rest-service/src/test/resources/application.properties @@ -0,0 +1,8 @@ +# disable discovery +spring.cloud.discovery.enabled = false + +# disable cloud config and config discovery +spring.cloud.config.discovery.enabled = false +spring.cloud.config.enabled = false + +log4j.logger.org.hibernate.type=TRACE \ No newline at end of file diff --git a/fda-authentication-service/service_ready b/fda-authentication-service/service_ready new file mode 100644 index 0000000000000000000000000000000000000000..b2e4f9df6804f249ba8aadd72f742929072badaa --- /dev/null +++ b/fda-authentication-service/service_ready @@ -0,0 +1,6 @@ +#!/bin/bash +if [ -f /ready ]; then + echo "service is ready and accepting connections" + exit 0 +fi +exit 1 \ No newline at end of file diff --git a/fda-authentication-service/services/pom.xml b/fda-authentication-service/services/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..8970cda209887c1ea924225740f43feb006dcd6e --- /dev/null +++ b/fda-authentication-service/services/pom.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>fda-authentication-service</artifactId> + <groupId>at.tuwien</groupId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>services</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>fda-authentication-service-services</name> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>${java.version}</source> + <target>${java.version}</target> + <annotationProcessorPaths> + <path> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + </path> + <!-- keep this order https://stackoverflow.com/questions/47676369/mapstruct-and-lombok-not-working-together#answer-65021876 --> + <path> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-authentication-service/services/src/main/java/at/tuwien/config/ReadyConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..0bee3b961edd4ca456f0243c8eede630a4a54716 --- /dev/null +++ b/fda-authentication-service/services/src/main/java/at/tuwien/config/ReadyConfig.java @@ -0,0 +1,23 @@ +package at.tuwien.config; + +import com.google.common.io.Files; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; + +import java.io.File; +import java.io.IOException; + +@Configuration +public class ReadyConfig { + + @Value("${fda.ready.path}") + private String readyPath; + + @EventListener(ApplicationReadyEvent.class) + public void init() throws IOException { + Files.touch(new File(readyPath)); + } + +} diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/mapper/UserMapper.java b/fda-authentication-service/services/src/main/java/at/tuwien/mapper/UserMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..a3bdb5a2247ea2b7629604693c41ee78afed7427 --- /dev/null +++ b/fda-authentication-service/services/src/main/java/at/tuwien/mapper/UserMapper.java @@ -0,0 +1,8 @@ +package at.tuwien.mapper; + +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface UserMapper { + +} diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/service/SamlUserDetailsService.java b/fda-authentication-service/services/src/main/java/at/tuwien/service/SamlUserDetailsService.java new file mode 100644 index 0000000000000000000000000000000000000000..874fe51d64dced70e8dbf00759f70e3c3d2cefa3 --- /dev/null +++ b/fda-authentication-service/services/src/main/java/at/tuwien/service/SamlUserDetailsService.java @@ -0,0 +1,23 @@ +package at.tuwien.service; + +import lombok.extern.log4j.Log4j2; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.saml.SAMLCredential; +import org.springframework.security.saml.userdetails.SAMLUserDetailsService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Log4j2 +@Service +public class SamlUserDetailsService implements SAMLUserDetailsService { + + @Override + public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException { + String id = credential.getNameID().getValue(); + /* right now we only support users */ + return new User(id, "empty", true, true, true, true, List.of(new SimpleGrantedAuthority("ROLE_USER"))); + } +} diff --git a/fda-broker-service/Dockerfile b/fda-broker-service/Dockerfile index ca689c00b666e9a355592e0a4ee10c241cb4710b..167f5aad08023400b3dabafc89ebfb8e4bc7de53 100644 --- a/fda-broker-service/Dockerfile +++ b/fda-broker-service/Dockerfile @@ -6,4 +6,4 @@ RUN chmod +x /usr/bin/service_ready COPY ./rabbitmq.conf /etc/rabbitmq/ -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD service_ready \ No newline at end of file +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready \ No newline at end of file diff --git a/fda-citation-service/Dockerfile b/fda-citation-service/Dockerfile index 6a6872c18eb679b11afef3f576c82fcd8d9a18f1..76774bc545deb7567a07d10c148ae5f97e862c34 100644 --- a/fda-citation-service/Dockerfile +++ b/fda-citation-service/Dockerfile @@ -14,9 +14,11 @@ COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tu COPY ./rest-service ./rest-service COPY ./services ./services COPY ./report ./report -COPY ./api ./api -RUN mvn -q clean package -DskipTests +ARG CI_JOB_STAGE + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null ###### THIRD STAGE ###### FROM openjdk:11-jre-slim as runtime @@ -24,7 +26,7 @@ FROM openjdk:11-jre-slim as runtime COPY ./service_ready /usr/bin RUN chmod +x /usr/bin/service_ready -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD service_ready +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready COPY --from=build ./rest-service/target/rest-service-*.jar ./rest.jar diff --git a/fda-citation-service/api/pom.xml b/fda-citation-service/api/pom.xml deleted file mode 100644 index 6525bab3727089f98059fa8c935d1de9feb1cbf2..0000000000000000000000000000000000000000 --- a/fda-citation-service/api/pom.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <artifactId>fda-citation-service</artifactId> - <groupId>at.tuwien</groupId> - <version>0.0.1-SNAPSHOT</version> - </parent> - <modelVersion>4.0.0</modelVersion> - - <artifactId>api</artifactId> - -</project> \ No newline at end of file diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositLinksDto.java b/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositLinksDto.java deleted file mode 100644 index 3cb5bb8317f0c9813ccd2b69898c25fd2701c24a..0000000000000000000000000000000000000000 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositLinksDto.java +++ /dev/null @@ -1,30 +0,0 @@ -package at.tuwien.api.zenodo.deposit; - -import lombok.*; - -@Setter -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class DepositLinksDto { - - private String bucket; - - private String discard; - - private String edit; - - private String files; - - private String html; - - private String latest_draft; - - private String latest_draft_html; - - private String publish; - - private String self; - -} diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileLinksDto.java b/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileLinksDto.java deleted file mode 100644 index d543b62cf48dcf419187245a5f1cbc9e69a1eb3b..0000000000000000000000000000000000000000 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileLinksDto.java +++ /dev/null @@ -1,16 +0,0 @@ -package at.tuwien.api.zenodo.files; - -import lombok.*; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class FileLinksDto { - - private String download; - - private String self; - -} diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileResponseDto.java b/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileResponseDto.java deleted file mode 100644 index 78928a91a945b31780f418c3b94e12b97ba524ea..0000000000000000000000000000000000000000 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileResponseDto.java +++ /dev/null @@ -1,24 +0,0 @@ -package at.tuwien.api.zenodo.files; - -import lombok.*; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class FileResponseDto { - - private String checksum; - - private String filename; - - private Long filesize; - - private Boolean locked; - - private String id; - - private FileLinksDto links; - -} diff --git a/fda-citation-service/pom.xml b/fda-citation-service/pom.xml index b9927da4fb451f70cf92e8dc3f000b5479d99f39..da3f183c0a8bc19f79e65b2dde4ed1be09d6e70d 100644 --- a/fda-citation-service/pom.xml +++ b/fda-citation-service/pom.xml @@ -19,7 +19,6 @@ <module>rest-service</module> <module>services</module> <module>report</module> - <module>api</module> </modules> <properties> @@ -80,6 +79,10 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + </dependency> <!-- Zenodo --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> @@ -112,6 +115,12 @@ <artifactId>jacoco-maven-plugin</artifactId> <version>${jacoco.version}</version> </dependency> + <!-- CSV --> + <dependency> + <groupId>com.opencsv</groupId> + <artifactId>opencsv</artifactId> + <version>5.5</version> + </dependency> <!-- IDE --> <dependency> <groupId>org.projectlombok</groupId> diff --git a/fda-citation-service/rest-service/src/main/java/at/tuwien/endpoints/FileEndpoint.java b/fda-citation-service/rest-service/src/main/java/at/tuwien/endpoints/FileEndpoint.java index 263fee91f41c21da2edd37166870e49345253106..6c3603322796f90a87d3022dc1f51091e123e3fe 100644 --- a/fda-citation-service/rest-service/src/main/java/at/tuwien/endpoints/FileEndpoint.java +++ b/fda-citation-service/rest-service/src/main/java/at/tuwien/endpoints/FileEndpoint.java @@ -1,69 +1,66 @@ package at.tuwien.endpoints; -import at.tuwien.api.zenodo.files.FileResponseDto; -import at.tuwien.api.zenodo.files.FileUploadDto; +import at.tuwien.api.database.deposit.files.FileDto; import at.tuwien.exception.*; +import at.tuwien.mapper.FileMapper; import at.tuwien.service.FileService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; import javax.validation.Valid; -import javax.validation.constraints.NotBlank; import java.util.List; +import java.util.stream.Collectors; @Log4j2 @CrossOrigin(origins = "*") @RestController -@RequestMapping("/api/database/{id}/table/{tableid}/deposit/file") +@RequestMapping("/api/database/{id}/cite/file") public class FileEndpoint { + private final FileMapper fileMapper; private final FileService fileService; @Autowired - public FileEndpoint(FileService fileService) { + public FileEndpoint(FileMapper fileMapper, FileService fileService) { + this.fileMapper = fileMapper; this.fileService = fileService; } @GetMapping - public List<FileResponseDto> listAll(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId) - throws MetadataDatabaseNotFoundException, ZenodoAuthenticationException, ZenodoApiException, - ZenodoNotFoundException, ZenodoUnavailableException { - return fileService.listResources(databaseId, tableId); + public List<FileDto> listAll(@Valid @PathVariable("id") Long databaseId) { + return fileService.listResources() + .stream() + .map(fileMapper::fileToFileDto) + .collect(Collectors.toList()); } - @GetMapping("/{fileId}") - public FileResponseDto find(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId, - @NotBlank @RequestParam("fileId") String fileId) - throws MetadataDatabaseNotFoundException, ZenodoApiException, ZenodoNotFoundException, - ZenodoAuthenticationException, ZenodoUnavailableException { - return fileService.findResource(databaseId, tableId, fileId); + @GetMapping("/{queryId}") + public FileDto find(@Valid @PathVariable("id") Long databaseId, + @Valid @PathVariable("queryId") Long queryId) + throws RemoteApiException, RemoteNotFoundException, RemoteAuthenticationException, + RemoteUnavailableException, QueryNotFoundException, MetadataDatabaseNotFoundException { + return fileMapper.fileToFileDto(fileService.findResource(databaseId, queryId)); } - @PostMapping - public FileResponseDto create(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId, - @Valid @RequestParam("data") FileUploadDto data, - @Valid @RequestParam("file") MultipartFile file) - throws MetadataDatabaseNotFoundException, ZenodoApiException, ZenodoFileTooLargeException, - ZenodoNotFoundException, ZenodoAuthenticationException, ZenodoUnavailableException { - return fileService.createResource(databaseId, tableId, data, file); + @PostMapping("/{queryId}") + public FileDto create(@Valid @PathVariable("id") Long databaseId, + @Valid @PathVariable("queryId") Long queryId) + throws RemoteApiException, RemoteNotFoundException, RemoteAuthenticationException, + RemoteUnavailableException, QueryNotFoundException, RemoteDatabaseException, TableServiceException, + RemoteFileException, MetadataDatabaseNotFoundException { + return fileMapper.fileToFileDto(fileService.createResource(databaseId, queryId)); } - @PutMapping("/{fileId}") - public FileResponseDto update(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId, - @NotBlank @RequestParam("fileId") String fileId) { + @PutMapping("/{queryId}") + public FileDto update(@Valid @PathVariable("id") Long databaseId, + @Valid @PathVariable("queryId") Long queryId) { return null; } - @DeleteMapping("/{fileId}") - public FileResponseDto delete(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId, - @NotBlank @RequestParam("fileId") String fileId) { + @DeleteMapping("/{queryId}") + public FileDto delete(@Valid @PathVariable("id") Long databaseId, + @Valid @PathVariable("queryId") Long queryId) { return null; } } diff --git a/fda-citation-service/rest-service/src/main/java/at/tuwien/endpoints/MetadataEndpoint.java b/fda-citation-service/rest-service/src/main/java/at/tuwien/endpoints/MetadataEndpoint.java index fc64bd4e8942fe25674494f7661bf0f7a14b605d..50bbb6d949b0f7c4124666133563081c7a2c5f23 100644 --- a/fda-citation-service/rest-service/src/main/java/at/tuwien/endpoints/MetadataEndpoint.java +++ b/fda-citation-service/rest-service/src/main/java/at/tuwien/endpoints/MetadataEndpoint.java @@ -1,67 +1,86 @@ package at.tuwien.endpoints; -import at.tuwien.api.zenodo.deposit.DepositChangeRequestDto; -import at.tuwien.api.zenodo.deposit.DepositChangeResponseDto; -import at.tuwien.api.zenodo.deposit.DepositResponseDto; +import at.tuwien.api.database.deposit.DepositChangeRequestDto; +import at.tuwien.api.database.query.QueryDto; import at.tuwien.exception.*; +import at.tuwien.mapper.QueryMapper; import at.tuwien.service.MetadataService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; -import javax.validation.constraints.NotBlank; import java.util.List; +import java.util.stream.Collectors; @Log4j2 @CrossOrigin(origins = "*") @RestController -@RequestMapping("/api/database/{id}/table/{tableid}/deposit/metadata") +@RequestMapping("/api/database/{id}/cite/metadata") public class MetadataEndpoint { + private final QueryMapper queryMapper; private final MetadataService metadataService; @Autowired - public MetadataEndpoint(MetadataService metadataService) { + public MetadataEndpoint(QueryMapper queryMapper, MetadataService metadataService) { + this.queryMapper = queryMapper; this.metadataService = metadataService; } @GetMapping - public List<DepositResponseDto> findAll(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId) throws ZenodoApiException, - ZenodoAuthenticationException, MetadataDatabaseNotFoundException, ZenodoUnavailableException { - return metadataService.listCitations(databaseId, tableId); + @Transactional + public List<QueryDto> findAll(@Valid @PathVariable("id") Long databaseId) throws MetadataDatabaseNotFoundException { + return metadataService.listCitations(databaseId) + .stream() + .map(queryMapper::queryToQueryDto) + .collect(Collectors.toList()); } - @PostMapping - public DepositChangeResponseDto create(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId) throws ZenodoApiException, - ZenodoAuthenticationException, MetadataDatabaseNotFoundException, ZenodoUnavailableException { - return metadataService.storeCitation(databaseId, tableId); + @PostMapping("/{queryId}") + @Transactional + public QueryDto create(@Valid @PathVariable("id") Long databaseId, + @Valid @PathVariable("queryId") Long queryId) throws RemoteApiException, + RemoteAuthenticationException, MetadataDatabaseNotFoundException, RemoteUnavailableException, + RemoteNotFoundException { + return queryMapper.queryToQueryDto(metadataService.storeCitation(databaseId, queryId)); } - @GetMapping("/{fileId}") - public DepositResponseDto find(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId) - throws MetadataDatabaseNotFoundException, ZenodoApiException, ZenodoNotFoundException, - ZenodoAuthenticationException, ZenodoUnavailableException { - return metadataService.findCitation(databaseId, tableId); + @GetMapping("/{queryId}") + @Transactional + public QueryDto find(@Valid @PathVariable("id") Long databaseId, + @Valid @RequestParam("queryId") Long queryId) + throws MetadataDatabaseNotFoundException, RemoteApiException, RemoteNotFoundException, + RemoteAuthenticationException, RemoteUnavailableException, QueryNotFoundException { + return queryMapper.queryToQueryDto(metadataService.findCitation(databaseId, queryId)); } - @PutMapping("/{fileId}") - public DepositChangeResponseDto update(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId, - @Valid @RequestBody DepositChangeRequestDto data) - throws MetadataDatabaseNotFoundException, ZenodoApiException, ZenodoNotFoundException, - ZenodoAuthenticationException, ZenodoUnavailableException { - return metadataService.updateCitation(databaseId, tableId, data); + @PutMapping("/{queryId}") + @Transactional + public QueryDto update(@Valid @PathVariable("id") Long databaseId, + @Valid @PathVariable("queryId") Long queryId, + @Valid @RequestBody DepositChangeRequestDto data) + throws RemoteApiException, RemoteNotFoundException, RemoteAuthenticationException, + RemoteUnavailableException, QueryNotFoundException, MetadataDatabaseNotFoundException { + return queryMapper.queryToQueryDto(metadataService.updateCitation(databaseId, queryId, data)); } - @DeleteMapping("/{fileId}") - public void delete(@Valid @RequestParam("id") Long databaseId, - @Valid @RequestParam("tableId") Long tableId, - @NotBlank @RequestParam("fileId") String fileId) throws MetadataDatabaseNotFoundException, - ZenodoApiException, ZenodoAuthenticationException, ZenodoNotFoundException, ZenodoUnavailableException { - metadataService.deleteCitation(databaseId, tableId); + @DeleteMapping("/{queryId}") + @Transactional + public void delete(@Valid @PathVariable("id") Long databaseId, + @Valid @PathVariable("queryId") Long queryId) throws MetadataDatabaseNotFoundException, + RemoteApiException, RemoteAuthenticationException, RemoteNotFoundException, RemoteUnavailableException, + QueryNotFoundException { + metadataService.deleteCitation(databaseId, queryId); + } + + @PostMapping("/{queryId}/publish") + @Transactional + public QueryDto publish(@Valid @PathVariable("id") Long databaseId, + @Valid @PathVariable("queryId") Long queryId) throws RemoteApiException, + RemoteAuthenticationException, MetadataDatabaseNotFoundException, RemoteUnavailableException, + RemoteNotFoundException, QueryNotFoundException { + return queryMapper.queryToQueryDto(metadataService.publishCitation(databaseId, queryId)); } } diff --git a/fda-citation-service/rest-service/src/main/resources/application-docker.yml b/fda-citation-service/rest-service/src/main/resources/application-docker.yml index a7a4a410d8397c409c7db046a19946b037cd9f29..468fe81b49d0faea7d93b1f1a611d6638abd676a 100644 --- a/fda-citation-service/rest-service/src/main/resources/application-docker.yml +++ b/fda-citation-service/rest-service/src/main/resources/application-docker.yml @@ -25,8 +25,10 @@ eureka: instance.hostname: fda-citation-service client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/ fda: + ready.path: /ready mapping.path: /root table.path: /root + query.endpoint: fda-table-service:9093 zenodo: endpoint: https://sandbox.zenodo.org/ api_key: "${ZENODO_API_KEY}" \ No newline at end of file diff --git a/fda-citation-service/rest-service/src/main/resources/application.yml b/fda-citation-service/rest-service/src/main/resources/application.yml index affe3fa08da6b19244b0806f926916afdb22fe9d..5432c8633212e8e617bc1684e92ec3e4218e4915 100644 --- a/fda-citation-service/rest-service/src/main/resources/application.yml +++ b/fda-citation-service/rest-service/src/main/resources/application.yml @@ -26,8 +26,10 @@ eureka: instance.hostname: fda-citation-service client.serviceUrl.defaultZone: http://localhost:9090/eureka/ fda: + ready.path: ~/ mapping.path: rest-service/src/main/resources table.path: rest-service/src/main/java/at/tuwien/userdb + query.endpoint: fda-query-service:9093 zenodo: endpoint: https://sandbox.zenodo.org/ api_key: "${ZENODO_API_KEY}" \ No newline at end of file diff --git a/fda-citation-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-citation-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index d66e5ba37e9a3cf1a39e318ee5f21ad3a127305d..c8d35af3d29e7dfb1a7b23e71dbe3f58a2b30e41 100644 --- a/fda-citation-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-citation-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -1,20 +1,32 @@ package at.tuwien; -import at.tuwien.api.zenodo.deposit.*; -import at.tuwien.api.zenodo.files.FileResponseDto; -import at.tuwien.api.zenodo.files.FileLinksDto; +import at.tuwien.api.database.deposit.DepositChangeRequestDto; +import at.tuwien.api.database.deposit.DepositDto; +import at.tuwien.api.database.deposit.DepositTzDto; +import at.tuwien.api.database.deposit.files.FileDto; +import at.tuwien.api.database.deposit.files.FileLinksDto; +import at.tuwien.api.database.deposit.metadata.CreatorDto; +import at.tuwien.api.database.deposit.metadata.LicenseTypeDto; +import at.tuwien.api.database.deposit.metadata.MetadataDto; +import at.tuwien.api.database.deposit.metadata.UploadTypeDto; +import at.tuwien.api.database.query.ExecuteQueryDto; +import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.entities.container.Container; import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.entities.container.image.ContainerImageEnvironmentItem; import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType; import at.tuwien.entities.database.Database; +import at.tuwien.entities.database.query.File; +import at.tuwien.entities.database.query.Query; import at.tuwien.entities.database.table.Table; import org.apache.commons.lang.RandomStringUtils; import org.springframework.test.context.TestPropertySource; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import static java.time.temporal.ChronoUnit.HOURS; @@ -44,28 +56,81 @@ public abstract class BaseUnitTest { public final static Long DEPOSIT_1_CONCEPT_RECORD_ID = 143L; public final static Long DEPOSIT_1_OWNER = 144L; - public final static String METADATA_1_TITLE = "My super dataset"; - public final static UploadTypeDto METADATA_1_UPLOAD_TYPE = UploadTypeDto.DATASET; - public final static String METADATA_1_DESCRIPTION = "The dataset contains 1000 records of ..."; + public final static Long QUERY_1_ID = 1L; + public final static String QUERY_1_TITLE = "All Raindata"; + public final static String QUERY_1_QUERY = "SELECT * FROM rainfall;"; + public final static String QUERY_1_QUERY_NORMALIZED = "SELECT id,rainfall FROM rainfall;"; + public final static String QUERY_1_HASH = "a5ddf5ac87b72173f75ccbd134ba1072"; + public final static Instant QUERY_1_EXECUTION_TIMESTAMP = Instant.now(); public final static String CREATOR_1_NAME = "First1 Last1"; public final static String CREATOR_1_AFFIL = "TU Wien"; public final static String CREATOR_1_ORCID = "0000-0002-5713-0725"; + public final static CreatorDto CREATOR_1 = CreatorDto.builder() + .name(CREATOR_1_NAME) + .affiliation(CREATOR_1_AFFIL) + .orcid(CREATOR_1_ORCID) + .build(); + public final static String CREATOR_2_NAME = "First2 Last2"; public final static String CREATOR_2_AFFIL = "TU Graz"; public final static String CREATOR_2_ORCID = "0000-0002-2606-4059"; - public final static String FILE_1_ID = "deadbeef-deafdeed"; + public final static CreatorDto CREATOR_2 = CreatorDto.builder() + .name(CREATOR_2_NAME) + .affiliation(CREATOR_2_AFFIL) + .orcid(CREATOR_2_ORCID) + .build(); + + public final static String METADATA_1_TITLE = "My super dataset"; + public final static UploadTypeDto METADATA_1_UPLOAD_TYPE = UploadTypeDto.DATASET; + public final static String METADATA_1_DESCRIPTION = "The dataset contains 1000 records of ..."; + public final static CreatorDto[] METADATA_1_CREATORS = new CreatorDto[]{CREATOR_1, CREATOR_2}; + + public final static Long FILE_1_ID = 1L; + public final static Long FILE_1_DB_ID = 1L; + public final static Long FILE_1_QID = QUERY_1_ID; public final static String FILE_1_NAME = "testdata-othername.csv"; + public final static String FILE_1_REF_ID = "6b3df619-eb55-427a-8ee2-9bef7c1ae189"; public final static String FILE_1_CHECKSUM = "d393c7fa1240c18473133793f7901aaa"; public final static Long FILE_1_SIZE = 34614L; - public final static String FILE_2_ID = "deadbeef-deafdeed"; + public final static File FILE_1 = File.builder() + .id(FILE_1_ID) + .fqid(FILE_1_QID) + .fdbid(FILE_1_DB_ID) + .refId(FILE_1_REF_ID) + .build(); + + public final static String FILE_1_LINKS_DOWNLOAD = "http://localhost:5500/file/" + FILE_1_ID + "/download"; + public final static String FILE_1_LINKS_SELF = "http://localhost:5500/file/" + FILE_1_ID; + + public final static Query QUERY_1 = Query.builder() + .id(QUERY_1_ID) + .qdbid(DATABASE_1_ID) + .title(QUERY_1_TITLE) + .query(QUERY_1_QUERY) + .queryNormalized(QUERY_1_QUERY_NORMALIZED) + .executionTimestamp(QUERY_1_EXECUTION_TIMESTAMP) + .files(List.of(FILE_1)) + .depositId(DEPOSIT_1_ID) + .qdbid(DATABASE_1_ID) + .build(); + + public final static Long FILE_2_ID = 2L; + public final static Long FILE_2_DB_ID = 1L; public final static String FILE_2_NAME = "testdata-weather.csv"; + public final static String FILE_2_REF_ID = "78729cbb-37ea-441a-94ae-c40ff021b09d"; public final static String FILE_2_CHECKSUM = "a65cf8b8719b1a65db4f361eeec18457"; public final static Long FILE_2_SIZE = 14094055L; + public final static File FILE_2 = File.builder() + .id(FILE_2_ID) + .fdbid(FILE_2_DB_ID) + .refId(FILE_2_REF_ID) + .build(); + public final static Long DEPOSIT_2_ID = 2L; public final static String DEPOSIT_2_TITLE = "Test Document " + RandomStringUtils.randomAlphanumeric(10); public final static String DEPOSIT_2_DESCRIPTION = "Test Description " + RandomStringUtils.randomAlphanumeric(100); @@ -75,9 +140,6 @@ public abstract class BaseUnitTest { public final static String DEPOSIT_2_STATE = "draft"; public final static Boolean DEPOSIT_2_SUBMITTED = false; - public final static String FILE_1_LINKS_DOWNLOAD = "http://localhost:5500/file/" + FILE_1_ID + "/download"; - public final static String FILE_1_LINKS_SELF = "http://localhost:5500/file/" + FILE_1_ID; - public final static String DEPOSIT_1_DOI = "10.5072/zenodo.542201"; public final static Long DEPOSIT_1_REC_ID = 542201L; @@ -152,19 +214,6 @@ public abstract class BaseUnitTest { .internalName(TABLE_1_INTERNAL_NAME) .topic(TABLE_1_TOPIC) .tdbid(DATABASE_1_ID) - .depositId(DEPOSIT_1_ID) - .build(); - - public final static CreatorDto CREATOR_1 = CreatorDto.builder() - .name(CREATOR_1_NAME) - .affiliation(CREATOR_1_AFFIL) - .orcid(CREATOR_1_ORCID) - .build(); - - public final static CreatorDto CREATOR_2 = CreatorDto.builder() - .name(CREATOR_2_NAME) - .affiliation(CREATOR_2_AFFIL) - .orcid(CREATOR_2_ORCID) .build(); public final static MetadataDto METADATA_1 = MetadataDto.builder() @@ -179,15 +228,21 @@ public abstract class BaseUnitTest { .self(FILE_1_LINKS_SELF) .build(); - public final static FileResponseDto FILE_1 = FileResponseDto.builder() - .checksum(FILE_1_CHECKSUM) - .filename(FILE_1_NAME) + public final static FileDto FILE_1_DTO = FileDto.builder() .id(FILE_1_ID) - .filesize(FILE_1_SIZE) - .links(FILE_1_LINKS) + .refId(FILE_1_REF_ID) + .fqid(QUERY_1_ID) + .fdbid(DATABASE_1_ID) .build(); - public final static DepositChangeResponseDto DEPOSIT_1 = DepositChangeResponseDto.builder() + public final static FileDto FILE_2_DTO = FileDto.builder() + .id(FILE_2_ID) + .refId(FILE_2_REF_ID) + .fqid(QUERY_1_ID) + .fdbid(DATABASE_1_ID) + .build(); + + public final static DepositTzDto DEPOSIT_1 = DepositTzDto.builder() .id(DEPOSIT_1_ID) .created(DEPOSIT_1_CREATED) .modified(DEPOSIT_1_MODIFIED) @@ -195,16 +250,37 @@ public abstract class BaseUnitTest { .state(DEPOSIT_1_STATE) .submitted(DEPOSIT_1_SUBMITTED) .recordId(DEPOSIT_1_RECORD_ID) - .files(List.of(FILE_1)) + .files(List.of(FILE_1_DTO, FILE_2_DTO)) .build(); - public final static DepositResponseDto DEPOSIT_2 = DepositResponseDto.builder() - .id(DEPOSIT_1_ID) - .title(DEPOSIT_1_TITLE) - .state(DEPOSIT_1_STATE) - .submitted(DEPOSIT_1_SUBMITTED) - .recordId(DEPOSIT_1_RECORD_ID) - .files(List.of(FILE_1)) + public final static ExecuteQueryDto QUERY_1_EXECUTE = ExecuteQueryDto.builder() + .query(QUERY_1_QUERY) + .title(QUERY_1_TITLE) + .build(); + + public final static String COLUMN_1_INTERNAL_NAME = "id"; + public final static String COLUMN_2_INTERNAL_NAME = "name"; + + public final static Map<String, Object> ROW_1 = new LinkedHashMap<>() {{ + put(COLUMN_1_INTERNAL_NAME, 1L); + put(COLUMN_2_INTERNAL_NAME, "Foo"); + }}; + public final static Map<String, Object> ROW_2 = new LinkedHashMap<>() {{ + put(COLUMN_1_INTERNAL_NAME, 2L); + put(COLUMN_2_INTERNAL_NAME, "Bar"); + }}; + public final static Map<String, Object> ROW_3 = new LinkedHashMap<>() {{ + put(COLUMN_1_INTERNAL_NAME, 3L); + put(COLUMN_2_INTERNAL_NAME, "Baz"); + }}; + + public final static QueryResultDto QUERY_1_RESULT = QueryResultDto.builder() + .id(QUERY_1_ID) + .result(List.of(ROW_1, ROW_2, ROW_3)) + .build(); + + public final static DepositChangeRequestDto DEPOST_1_REQUEST = DepositChangeRequestDto.builder() + .metadata(METADATA_1) .build(); } diff --git a/fda-citation-service/rest-service/src/test/java/at/tuwien/mapper/MapperUnitTest.java b/fda-citation-service/rest-service/src/test/java/at/tuwien/mapper/MapperUnitTest.java deleted file mode 100644 index f35c430a53ffa28e8e2352676483f2c2eae55d54..0000000000000000000000000000000000000000 --- a/fda-citation-service/rest-service/src/test/java/at/tuwien/mapper/MapperUnitTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.BaseUnitTest; -import at.tuwien.api.zenodo.deposit.DepositChangeResponseDto; -import at.tuwien.api.zenodo.deposit.DepositResponseDto; -import at.tuwien.config.ReadyConfig; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.util.ResourceUtils; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@SpringBootTest -public class MapperUnitTest extends BaseUnitTest { - - @MockBean - private ReadyConfig readyConfig; - - @Autowired - private ObjectMapper objectMapper; - - @Test - public void listDeposits_success() throws IOException { - final String json = FileUtils.readFileToString(ResourceUtils.getFile("classpath:zenodo-deposits-list.json")); - - /* test */ - final DepositResponseDto[] response = objectMapper.readValue(json, DepositResponseDto[].class); - assertEquals(10, response.length); - } - - @Test - public void storeDeposits_success() throws IOException, URISyntaxException { - final String json = FileUtils.readFileToString(ResourceUtils.getFile("classpath:zenodo-deposits-store.json")); - - /* test */ - final DepositChangeResponseDto response = objectMapper.readValue(json, DepositChangeResponseDto.class); - assertEquals(926290, response.getConceptRecId()); - assertEquals(0, response.getFiles().size()); - assertEquals(926291, response.getId()); - assertEquals(new URI("https://sandbox.zenodo.org/api/files/dbea7621-8308-45af-b6af-9e12394dcc1b"), response.getLinks().getBucket()); - assertEquals(new URI("https://sandbox.zenodo.org/deposit/926291"), response.getLinks().getHtml()); - assertEquals(new URI("https://sandbox.zenodo.org/api/deposit/depositions/926291/actions/discard"), response.getLinks().getDiscard()); - assertEquals(new URI("https://sandbox.zenodo.org/api/deposit/depositions/926291/actions/edit"), response.getLinks().getEdit()); - assertEquals(new URI("https://sandbox.zenodo.org/api/deposit/depositions/926291/files"), response.getLinks().getFiles()); - assertEquals(new URI("https://sandbox.zenodo.org/api/deposit/depositions/926291/actions/publish"), response.getLinks().getPublish()); - assertEquals(new URI("https://sandbox.zenodo.org/api/deposit/depositions/926291"), response.getLinks().getSelf()); - assertEquals("10.5072/zenodo.926291", response.getMetadata().getPrereserveDoi().getDoi()); - assertEquals(93513L, response.getOwner()); - assertEquals(926291L, response.getRecordId()); - assertEquals("unsubmitted", response.getState()); - assertEquals(false, response.getSubmitted()); - assertEquals("", response.getTitle()); - } - - -} \ No newline at end of file diff --git a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/FileServiceIntegrationTest.java b/fda-citation-service/rest-service/src/test/java/at/tuwien/service/FileServiceIntegrationTest.java deleted file mode 100644 index 16675992fdfb5e293ac62d14efffb5ae91eee41f..0000000000000000000000000000000000000000 --- a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/FileServiceIntegrationTest.java +++ /dev/null @@ -1,171 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.BaseUnitTest; -import at.tuwien.api.zenodo.deposit.DepositChangeResponseDto; -import at.tuwien.api.zenodo.files.FileResponseDto; -import at.tuwien.api.zenodo.files.FileUploadDto; -import at.tuwien.config.ReadyConfig; -import at.tuwien.exception.*; -import at.tuwien.repository.jpa.ContainerRepository; -import at.tuwien.repository.jpa.DatabaseRepository; -import at.tuwien.repository.jpa.TableRepository; -import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.util.ResourceUtils; - -import javax.transaction.Transactional; -import java.io.IOException; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -@SpringBootTest -@ExtendWith(SpringExtension.class) -@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) -public class FileServiceIntegrationTest extends BaseUnitTest { - - @MockBean - private ReadyConfig readyConfig; - - @Autowired - private TableRepository tableRepository; - - @Autowired - private ContainerRepository containerRepository; - - @Autowired - private DatabaseRepository databaseRepository; - - @Autowired - private ZenodoFileService fileService; - - @Autowired - private ZenodoMetadataService metadataService; - - @BeforeEach - @Transactional - public void beforeEach() { - containerRepository.save(CONTAINER_1); - databaseRepository.save(DATABASE_1); - tableRepository.save(TABLE_1); - } - - @Test - public void createResource_succeeds() throws IOException, ZenodoApiException, ZenodoNotFoundException, - ZenodoAuthenticationException, ZenodoFileTooLargeException, MetadataDatabaseNotFoundException, - ZenodoUnavailableException { - final MockMultipartFile file = new MockMultipartFile("testdata.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/testdata.csv"))); - - /* request */ - final DepositChangeResponseDto deposit = metadataService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - final FileUploadDto request = FileUploadDto.builder() - .name(FILE_1_NAME) - .build(); - - /* test */ - final FileResponseDto response = fileService.createResource(DATABASE_1_ID, TABLE_1_ID, request, file); - assertEquals(FILE_1_NAME, response.getFilename()); - assertEquals(FILE_1_CHECKSUM, response.getChecksum()); - assertEquals(FILE_1_SIZE, response.getFilesize()); - } - - @Test - @Disabled("slow internet") - public void createResource_largeFile_succeeds() throws IOException, ZenodoApiException, ZenodoNotFoundException, - ZenodoAuthenticationException, ZenodoFileTooLargeException, MetadataDatabaseNotFoundException, - ZenodoUnavailableException { - final MockMultipartFile file = new MockMultipartFile("weatherAUS.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/weatherAUS.csv"))); - - /* request */ - final DepositChangeResponseDto deposit = metadataService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - final FileUploadDto request = FileUploadDto.builder() - .name(FILE_2_NAME) - .build(); - - /* test */ - final FileResponseDto response = fileService.createResource(DATABASE_1_ID, TABLE_1_ID, request, file); - assertEquals(FILE_2_NAME, response.getFilename()); - assertEquals(FILE_2_CHECKSUM, response.getChecksum()); - assertEquals(FILE_2_SIZE, response.getFilesize()); - } - - @Test - public void listAll_notFound_fails() { - - /* test */ - assertThrows(ZenodoNotFoundException.class, () -> { - fileService.listResources(DATABASE_1_ID, TABLE_1_ID); - }); - } - - @Test - public void listAll_succeeds() throws MetadataDatabaseNotFoundException, ZenodoApiException, - ZenodoNotFoundException, ZenodoAuthenticationException, IOException, ZenodoFileTooLargeException, - ZenodoUnavailableException { - final MockMultipartFile file = new MockMultipartFile("testdata.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/testdata.csv"))); - - /* request */ - final DepositChangeResponseDto deposit = metadataService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - final FileUploadDto upload = FileUploadDto.builder() - .name(FILE_1_NAME) - .build(); - final FileResponseDto fileResponse = fileService.createResource(DATABASE_1_ID, TABLE_1_ID, upload, file); - - /* test */ - final List<FileResponseDto> listResponse = fileService.listResources(DATABASE_1_ID, TABLE_1_ID); - assertEquals(1, listResponse.size()); - assertEquals(FILE_1_CHECKSUM, listResponse.get(0).getChecksum()); - assertEquals(fileResponse.getId(), listResponse.get(0).getId()); - } - - @Test - public void findResource_noContent_fails() throws MetadataDatabaseNotFoundException, ZenodoApiException, - ZenodoFileTooLargeException, ZenodoNotFoundException, ZenodoAuthenticationException, - ZenodoUnavailableException, IOException { - final MockMultipartFile file = new MockMultipartFile("testdata.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/testdata.csv"))); - - /* request */ - final DepositChangeResponseDto deposit = metadataService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - final FileUploadDto upload = FileUploadDto.builder() - .name(FILE_1_NAME) - .build(); - final FileResponseDto fileResponse = fileService.createResource(DATABASE_1_ID, TABLE_1_ID, upload, file); - - /* test */ - final FileResponseDto findResponse = fileService.findResource(DATABASE_1_ID, TABLE_1_ID, fileResponse.getId()); - assertEquals(FILE_1_CHECKSUM, findResponse.getChecksum()); - assertEquals(fileResponse.getId(), findResponse.getId()); - } - - @Test - public void deleteRessource_succeeds() throws MetadataDatabaseNotFoundException, ZenodoApiException, - ZenodoFileTooLargeException, ZenodoNotFoundException, ZenodoAuthenticationException, IOException, - ZenodoUnavailableException { - final MockMultipartFile file = new MockMultipartFile("testdata.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/testdata.csv"))); - - /* request */ - final DepositChangeResponseDto deposit = metadataService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - final FileUploadDto upload = FileUploadDto.builder() - .name(FILE_1_NAME) - .build(); - final FileResponseDto fileResponse = fileService.createResource(DATABASE_1_ID, TABLE_1_ID, upload, file); - - /* test */ - fileService.deleteResource(DATABASE_1_ID, TABLE_1_ID, fileResponse.getId()); - } - -} \ No newline at end of file diff --git a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/FileServiceUnitTest.java b/fda-citation-service/rest-service/src/test/java/at/tuwien/service/FileServiceUnitTest.java deleted file mode 100644 index f160cf99b71a608f9e6783cf0b0f9d5e51bdd0dd..0000000000000000000000000000000000000000 --- a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/FileServiceUnitTest.java +++ /dev/null @@ -1,331 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.BaseUnitTest; -import at.tuwien.api.zenodo.files.FileResponseDto; -import at.tuwien.api.zenodo.files.FileUploadDto; -import at.tuwien.config.ReadyConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.exception.*; -import at.tuwien.repository.jpa.TableRepository; -import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.util.MultiValueMap; -import org.springframework.util.ResourceUtils; -import org.springframework.web.client.ResourceAccessException; -import org.springframework.web.client.RestTemplate; - -import java.io.IOException; -import java.util.List; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.when; - -@SpringBootTest -@ExtendWith(SpringExtension.class) -public class FileServiceUnitTest extends BaseUnitTest { - - @MockBean - private ReadyConfig readyConfig; - - @Autowired - private ZenodoFileService fileService; - - @MockBean - private RestTemplate apiTemplate; - - @MockBean - private TableRepository tableRepository; - - final Database DATABASE_1 = Database.builder() - .id(DATABASE_1_ID) - .build(); - - @Test - public void createResource_succeeds() throws IOException, ZenodoApiException, ZenodoNotFoundException, - ZenodoAuthenticationException, ZenodoFileTooLargeException, MetadataDatabaseNotFoundException, - ZenodoUnavailableException { - final MockMultipartFile file = new MockMultipartFile("testdata.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/testdata.csv"))); - - /* mock */ - when(apiTemplate.postForEntity(anyString(), Mockito.<MultiValueMap<String, HttpEntity<?>>>any(), - eq(FileResponseDto.class), eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(FILE_1)); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* request */ - final FileUploadDto request = FileUploadDto.builder() - .name(FILE_1_NAME) - .build(); - - /* test */ - final FileResponseDto response = fileService.createResource(DATABASE_1_ID, TABLE_1_ID, request, file); - assertEquals(FILE_1_NAME, response.getFilename()); - assertEquals(FILE_1_CHECKSUM, response.getChecksum()); - assertEquals(FILE_1_SIZE, response.getFilesize()); - } - - @Test - public void createResource_unavailable_fails() throws IOException { - final MockMultipartFile file = new MockMultipartFile("testdata.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/testdata.csv"))); - - /* mock */ - doThrow(ResourceAccessException.class) - .when(apiTemplate) - .postForEntity(anyString(), Mockito.<MultiValueMap<String, HttpEntity<?>>>any(), - eq(FileResponseDto.class), eq(DEPOSIT_1_ID), anyString()); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* request */ - final FileUploadDto request = FileUploadDto.builder() - .name(FILE_1_NAME) - .build(); - - /* test */ - assertThrows(ZenodoUnavailableException.class, () -> { - fileService.createResource(DATABASE_1_ID, TABLE_1_ID, request, file); - }); - } - - @Test - public void createResource_notExists_fails() throws IOException { - final MockMultipartFile file = new MockMultipartFile("testdata.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/testdata.csv"))); - - /* mock */ - when(apiTemplate.postForEntity(anyString(), Mockito.<MultiValueMap<String, HttpEntity<?>>>any(), - eq(FileResponseDto.class), eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.BAD_REQUEST) - .build()); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* request */ - final FileUploadDto request = FileUploadDto.builder() - .name(FILE_1_NAME) - .build(); - - /* test */ - assertThrows(ZenodoNotFoundException.class, () -> { - fileService.createResource(DATABASE_1_ID, TABLE_1_ID, request, file); - }); - } - - @Test - public void createResource_bodyEmpty_fails() throws IOException { - final MockMultipartFile file = new MockMultipartFile("testdata.csv", FileUtils.readFileToByteArray( - ResourceUtils.getFile("classpath:csv/testdata.csv"))); - - /* mock */ - when(apiTemplate.postForEntity(anyString(), Mockito.<MultiValueMap<String, HttpEntity<?>>>any(), - eq(FileResponseDto.class), eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.accepted().body(null)); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* request */ - final FileUploadDto request = FileUploadDto.builder() - .name(FILE_1_NAME) - .build(); - - /* test */ - assertThrows(ZenodoApiException.class, () -> { - fileService.createResource(DATABASE_1_ID, TABLE_1_ID, request, file); - }); - } - - @Test - public void listAll_succeeds() throws MetadataDatabaseNotFoundException, ZenodoApiException, - ZenodoNotFoundException, ZenodoAuthenticationException, ZenodoUnavailableException { - - /* mock */ - when(apiTemplate.exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(FileResponseDto[].class), - eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.ok().body(new FileResponseDto[]{FILE_1})); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - final List<FileResponseDto> response = fileService.listResources(DATABASE_1_ID, TABLE_1_ID); - assertEquals(1, response.size()); - } - - @Test - public void listAll_unavailable_fails() { - - /* mock */ - doThrow(ResourceAccessException.class) - .when(apiTemplate) - .exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(FileResponseDto[].class), - eq(DEPOSIT_1_ID), anyString()); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - assertThrows(ZenodoUnavailableException.class, () -> { - fileService.listResources(DATABASE_1_ID, TABLE_1_ID); - }); - } - - @Test - public void listAll_noContent_fails() { - - /* mock */ - when(apiTemplate.exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(FileResponseDto[].class), - eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.ok().body(null)); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - assertThrows(ZenodoApiException.class, () -> { - fileService.listResources(DATABASE_1_ID, TABLE_1_ID); - }); - } - - @Test - public void listAll_notFound_fails() { - - /* mock */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - assertThrows(MetadataDatabaseNotFoundException.class, () -> { - fileService.listResources(DATABASE_1_ID, 9999L); - }); - } - - @Test - public void findResource_succeeds() throws MetadataDatabaseNotFoundException, ZenodoApiException, - ZenodoNotFoundException, ZenodoAuthenticationException, ZenodoUnavailableException { - - /* mock */ - when(apiTemplate.exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(FileResponseDto.class), - eq(DEPOSIT_1_ID), eq(FILE_1_ID), anyString())) - .thenReturn(ResponseEntity.ok().body(FILE_1)); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - final FileResponseDto file = fileService.findResource(DATABASE_1_ID, TABLE_1_ID, FILE_1_ID); - assertEquals(FILE_1_ID, file.getId()); - assertEquals(FILE_1_NAME, file.getFilename()); - assertEquals(FILE_1_SIZE, file.getFilesize()); - assertEquals(FILE_1_CHECKSUM, file.getChecksum()); - } - - @Test - public void findResource_unavailable_fails() { - - /* mock */ - doThrow(ResourceAccessException.class) - .when(apiTemplate) - .exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(FileResponseDto.class), - eq(DEPOSIT_1_ID), eq(FILE_1_ID), anyString()); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - assertThrows(ZenodoUnavailableException.class, () -> { - fileService.findResource(DATABASE_1_ID, TABLE_1_ID, FILE_1_ID); - }); - } - - @Test - public void findResource_noContent_fails() { - - /* mock */ - when(apiTemplate.exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(FileResponseDto.class), - eq(DEPOSIT_1_ID), eq(FILE_1_ID), anyString())) - .thenReturn(ResponseEntity.ok().body(null)); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - assertThrows(ZenodoApiException.class, () -> { - fileService.findResource(DATABASE_1_ID, TABLE_1_ID, FILE_1_ID); - }); - } - - @Test - public void findResource_notFound_fails() { - - /* mock */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.empty()); - - /* test */ - assertThrows(MetadataDatabaseNotFoundException.class, () -> { - fileService.findResource(DATABASE_1_ID, TABLE_1_ID, FILE_1_ID); - }); - } - - @Test - public void deleteResource_succeeds() throws MetadataDatabaseNotFoundException, ZenodoApiException, - ZenodoNotFoundException, ZenodoAuthenticationException, ZenodoUnavailableException { - - /* mock */ - when(apiTemplate.exchange(anyString(), eq(HttpMethod.DELETE), Mockito.any(), eq(String.class), - eq(DEPOSIT_1_ID), eq(FILE_1_ID), anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT).build()); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - fileService.deleteResource(DATABASE_1_ID, TABLE_1_ID, FILE_1_ID); - } - - @Test - public void deleteResource_unavailable_fails() { - - /* mock */ - doThrow(ResourceAccessException.class) - .when(apiTemplate) - .exchange(anyString(), eq(HttpMethod.DELETE), Mockito.any(), eq(String.class), - eq(DEPOSIT_1_ID), eq(FILE_1_ID), anyString()); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - assertThrows(ZenodoUnavailableException.class, () -> { - fileService.deleteResource(DATABASE_1_ID, TABLE_1_ID, FILE_1_ID); - }); - } - - @Test - public void deleteResource_wrongStatus_fails() { - - /* mock */ - when(apiTemplate.exchange(anyString(), eq(HttpMethod.DELETE), Mockito.any(), eq(String.class), - eq(DEPOSIT_1_ID), eq(FILE_1_ID), anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.OK).build()); - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - - /* test */ - assertThrows(ZenodoApiException.class, () -> { - fileService.deleteResource(DATABASE_1_ID, TABLE_1_ID, FILE_1_ID); - }); - } - -} \ No newline at end of file diff --git a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceIntegrationTest.java b/fda-citation-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceIntegrationTest.java deleted file mode 100644 index ef102fd44136a8c84303adf6288535e02a10d392..0000000000000000000000000000000000000000 --- a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceIntegrationTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.BaseUnitTest; -import at.tuwien.api.zenodo.deposit.*; -import at.tuwien.config.ReadyConfig; -import at.tuwien.entities.database.table.Table; -import at.tuwien.exception.*; -import at.tuwien.repository.jpa.ContainerRepository; -import at.tuwien.repository.jpa.DatabaseRepository; -import at.tuwien.repository.jpa.TableRepository; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import javax.transaction.Transactional; - -@SpringBootTest -@ExtendWith(SpringExtension.class) -public class MetadataServiceIntegrationTest extends BaseUnitTest { - - @MockBean - private ReadyConfig readyConfig; - - @Autowired - private ZenodoMetadataService zenodoService; - - @Autowired - private TableRepository tableRepository; - - @Autowired - private ContainerRepository containerRepository; - - @Autowired - private DatabaseRepository databaseRepository; - - @BeforeEach - @Transactional - public void beforeEach() { - containerRepository.save(CONTAINER_1); - databaseRepository.save(DATABASE_1); - tableRepository.save(TABLE_1); - } - - @Test - public void listDeposit_succeeds() throws ZenodoApiException, ZenodoAuthenticationException, - ZenodoUnavailableException { - - /* test */ - zenodoService.listCitations(DATABASE_1_ID, TABLE_1_ID); - } - - @Test - public void createDeposit_succeeds() throws ZenodoApiException, ZenodoAuthenticationException, - MetadataDatabaseNotFoundException, ZenodoUnavailableException { - - /* test */ - final DepositChangeResponseDto response = zenodoService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - Assertions.assertNotNull(response.getId()); - } - - @Test - public void updateDeposit_succeeds() throws ZenodoApiException, ZenodoAuthenticationException, - ZenodoNotFoundException, MetadataDatabaseNotFoundException, ZenodoUnavailableException { - final DepositChangeResponseDto deposit = zenodoService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - final DepositChangeRequestDto request = DepositChangeRequestDto.builder() - .metadata(METADATA_1) - .build(); - - /* test */ - final DepositChangeResponseDto response2 = zenodoService.updateCitation(DATABASE_1_ID, TABLE_1_ID, request); - Assertions.assertNotNull(response2.getId()); - Assertions.assertEquals(METADATA_1_TITLE, response2.getTitle()); - Assertions.assertEquals(METADATA_1_TITLE, response2.getMetadata().getTitle()); - Assertions.assertEquals(METADATA_1_DESCRIPTION, response2.getMetadata().getDescription()); - } - -} \ No newline at end of file diff --git a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java b/fda-citation-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java deleted file mode 100644 index e44fcc5ab4685bbf4410fe589b382a1aa2df922e..0000000000000000000000000000000000000000 --- a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java +++ /dev/null @@ -1,295 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.BaseUnitTest; -import at.tuwien.api.zenodo.deposit.DepositChangeResponseDto; -import at.tuwien.api.zenodo.deposit.DepositResponseDto; -import at.tuwien.api.zenodo.deposit.DepositChangeRequestDto; -import at.tuwien.api.zenodo.deposit.MetadataDto; -import at.tuwien.config.ReadyConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.exception.*; -import at.tuwien.repository.jpa.TableRepository; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.web.client.ResourceAccessException; -import org.springframework.web.client.RestTemplate; - -import java.util.List; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; - -@SpringBootTest -@ExtendWith(SpringExtension.class) -public class MetadataServiceUnitTest extends BaseUnitTest { - - @Autowired - private ZenodoMetadataService zenodoService; - - @MockBean - private ReadyConfig readyConfig; - - @MockBean - private RestTemplate apiTemplate; - - @MockBean - private TableRepository tableRepository; - - final Database DATABASE_1 = Database.builder() - .id(DATABASE_1_ID) - .build(); - - @Test - public void listCitations_succeeds() throws ZenodoApiException, ZenodoAuthenticationException, - ZenodoUnavailableException { - - /* mocks */ - when(apiTemplate.exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(DepositResponseDto[].class), - anyString())) - .thenReturn(ResponseEntity.ok(new DepositResponseDto[]{DEPOSIT_2})); - - /* test */ - final List<DepositResponseDto> response = zenodoService.listCitations(DATABASE_1_ID, TABLE_1_ID); - assertEquals(1, response.size()); - } - - @Test - public void listCitations_unavailable_fails() { - - /* mocks */ - doThrow(ResourceAccessException.class) - .when(apiTemplate) - .exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(DepositResponseDto[].class), - anyString()); - - /* test */ - assertThrows(ZenodoUnavailableException.class, () -> { - zenodoService.listCitations(DATABASE_1_ID, TABLE_1_ID); - }); - } - - @Test - public void listCitations_empty_fails() { - - /* mocks */ - when(apiTemplate.exchange(anyString(), eq(HttpMethod.GET), Mockito.any(), eq(DepositResponseDto[].class), - anyString())) - .thenReturn(ResponseEntity.ok().build()); - - /* test */ - assertThrows(ZenodoApiException.class, () -> { - zenodoService.listCitations(DATABASE_1_ID, TABLE_1_ID); - }); - } - - @Test - public void storeCitation_succeed() throws ZenodoApiException, ZenodoAuthenticationException, - MetadataDatabaseNotFoundException, ZenodoUnavailableException { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - when(apiTemplate.exchange(anyString(), eq(HttpMethod.POST), Mockito.<HttpEntity<String>>any(), eq(DepositChangeResponseDto.class), - anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.CREATED) - .body(DEPOSIT_1)); - - /* test */ - final DepositChangeResponseDto response = zenodoService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - assertEquals(DEPOSIT_1_CREATED, response.getCreated()); - assertEquals(DEPOSIT_1_MODIFIED, response.getModified()); - } - - @Test - public void storeCitation_unavailable_fails() { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - doThrow(ResourceAccessException.class) - .when(apiTemplate) - .exchange(anyString(), eq(HttpMethod.POST), Mockito.<HttpEntity<String>>any(), eq(DepositChangeResponseDto.class), - anyString()); - - /* test */ - assertThrows(ZenodoUnavailableException.class, () -> { - zenodoService.storeCitation(DATABASE_1_ID, TABLE_1_ID); - }); - } - - @Test - public void deleteCitation_succeeds() throws ZenodoApiException, ZenodoAuthenticationException, - MetadataDatabaseNotFoundException, ZenodoNotFoundException, ZenodoUnavailableException { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - when(apiTemplate.exchange(anyString(), eq(HttpMethod.DELETE), Mockito.any(), eq(String.class), anyLong(), - anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.CREATED) - .build()); - - /* test */ - zenodoService.deleteCitation(DATABASE_1_ID, TABLE_1_ID); - } - - @Test - public void deleteCitation_unavailable_fails() { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - doThrow(ResourceAccessException.class) - .when(apiTemplate) - .exchange(anyString(), eq(HttpMethod.DELETE), Mockito.any(), eq(String.class), anyLong(), - anyString()); - - /* test */ - assertThrows(ZenodoUnavailableException.class, () -> { - zenodoService.deleteCitation(DATABASE_1_ID, TABLE_1_ID); - }); - } - - @Test - public void deleteCitation_fails() { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - when(apiTemplate.exchange(anyString(), eq(HttpMethod.DELETE), Mockito.any(), eq(String.class), anyLong(), - anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .build()); - - /* test */ - assertThrows(ZenodoApiException.class, () -> { - zenodoService.deleteCitation(DATABASE_1_ID, TABLE_1_ID); - }); - } - - @Test - public void updateCitation_succeeds() throws ZenodoApiException, ZenodoAuthenticationException, - ZenodoNotFoundException, MetadataDatabaseNotFoundException, ZenodoUnavailableException { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - when(apiTemplate.exchange(anyString(), eq(HttpMethod.PUT), Mockito.<HttpEntity<DepositChangeRequestDto>>any(), eq(DepositChangeResponseDto.class), - eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(DEPOSIT_1)); - - /* request */ - final DepositChangeRequestDto request = DepositChangeRequestDto.builder() - .metadata(METADATA_1) - .build(); - - /* test */ - zenodoService.updateCitation(DATABASE_1_ID, TABLE_1_ID, request); - } - - @Test - public void updateCitation_unavailable_fails() { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - doThrow(ResourceAccessException.class) - .when(apiTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), Mockito.<HttpEntity<DepositChangeRequestDto>>any(), eq(DepositChangeResponseDto.class), - eq(DEPOSIT_1_ID), anyString()); - - /* request */ - final DepositChangeRequestDto request = DepositChangeRequestDto.builder() - .metadata(METADATA_1) - .build(); - - /* test */ - assertThrows(ZenodoUnavailableException.class, () -> { - zenodoService.updateCitation(DATABASE_1_ID, TABLE_1_ID, request); - }); - } - - @Test - public void updateCitation_only1orcid_fails() { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - when(apiTemplate.exchange(anyString(), eq(HttpMethod.PUT), Mockito.<HttpEntity<DepositChangeRequestDto>>any(), eq(DepositChangeResponseDto.class), - eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.BAD_REQUEST) - .build()); - - /* request */ - final MetadataDto m = METADATA_1; - m.getCreators()[1].setOrcid(null); - final DepositChangeRequestDto request = DepositChangeRequestDto.builder() - .metadata(m) - .build(); - - /* test */ - assertThrows(ZenodoNotFoundException.class, () -> { - zenodoService.updateCitation(DATABASE_1_ID, TABLE_1_ID, request); - }); - } - - @Test - public void updateCitation_notExists_fails() { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.of(TABLE_1)); - when(apiTemplate.exchange(anyString(), eq(HttpMethod.PUT), Mockito.<HttpEntity<DepositChangeRequestDto>>any(), eq(DepositChangeResponseDto.class), - eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.BAD_REQUEST) - .build()); - - /* request */ - final DepositChangeRequestDto request = DepositChangeRequestDto.builder() - .metadata(METADATA_1) - .build(); - - /* test */ - assertThrows(ZenodoNotFoundException.class, () -> { - zenodoService.updateCitation(DATABASE_1_ID, TABLE_1_ID, request); - }); - } - - @Test - public void updateCitation_notFound_fails() { - - /* mocks */ - when(tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID)) - .thenReturn(Optional.empty()); - when(apiTemplate.exchange(anyString(), eq(HttpMethod.PUT), Mockito.<HttpEntity<DepositChangeRequestDto>>any(), - eq(DepositChangeResponseDto.class), - eq(DEPOSIT_1_ID), anyString())) - .thenReturn(ResponseEntity.status(HttpStatus.BAD_REQUEST) - .build()); - - /* request */ - final DepositChangeRequestDto request = DepositChangeRequestDto.builder() - .metadata(METADATA_1) - .build(); - - /* test */ - assertThrows(MetadataDatabaseNotFoundException.class, () -> { - zenodoService.updateCitation(DATABASE_1_ID, TABLE_1_ID, request); - }); - } - -} \ No newline at end of file diff --git a/fda-citation-service/rest-service/src/test/java/at/tuwien/service/ServiceUnitTest.java b/fda-citation-service/rest-service/src/test/java/at/tuwien/service/ServiceUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..89c3f2772829831c42ed1ec15ab80c8017a2e5dd --- /dev/null +++ b/fda-citation-service/rest-service/src/test/java/at/tuwien/service/ServiceUnitTest.java @@ -0,0 +1,18 @@ +package at.tuwien.service; + +import at.tuwien.BaseUnitTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest +public class ServiceUnitTest extends BaseUnitTest { + + @Test + public void applicationLoads_succeeds() { + + } + +} diff --git a/fda-citation-service/rest-service/src/test/resources/csv/keyboard.csv b/fda-citation-service/rest-service/src/test/resources/csv/keyboard.csv new file mode 100644 index 0000000000000000000000000000000000000000..21c3c1e0400af94bbd077d9a00dc300c0c6d3b1c --- /dev/null +++ b/fda-citation-service/rest-service/src/test/resources/csv/keyboard.csv @@ -0,0 +1,4969 @@ +Shift key time,Esc key time,Ctrl key time,Alt key time,User ID,Test date,Gender,Right hand,Birth year,Computer skill level +1.1315,0.9827,1.06866667,0.90588889,1,3/10/2019 10:17,male,1,1964,4 +1.042,1.2572,1.2215,1.13133333,1,11/14/2019 8:57,male,1,1964,4 +1.12722222,1.11575,1.24833333,1.1035,2,2/6/2019 0:00,female,1,1965, +1.33814286,1.43566667,1.58525,1.2845,4,2/10/2019 0:00,male,1,1954,4 +2.0555,1.4265,0.91785714,1.66333333,4,3/11/2019 13:10,male,1,1954,4 +1.851,1.75725,1.481,1.90742857,4,2/9/2019 0:00,male,1,1954,4 +1.242,1.364,1.30457143,2.05133333,4,2/10/2019 0:00,male,1,1954,4 +1.6315,1.31514286,1.07133333,1.42328571,4,10/1/2019 10:17,male,1,1954,4 +1.351,1.909,1.37833333,3.66075,4,2/9/2019 0:00,male,1,1954,4 +1.23233333,1.308,1.325,1.02027273,4,2/13/2019 0:00,male,1,1954,4 +1.407,1.4645,1.3726,1.939,4,2/10/2019 0:00,male,1,1954,4 +1.25366667,1.11983333,1.0786,1.9828,4,3/9/2019 0:00,male,1,1954,4 +0.83433333,0.91425,1.07875,0.915,6,2/6/2019 0:00,male,1,1974, +1.00922222,0.85871429,1.07542857,1.01371429,6,2/26/2019 0:00,male,1,1974, +0.6483,0.83916667,0.67513333,0.7926,7,2/6/2019 0:00,female,1,1997, +0.79875,0.87953333,0.84928571,0.8878,8,2/6/2019 0:00,male,0,1976, +1.0078,1.084,1.33066667,1.4336,11,2/7/2019 0:00,female,1,1974, +0.65666667,0.8717,0.731375,0.70890909,12,2/7/2019 0:00,female,1,1991, +0.757,0.733,0.79955556,0.8475,13,2/7/2019 0:00,female,1,1995, +0.867375,0.85816667,1.0091,0.85688889,14,2/7/2019 0:00,male,1,1995, +1.217,1.816,1.547,1.13766667,15,2/10/2019 0:00,female,1,1959, +0.5342,0.63008333,0.57711765,0.51335714,16,2/27/2019 0:00,male,1,1996, +0.6925,0.71164286,0.73025,0.72925,25,2/27/2019 0:00,male,1,1996, +1.00528571,1.08288889,1.76,1.3865,114,2/26/2019 0:00,female,1,1977, +0.842,0.84927273,1.084,1.11075,115,2/27/2019 0:00,male,1,1996, +0.64661538,0.64628571,0.6477,0.85,116,2/27/2019 0:00,male,1,1996, +0.8312,0.894,1.057,0.8468,117,2/27/2019 0:00,male,1,1996, +0.80885714,1.04216667,0.87963636,1.22366667,120,3/5/2019 0:00,male,1,1999, +0.8112,0.7375,1.52675,1.12016667,121,3/5/2019 0:00,female,1,1999, +0.676875,0.77066667,0.75535714,0.8991,122,3/5/2019 0:00,male,1,1999, +1.04611111,0.9679,1.33,0.99825,123,3/5/2019 0:00,male,0,1999, +1.418,1.30325,1.57083333,1.3145,124,3/5/2019 0:00,male,1,1987, +1.418,1.30325,1.57083333,1.3145,124,3/5/2019 0:00,male,1,1987, +0.7904,0.71209091,0.61514286,0.90054545,125,3/5/2019 0:00,male,1,1999, +0.6872,0.58957143,0.645375,0.76925,126,3/5/2019 0:00,male,1,1999, +0.984,0.8,0.864,0.56,127,3/5/2019 0:00,male,1,1999, +0.8188,0.80718182,0.92336364,0.75844444,128,3/5/2019 0:00,female,1,1999, +1.07428571,0.7974,0.90233333,0.89092308,130,3/5/2019 0:00,female,1,1999, +0.68311111,0.8806,0.587,0.948875,131,3/5/2019 0:00,male,1,1986, +0.69036364,0.70790909,0.647,0.62335714,131,3/7/2019 0:00,male,1,1986, +0.6075,0.5803,0.5397,0.53626316,131,3/7/2019 0:00,male,1,1986, +0.65108333,0.65275,0.73257143,1.369125,135,3/5/2019 0:00,male,1,1999, +0.96833333,0.70971429,0.89314286,0.71518182,139,3/5/2019 0:00,male,1,1997, +0.93771429,0.8199,1.110875,0.87685714,143,3/5/2019 0:00,female,1,1999, +0.816,0.82811111,0.895875,0.68055556,144,3/7/2019 0:00,female,1,2000, +0.83842857,0.67892308,0.78066667,1.10928571,145,3/7/2019 0:00,male,1,2000, +0.58154545,0.88175,0.6398,1.02455556,146,3/7/2019 0:00,male,1,1999, +0.93957143,0.89228571,0.87745455,0.92975,147,3/7/2019 0:00,female,1,1999, +0.75046154,0.89666667,0.625,0.81916667,148,3/7/2019 0:00,male,1,1999, +0.84657143,0.79755556,0.89663636,0.86425,149,3/7/2019 0:00,female,1,1999, +0.89275,0.99433333,0.82233333,0.9162,151,3/7/2019 0:00,male,1,1999, +6.1895,1.7645,0.891,1.9292,152,3/7/2019 0:00,male,1,1999, +0.77425,0.960375,0.92622222,0.70563636,154,3/7/2019 0:00,male,1,1999, +0.70755556,0.6365,1.1422,0.78972727,155,3/7/2019 0:00,male,1,1998, +0.8857,0.78281818,1.163375,0.6775,156,3/7/2019 0:00,male,1,1999, +2.39966667,2.733,1.337,1.3025,157,3/7/2019 0:00,male,1,1998, +1.373,1.25233333,1.35414286,1.2313,158,3/7/2019 0:00,female,1,1999, +1.75933333,3.33966667,1.14625,0.901,159,3/7/2019 0:00,female,1,1999, +0.896,1.24625,0.866875,0.95477778,160,3/7/2019 0:00,female,1,1999, +1.308,1.0075,1.291,2.279,161,3/7/2019 0:00,female,1,1999, +0.9614,0.88583333,0.99866667,0.94233333,162,3/7/2019 0:00,female,1,2006, +0.7855,0.70561538,1.05416667,0.79088889,162,3/7/2019 0:00,female,1,2006, +1.11583333,0.96909091,0.81271429,0.90942857,164,3/9/2019 0:00,female,1,1991, +0.72083333,0.70366667,0.75125,0.46515385,165,3/9/2019 0:00,female,1,1996, +0.829,0.893625,0.82383333,0.73230769,166,3/9/2019 0:00,female,1,1992, +0.52884615,0.59291667,0.61076923,0.7606,168,3/9/2019 0:00,male,1,1979, +0.981125,0.9803,0.72033333,0.92325,168,3/9/2019 0:00,male,1,1979, +0.66344444,0.58917647,0.62266667,0.73090909,169,3/9/2019 0:00,male,1,1994, +1.201125,0.91522222,1.4325,1.1884,173,3/27/2019 15:48,female,1,1994, +0.776,0.89316667,0.79175,1.61433333,174,3/28/2019 13:38,male,1,1997, +0.8386,0.945,0.97783333,0.7218,175,3/28/2019 13:38,male,1,1999, +1.02766667,1.04766667,1.221,1.08577778,176,3/28/2019 13:39,female,1,1999, +0.91245455,0.91183333,1.0544,0.9046,177,5/10/2019 12:02,male,1,1995, +1.49,4.0744,1.449,1.347,177,5/14/2019 12:53,male,1,1995, +0.862,0.97554545,0.9338,0.90075,177,4/2/2019 11:32,male,1,1995, +4.6365,1.8975,3.18866667,1.314,177,5/14/2019 18:35,male,1,1995, +3.6185,3.2785,0.993,1.8435,177,4/9/2019 15:10,male,1,1995, +2.4175,2.537,2.75533333,1.293,177,5/14/2019 18:37,male,1,1995, +0.67207692,0.716125,0.7805,0.7948,178,4/4/2019 12:24,male,1,1997, +1.066,1.0225,0.921,1.20883333,179,4/4/2019 12:25,male,0,1999, +0.76857143,0.86318182,0.98255556,1.093,180,4/4/2019 12:25,female,1,1999, +0.94272727,0.68763636,1.18716667,2.3435,181,4/4/2019 12:25,male,1,1999, +0.5747,0.7233,0.67144444,0.58705556,182,4/4/2019 12:25,male,1,1999, +0.8422,1.11283333,1.08666667,1.179,183,4/4/2019 12:24,female,0,1988, +1.05883333,0.9445,1.4578,0.998375,184,4/4/2019 12:25,female,1,1999, +0.71355556,0.6338,0.77914286,0.64222222,185,4/4/2019 12:25,male,1,1999, +0.56246667,0.73257143,0.81123077,0.720875,186,4/4/2019 12:25,male,1,1998, +1.101125,2.0505,1.3452,1.346,187,4/4/2019 12:25,female,1,1999, +1.07583333,1.0542,1.36388889,0.77314286,188,4/4/2019 12:25,female,1,1999, +1.19085714,1.32566667,2.10175,1.31,189,4/4/2019 12:25,female,1,2000, +1.7505,1.42133333,2.118,2.1285,190,4/4/2019 12:25,female,1,2000, +1.4745,1.08333333,2.80025,1.08666667,193,4/4/2019 12:25,female,0,1999, +0.81775,0.97328571,0.79528571,0.89433333,194,4/4/2019 13:45,male,1,1999, +0.8988,1.29714286,1.37471429,0.79925,195,4/4/2019 13:46,female,1,1999, +1.0275,0.89945455,1.227,1.1,197,4/4/2019 13:55,female,1,1999, +0.85433333,0.96733333,1.147,0.7703,198,4/4/2019 13:55,female,1,2000, +0.92877778,0.81788889,0.805,1.2935,199,4/4/2019 13:59,male,1,1998, +2.3305,1.20828571,1.358,1.30466667,200,4/4/2019 13:57,female,1,1999, +1.981,1.57866667,2.0115,1.150375,201,4/4/2019 13:58,female,1,1999, +1.572,1.312,2.638,2.244,202,4/9/2019 9:03,female,1,1961, +0.7431,0.70033333,1.04533333,0.87890909,204,4/16/2019 8:14,male,1,1985,5 +0.749625,1.021,1.0971,1.612,206,4/9/2019 11:24,male,1,1985, +1.00214286,1.1108,1.047,1.05111111,207,4/9/2019 14:51,female,1,1967, +1.24485714,0.88057143,1.06814286,0.899375,208,4/9/2019 15:10,female,1,1999, +1.0675,1.2282,1.24555556,0.919125,209,4/9/2019 15:10,female,1,2000, +1.4896,1.232,1.281,0.832,210,4/9/2019 15:10,male,1,1998, +0.99542857,0.93333333,1.00791667,1.568,211,4/9/2019 15:10,female,0,1999, +0.95985714,0.89311111,1.2088,1.19542857,212,4/9/2019 15:10,female,1,1999, +0.85735714,0.6662,1.4134,0.99928571,213,4/9/2019 15:10,female,1,1999, +0.55842857,0.6027,0.62378571,0.7051,215,4/9/2019 15:13,female,1,1999, +0.838,0.82588889,0.9448,0.86272727,219,4/10/2019 9:27,female,1,1987, +1.427,2.098,1.19325,1.518,221,4/11/2019 2:39,male,1,1969, +1.02833333,1.08977778,0.97775,0.957,221,4/11/2019 2:40,male,1,1969, +0.7435,1.03633333,0.82166667,0.8744,226,4/17/2019 10:48,female,1,1990, +0.984125,0.812,1.3715,0.69557143,227,4/18/2019 9:45,male,1,1987, +0.462125,0.713,0.84284615,0.7152,231,4/19/2019 18:28,male,1,1995, +0.8540625,1.026,0.97,0.96228571,232,11/10/2019 9:31,female,1,1987,3 +0.91342857,1.0988,1.261,0.9326,232,11/6/2019 7:41,female,1,1987,3 +1.5515,1.2635,1.57066667,1.53657143,233,4/20/2019 19:04,female,1,1993, +1.1595,1.527875,1.1534,1.21357143,235,4/23/2019 8:52,male,0,1972, +0.7601,0.879,0.73288889,0.93277778,237,4/24/2019 10:59,female,1,1981, +0.997,1.21466667,1.13827273,0.9992,240,5/13/2019 22:31,female,1,1995, +1.35875,0.7226,1.2905,0.927875,241,5/14/2019 8:05,male,1,1988, +1.60766667,0.93461538,1.3092,0.91642857,242,5/14/2019 23:00,male,1,1963, +1.61066667,0.928,0.95966667,0.94245455,243,5/14/2019 22:53,male,1,1977, +1.15075,1.365,1.4175,1.61228571,244,5/18/2019 15:03,male,1,1954, +1.655,1.89333333,1.58833333,1.307,245,5/21/2019 9:11,female,1,1970, +1.419,1.314,1.39925,1.92566667,254,5/22/2019 10:23,female,1,1970, +1.114,2.239,1.382,1.163,254,11/7/2019 10:18,female,1,1970, +0.65888889,0.77075,0.75322222,0.7986,271,5/30/2019 23:46,male,1,1993,5 +0.83,1.1545,0.949,1.9535,272,5/27/2019 16:02,female,1,1997, +0.7915,0.87942857,0.89028571,0.85584615,273,5/27/2019 20:14,male,1,1998, +0.56292308,0.56175,0.78945455,0.6128,273,5/27/2019 23:34,male,1,1998, +1.8705,1.32666667,0.7953,0.8994,275,5/28/2019 9:12,female,1,1997, +0.89755556,0.807125,0.73,0.85083333,277,5/28/2019 10:32,male,1,1997, +1.83983333,1.52575,2.177,1.27566667,280,5/28/2019 12:22,male,1,1997, +0.95381818,0.794375,0.93477778,0.9416,280,5/28/2019 12:16,male,1,1997, +0.56846154,0.58425,0.726,0.61276923,280,5/28/2019 12:20,male,1,1997, +1.1004,0.9715,1.3382,1.943,284,5/28/2019 14:19,male,1,1997, +0.66854545,1.0038,0.71181818,1.314,285,5/28/2019 14:22,male,1,1998, +0.8606,0.776,1.27414286,1.13266667,286,6/3/2019 19:04,male,1,1997, +0.7925,0.723375,0.7885,1.40866667,287,6/5/2019 20:49,female,1,1993, +0.94575,0.69854545,0.73457143,0.82945455,287,6/5/2019 20:51,female,1,1993, +0.75418182,0.7635,0.67111111,1.09814286,297,6/7/2019 10:14,male,1,1986, +1.663,0.9845,2.678,1.773,300,6/7/2019 10:22,male,1,1954, +0.68428571,0.7762,0.77233333,0.8705,302,6/7/2019 10:03,female,1,1991, +0.6595,2.4575,0.895,0.979,312,6/11/2019 9:57,male,1,1994, +1.131,1.0414,1.98766667,1.59257143,313,6/17/2019 2:19,male,1,1997, +0.8375,0.77757143,0.83642857,0.7387,313,6/12/2019 17:11,male,1,1997, +1.65266667,1.78766667,2.15725,1.38475,313,6/17/2019 2:12,male,1,1997, +0.6855,0.86533333,0.74666667,0.65153846,316,7/8/2019 11:59,male,1,1995, +1.256,1.50225,1.12971429,1.438,317,7/9/2019 0:13,male,1,1966, +1.0644,0.90466667,0.9005,0.97871429,317,7/9/2019 0:15,male,1,1966, +1.5224,1.72966667,2.00625,1.36533333,319,2/18/2021 9:36,female,1,1970,3 +1.01066667,0.67428571,1.09688889,0.72866667,321,7/24/2019 8:29,male,1,1981, +0.90371429,1.031,1.40083333,1.15183333,322,8/2/2019 15:03,female,1,1975, +1.00785714,0.90214286,1.105,1.18733333,322,8/2/2019 15:04,female,1,1975, +1.21828571,1.20742857,1.21966667,1.057,323,8/3/2019 9:11,male,1,1969, +0.97283333,2.679,1.64,3.835,329,10/1/2019 13:45,female,1,2000, +0.72215385,0.6514,0.6034,0.84184615,330,11/7/2019 23:51,male,1,2000, +0.558,0.82675,0.8116,0.734,330,11/7/2019 23:55,male,1,2000, +0.79357143,0.87075,0.91763636,0.86925,330,10/20/2019 18:24,male,1,2000, +0.64825,0.783125,0.68929412,0.66083333,330,11/7/2019 23:57,male,1,2000, +0.59814286,0.68321429,0.791375,0.91716667,330,11/7/2019 23:48,male,1,2000, +0.62923077,0.6355,0.643125,0.82271429,330,11/8/2019 0:00,male,1,2000, +0.68042857,0.7295,0.7140625,0.63988889,331,11/4/2019 8:36,male,0,1999, +0.628,0.57309091,0.82173333,0.57075,331,11/10/2019 16:34,male,0,1999, +0.76125,0.90666667,0.72416667,0.826875,331,11/5/2019 8:32,male,0,1999, +0.68364286,0.54366667,0.77871429,0.71544444,331,11/10/2019 16:35,male,0,1999, +0.66533333,1.06425,1.007,0.61775,331,11/6/2019 11:16,male,0,1999, +0.57845455,0.58307692,0.57158333,0.52494118,331,11/10/2019 17:14,male,0,1999, +0.585125,0.77613333,0.81514286,0.55315385,331,11/10/2019 16:33,male,0,1999, +1.44585714,1.03771429,1.19066667,1.13571429,332,10/1/2019 13:45,female,1,2000, +1.17471429,0.97383333,0.9002,1.203,332,10/1/2019 13:48,female,1,2000, +2.155,2.477,3.132,8.691,332,10/1/2019 13:44,female,1,2000, +0.71044444,1.58875,0.8578,0.7646,333,10/1/2019 13:43,male,1,2000, +1.101,1.1145,0.83742857,1.40716667,335,10/1/2019 13:44,female,1,2000, +0.83471429,0.94477778,1.01685714,0.93525,336,10/1/2019 13:48,female,1,2001, +0.8755,0.83066667,0.91833333,0.853,337,10/1/2019 13:42,male,1,2000,4 +0.8204,0.9403,0.99966667,0.87214286,337,10/19/2019 11:05,male,1,2000,4 +0.60869231,0.83171429,0.75330769,0.792375,339,10/1/2019 17:03,male,1,2000, +1.135625,0.87271429,1.1765,1.1175,340,10/1/2019 17:04,male,1,1999, +0.84545455,0.77628571,0.9915,0.826125,341,10/1/2019 17:04,male,1,2000, +0.8834,0.81090909,0.83008333,0.94014286,341,10/21/2019 13:24,male,1,2000, +0.88509091,1.07633333,0.86871429,1.19642857,342,11/10/2019 23:39,female,1,2000, +0.9518,0.7792,1.1079,0.928,342,11/11/2019 0:25,female,1,2000, +0.82157143,0.997125,0.98328571,1.18857143,342,11/10/2019 23:49,female,1,2000, +0.889375,0.80108333,0.97875,0.77042857,342,11/11/2019 0:26,female,1,2000, +0.72075,0.96583333,0.902,0.996125,342,11/10/2019 23:59,female,1,2000, +0.7614,0.7808,1.0212,1.51683333,342,11/5/2019 6:40,female,1,2000, +0.896,0.7881,0.97266667,1.22316667,342,11/11/2019 0:14,female,1,2000, +1.53857143,0.7544,1.10525,0.842,343,10/1/2019 17:04,female,1,2001, +0.66555556,0.7482,0.66326667,0.808875,344,11/8/2019 22:51,male,1,2000, +0.82285714,0.605,0.7948,0.95066667,344,11/8/2019 22:58,male,1,2000, +0.822,0.916,0.68283333,0.749,344,11/8/2019 22:52,male,1,2000, +0.75333333,0.756,0.6511,0.6085,344,11/8/2019 23:00,male,1,2000, +0.804625,0.65566667,0.68863636,0.7724,344,11/8/2019 22:54,male,1,2000, +0.6962,0.6215,0.68846667,0.562,344,11/8/2019 23:01,male,1,2000, +0.583,0.73022222,0.65483333,0.94014286,344,11/8/2019 22:47,male,1,2000, +0.711,0.86341176,0.664625,0.64354545,344,11/8/2019 22:56,male,1,2000, +0.6377,0.74753846,0.68325,0.61666667,345,10/19/2019 14:13,male,1,2000, +1.14233333,0.76854545,0.96044444,0.73571429,346,10/1/2019 17:03,female,1,2000, +0.67127273,0.55766667,0.6864375,0.49738462,346,11/10/2019 12:27,female,1,2000, +0.7405,0.57053333,0.7569,0.495,346,11/9/2019 11:35,female,1,2000, +0.641,0.56284615,0.6454,0.51021429,346,11/10/2019 12:29,female,1,2000, +2.60566667,1.511,2.45866667,1.63316667,346,11/9/2019 12:47,female,1,2000, +0.5506875,0.48623529,0.58016667,0.5174,346,11/10/2019 12:30,female,1,2000, +0.76064286,0.666,0.5312,0.48142857,346,11/10/2019 11:26,female,1,2000, +0.61136364,0.81158333,0.67275,0.55971429,346,11/10/2019 12:32,female,1,2000, +0.55935714,0.651,0.71181818,0.67233333,347,10/1/2019 17:03,male,0,2000, +0.65675,0.6552,0.62945455,0.58075,347,11/4/2019 16:50,male,0,2000, +0.768,0.72575,0.561,0.449,347,11/8/2019 11:34,male,0,2000, +2.292,2.7875,2.4555,2.738,347,10/19/2019 13:17,male,0,2000, +0.54281818,0.57592857,0.59286667,0.803375,347,11/5/2019 10:19,male,0,2000, +0.55845455,0.64776471,0.7505,0.73655556,347,11/10/2019 11:13,male,0,2000, +2.8774,1.984,1.92,1.574,347,10/19/2019 13:18,male,0,2000, +0.4394,0.534,0.56628571,0.50273333,347,11/6/2019 11:22,male,0,2000, +1.93633333,1.84966667,1.76933333,1.9315,347,10/19/2019 13:55,male,0,2000, +0.5471875,0.55790909,0.44452941,0.469,347,11/7/2019 18:53,male,0,2000, +0.87277778,0.885,0.79011111,0.85954545,348,10/1/2019 17:03,male,1,2000, +1.36833333,1.1285,0.85641667,0.9224,350,11/4/2019 7:02,female,1,2000, +0.78166667,0.77557143,0.6982,0.90825,350,11/8/2019 9:34,female,1,2000, +0.8405,1.144,0.69581818,0.915,350,11/5/2019 9:18,female,1,2000, +1.335,1.2464,0.86444444,0.7962,350,11/9/2019 13:39,female,1,2000, +0.98416667,0.84644444,0.66926667,0.87314286,350,11/6/2019 10:51,female,1,2000, +0.7793,0.74509091,0.62342857,1.00077778,350,11/10/2019 11:51,female,1,2000, +1.70775,1.69414286,0.914,1.2874,350,10/1/2019 17:04,female,1,2000, +1.001,1.03133333,0.781,0.79233333,350,11/7/2019 13:22,female,1,2000, +0.812125,0.6803,0.75409091,0.73109091,352,11/9/2019 11:23,female,1,2000,4 +0.7098,0.85833333,0.6992,0.65185714,352,11/4/2019 8:24,female,1,2000,4 +0.927,0.7177,0.7223,0.62655556,352,11/5/2019 9:17,female,1,2000,4 +0.7184,0.604,0.66388889,0.5395,352,11/10/2019 12:00,female,1,2000,4 +0.86825,0.933,1.056,0.668,352,11/6/2019 17:56,female,1,2000,4 +0.8312,0.74507692,0.9555,0.61266667,352,11/8/2019 11:46,female,1,2000,4 +0.7665,0.65193333,0.75366667,0.77416667,352,11/3/2019 19:43,female,1,2000,4 +1.07971429,0.972,1.90071429,1.167,353,10/1/2019 17:03,female,1,2000, +0.8076,0.789,0.94875,0.91616667,353,10/1/2019 17:04,female,1,2000, +0.76236364,0.75833333,0.62657143,0.84955556,356,10/7/2019 21:22,male,1,1981, +0.79142857,0.66741667,0.780375,0.81916667,356,10/8/2019 13:39,male,1,1981, +0.793625,0.80622222,0.83476923,0.74714286,356,10/8/2019 17:02,male,1,1981, +0.66128571,0.66721053,0.5675,0.61576923,357,10/8/2019 13:39,male,1,2000, +0.5365,0.6938,0.60455,0.52133333,357,10/8/2019 13:40,male,1,2000, +0.66363636,0.84676923,0.62936364,0.7265,357,10/8/2019 13:38,male,1,2000, +0.96325,0.609375,0.7729,0.66621429,358,10/8/2019 13:40,female,1,2000, +1.047,1.10666667,0.9065,1.05044444,358,10/8/2019 13:39,female,1,2000, +0.8378,0.574,0.842,0.671,358,10/8/2019 13:39,female,1,2000, +1.185,0.98025,0.943,1.08544444,359,10/8/2019 13:39,male,1,2000, +0.80733333,0.8875,0.85558824,1.153,359,10/8/2019 13:40,male,1,2000, +0.56611765,0.5336,0.62577778,0.58766667,360,10/8/2019 13:41,male,1,2000, +0.57111111,0.69016667,0.62283333,0.60292857,360,11/9/2019 14:53,male,1,2000, +0.54227273,0.66775,0.56011111,0.63825,360,11/9/2019 15:08,male,1,2000, +0.739125,0.6737,0.57847059,0.6132,360,11/11/2019 7:03,male,1,2000, +0.56609091,0.56536364,0.6026,0.54118182,360,11/5/2019 8:28,male,1,2000, +0.50130769,0.91792308,0.700625,0.5882,360,11/9/2019 15:01,male,1,2000, +0.583,0.61707143,0.52806667,0.525,360,11/9/2019 15:10,male,1,2000, +0.67346154,0.54075,0.59358333,0.56282353,360,11/7/2019 9:05,male,1,2000, +0.47590909,0.69161538,0.56193333,0.59791667,360,11/9/2019 15:03,male,1,2000, +0.48657895,0.6745,0.58718182,0.57093333,360,11/9/2019 15:13,male,1,2000, +0.6464,0.632,0.6704,0.584,360,10/8/2019 13:39,male,1,2000, +0.52476923,0.61121429,0.78533333,0.48675,360,11/8/2019 11:04,male,1,2000, +0.5046,0.71091667,0.62590909,0.5922,360,11/9/2019 15:07,male,1,2000, +0.5245,0.53654545,0.74057143,0.539,360,11/10/2019 11:39,male,1,2000, +0.72933333,0.81675,0.87275,0.8218,361,10/8/2019 13:39,female,1,2000,3 +0.7065,0.72,0.99555556,0.75466667,362,10/8/2019 13:34,male,1,2000, +0.6725,0.49746154,0.70861538,0.909125,362,10/8/2019 13:39,male,1,2000, +0.53777778,0.546,0.612,0.65090909,363,10/8/2019 13:41,male,1,2000, +0.59733333,0.83466667,0.696,0.74844444,364,10/8/2019 13:39,male,1,2000, +0.61226667,0.65706667,0.593,0.712,364,10/8/2019 13:40,male,1,2000, +0.65722222,0.778,1.14545455,0.8102,365,10/8/2019 13:40,male,1,1999, +0.76444444,0.7084,0.5848,0.71028571,366,10/8/2019 13:40,male,1,2000, +0.6939,0.86733333,0.7458125,0.682375,367,11/7/2019 7:10,female,1,1997, +0.72554545,0.6515,0.90071429,0.95575,367,10/18/2019 11:17,female,1,1997, +0.72345455,0.82842857,0.97114286,0.97666667,367,10/18/2019 20:45,female,1,1997, +0.647,0.7690625,0.81425,0.7688,367,11/8/2019 7:45,female,1,1997, +0.9425,1.646,1.177625,1.2734,367,10/17/2019 16:23,female,1,1997, +0.90271429,0.72523077,0.80988889,0.54683333,367,10/18/2019 11:28,female,1,1997, +0.715625,0.87525,0.8155,0.68761538,367,11/4/2019 6:57,female,1,1997, +0.720125,0.798375,0.72117647,0.74014286,367,11/5/2019 6:48,female,1,1997, +0.69533333,0.8004,0.66263636,0.6136,367,11/9/2019 8:02,female,1,1997, +1.62833333,1.50766667,1.40766667,1.05125,367,10/17/2019 16:40,female,1,1997, +1.43066667,1.47071429,1.05916667,1.09971429,367,10/18/2019 11:40,female,1,1997, +0.6412,0.71964286,0.80755556,0.62255556,367,11/6/2019 6:56,female,1,1997, +0.599125,0.62666667,0.68983333,0.6017,367,11/10/2019 8:55,female,1,1997, +0.658,0.64913333,0.69488889,0.758,367,10/18/2019 11:04,female,1,1997, +0.72807143,0.8117,1.06533333,0.75528571,367,10/18/2019 20:43,female,1,1997, +0.8026,0.73542857,0.7642,0.70054545,368,11/10/2019 23:55,female,1,2000, +0.6784,0.62281818,0.669125,0.57275,368,11/11/2019 0:46,female,1,2000, +0.62038462,0.835375,0.7122,0.61338462,368,11/11/2019 0:55,female,1,2000, +0.74855556,0.82466667,0.6992,0.70275,368,11/11/2019 0:06,female,1,2000, +0.99954545,0.7875,0.97466667,1.04,368,11/10/2019 23:41,female,1,2000, +0.62911111,0.65307143,0.75376923,0.628875,368,11/11/2019 0:20,female,1,2000, +0.99954545,0.7875,0.97466667,1.04,368,11/10/2019 23:41,female,1,2000, +0.965,0.97366667,0.5478125,0.54291667,368,11/11/2019 0:33,female,1,2000, +3.4745,1.4922,2.348,1.5145,369,10/8/2019 19:22,male,1,2000, +0.989375,0.94766667,0.88827273,0.66777778,369,10/8/2019 13:39,male,1,2000, +0.83125,0.65255556,0.97433333,0.68442857,369,10/8/2019 13:41,male,1,2000, +0.62863636,0.80536364,0.80033333,0.65528571,370,11/7/2019 21:44,female,1,2000,3 +2.967,2.37866667,5.9335,1.2645,370,11/4/2019 11:55,female,1,2000,3 +0.94228571,0.68026667,0.53945455,0.63618182,370,11/8/2019 15:09,female,1,2000,3 +0.89514286,1.748,1.10716667,0.786625,370,11/4/2019 11:56,female,1,2000,3 +0.7359,0.69936364,0.783,0.679,370,11/8/2019 16:37,female,1,2000,3 +0.6482,0.869,0.82273333,0.70766667,370,11/6/2019 11:27,female,1,2000,3 +0.90714286,0.5386,0.69378571,0.7365,370,11/10/2019 14:33,female,1,2000,3 +1.366,2.26057143,0.7984,0.75466667,371,10/8/2019 13:40,female,1,2000, +0.634,0.58528571,0.72325,0.65315385,371,11/5/2019 21:55,female,1,2000, +0.87214286,1.13514286,1.33042857,0.6329,371,11/5/2019 22:23,female,1,2000, +0.65075,0.88423077,0.86575,0.59575,371,11/10/2019 16:15,female,1,2000, +0.55754545,1.11025,0.44725,0.46969231,373,10/8/2019 13:40,female,1,2000, +1.232,1.5126,0.61283333,0.54953846,373,10/8/2019 13:41,female,1,2000, +0.748,0.64329412,0.736,0.754,374,10/8/2019 13:40,male,1,2000, +0.75375,0.61046154,0.88025,0.80218182,374,10/8/2019 13:41,male,1,2000, +1.0558,0.99814286,1.43842857,1.23166667,375,10/8/2019 13:40,female,1,1995, +1.36016667,0.86933333,0.99877778,1.11355556,378,10/8/2019 17:02,male,1,2000, +0.55428571,0.59257143,0.6016,0.66323077,379,11/5/2019 11:32,male,1,1999,4 +0.52371429,0.53369231,0.6105,0.54273333,379,11/8/2019 12:31,male,1,1999,4 +0.627375,0.52177778,0.60875,0.56992857,379,11/5/2019 11:34,male,1,1999,4 +0.54264286,0.553,0.56807143,0.655,379,11/9/2019 12:23,male,1,1999,4 +0.581,0.78081818,0.5455625,0.4640625,379,10/8/2019 17:02,male,1,1999,4 +0.62018182,0.59171429,0.60154545,0.56414286,379,11/6/2019 11:45,male,1,1999,4 +0.56038462,0.54815385,0.59007692,0.56353846,379,11/10/2019 13:36,male,1,1999,4 +0.611375,0.66183333,0.7009,0.74833333,379,11/4/2019 18:52,male,1,1999,4 +0.55869231,0.5685,0.61414286,0.5484,379,11/7/2019 17:03,male,1,1999,4 +1.176,1.24,1.03433333,1.164,380,10/8/2019 17:02,female,1,2000, +0.61866667,0.93033333,0.70884615,0.75741667,381,10/8/2019 17:02,male,1,2000, +0.89658333,0.93133333,0.9023,1.063,382,10/8/2019 17:03,female,1,2000, +1.11871429,1.18666667,1.22642857,1.0538,384,10/8/2019 17:02,male,1,2000, +2.00533333,1.091,1.72685714,1.1255,385,10/8/2019 17:02,female,1,2000, +0.87277778,0.93733333,1.07485714,1.083375,387,10/8/2019 17:02,female,1,2000, +0.743,4.875,2.269,5.591,388,10/8/2019 17:02,female,0,2001, +1.1,0.97466667,1.20325,0.84,390,10/8/2019 17:02,male,1,2000, +0.81244444,0.79990909,1.304,1.222875,390,10/8/2019 17:03,male,1,2000, +0.77533333,0.72266667,0.70825,0.64693333,391,10/8/2019 17:02,male,1,1999, +0.7153,0.718,0.65708333,0.80733333,392,10/8/2019 17:02,male,1,2000,3 +1.11466667,1.43633333,1.07466667,0.84725,393,10/8/2019 17:02,female,1,1999, +0.740625,0.6951,0.62957143,0.68116667,394,10/8/2019 17:02,male,1,1990, +0.558,0.5021,0.8142,0.52625,396,11/11/2019 0:32,female,1,2000, +0.688,0.592,0.72,0.658,396,10/8/2019 17:04,female,1,2000, +0.502,0.43633333,0.9104,0.706,396,11/11/2019 0:27,female,1,2000, +0.6422,0.50381818,0.788,0.58608333,396,11/11/2019 0:33,female,1,2000, +0.78366667,1.1725,0.748,0.7674,396,11/7/2019 18:21,female,1,2000, +0.57642857,0.5605,0.634,0.68828571,396,11/11/2019 0:28,female,1,2000, +0.632,0.5210625,0.57385714,0.6465,396,11/11/2019 0:29,female,1,2000, +0.55172727,0.582875,0.69877778,0.60507692,396,11/8/2019 21:33,female,1,2000, +0.60892857,0.48983333,0.70276923,0.6294,396,11/11/2019 0:31,female,1,2000, +0.56591667,0.6006875,0.84571429,0.58507692,396,11/11/2019 0:25,female,1,2000, +0.77942857,0.52475,0.54255556,0.6064,397,10/8/2019 17:02,male,1,1997, +0.5841,0.61233333,0.62911765,0.7328,398,10/8/2019 17:03,female,1,2001, +0.72685714,1.5055,0.8672,0.8528,398,10/8/2019 17:02,female,1,2001, +1.0185,0.82163636,0.8467,1.0175,402,10/14/2019 9:33,male,1,2000, +0.70206667,0.56444444,0.9722,1.34533333,402,10/14/2019 9:33,male,1,2000, +0.70058333,0.5737,0.685,0.68326667,402,10/14/2019 9:47,male,1,2000, +0.6944,0.5418,0.67,0.79545455,403,10/14/2019 9:36,male,1,2001,5 +0.54330769,0.53311111,0.6229,0.664,403,11/7/2019 17:07,male,1,2001,5 +0.6631,0.62630769,0.75627273,0.82125,403,11/6/2019 19:02,male,1,2001,5 +0.57,0.55128571,0.73475,0.59176923,403,11/10/2019 9:46,male,1,2001,5 +0.640625,0.55775,0.63407143,0.78672727,403,11/6/2019 19:14,male,1,2001,5 +0.63535714,0.62633333,0.68384615,0.6247,403,11/10/2019 10:02,male,1,2001,5 +0.63078571,0.572,0.67133333,0.61330769,403,11/6/2019 19:59,male,1,2001,5 +0.70357143,0.5165,0.67307143,0.732,403,11/10/2019 10:13,male,1,2001,5 +0.76776923,0.724625,0.78675,0.926625,404,10/14/2019 9:34,male,1,2000, +0.65421429,0.5704,0.6886,0.75144444,404,10/14/2019 9:46,male,1,2000, +0.708375,0.53928571,0.7902,0.67841667,405,10/14/2019 9:34,male,1,2000, +0.64827273,0.51564286,0.50953846,0.64185714,406,10/14/2019 9:45,male,1,2000, +0.98857143,1.1925,1.3254,0.99036364,407,10/14/2019 9:33,male,1,2000, +0.88557143,0.74166667,0.87069231,0.9215,407,11/8/2019 8:13,male,1,2000, +0.91325,0.9084,0.78908333,0.67314286,407,11/10/2019 20:12,male,1,2000, +0.7695,1.03708333,0.885,1.1642,407,10/14/2019 9:42,male,1,2000, +0.8695,1.0446,0.86116667,1.027375,407,11/9/2019 8:27,male,1,2000, +0.797625,0.80866667,0.96844444,0.77555556,407,11/6/2019 8:31,male,1,2000, +0.83628571,0.87544444,0.96257143,0.897,407,11/10/2019 19:47,male,1,2000, +0.62344444,0.848625,0.75321429,0.69955556,407,11/7/2019 8:19,male,1,2000, +0.9195,0.83681818,0.94571429,0.756125,407,11/10/2019 20:09,male,1,2000, +1.452,1.401,0.56175,1.184,408,11/5/2019 6:19,male,1,2000,4 +0.80130769,0.626,1.37457143,0.60444444,408,11/9/2019 6:32,male,1,2000,4 +0.6647,0.51333333,0.70636364,0.62452941,408,11/10/2019 9:41,male,1,2000,4 +1.6526,0.7018,0.84766667,1.02488889,408,10/14/2019 9:34,male,1,2000,4 +0.67116667,0.59815385,0.88316667,0.62123077,408,11/6/2019 6:28,male,1,2000,4 +1.083,0.5944,0.7432,0.89775,408,11/3/2019 6:24,male,1,2000,4 +1.2886,0.675,0.823,0.60233333,408,11/7/2019 6:35,male,1,2000,4 +1.025,1.5064,0.93344444,0.9452,408,11/4/2019 6:32,male,1,2000,4 +1.09825,0.66336364,0.899,0.672,408,11/8/2019 6:26,male,1,2000,4 +0.61584615,0.66728571,0.71885714,0.6959,409,11/5/2019 7:43,male,0,2000,4 +0.60961111,0.7696,0.63742857,0.6603,409,11/9/2019 7:43,male,0,2000,4 +0.58586667,0.72545455,0.5718,0.60914286,409,11/10/2019 8:23,male,0,2000,4 +0.602,0.6575,0.67916667,0.693875,409,11/6/2019 7:52,male,0,2000,4 +0.46275,0.955125,0.59628571,0.86283333,409,12/16/2019 18:22,male,0,2000,4 +0.7762,0.83425,0.90628571,1.00288889,409,10/14/2019 9:34,male,0,2000,4 +0.56576923,0.62077778,0.6483,0.69742857,409,11/7/2019 7:52,male,0,2000,4 +0.72477778,0.9182,0.6975,0.96271429,409,11/4/2019 17:04,male,0,2000,4 +0.75081818,0.9496,0.52116667,0.65055556,409,11/8/2019 7:52,male,0,2000,4 +0.84081818,0.777,0.93828571,1.00844444,410,10/14/2019 9:35,male,1,1999, +0.66115385,0.85666667,0.76355556,1.120125,411,10/14/2019 9:52,male,1,2000, +0.5855,1.004,0.5275,0.656,411,10/22/2019 19:43,male,1,2000, +0.949375,0.9126,0.74133333,0.85571429,411,11/4/2019 7:22,male,1,2000, +0.64457143,0.65671429,1.402,0.76857143,412,10/14/2019 9:48,male,1,2000, +0.7806,0.81588889,1.181,1.1277,413,10/14/2019 9:48,female,0,1999, +0.79466667,0.79,0.7849,0.85225,413,10/14/2019 9:48,female,0,1999, +0.75021429,0.779,0.78883333,0.728,413,10/14/2019 9:49,female,0,1999, +0.837,0.7385,0.77255556,0.8258,414,10/14/2019 10:01,male,1,2000, +0.57713333,0.747375,0.78781818,0.6613,415,10/14/2019 9:48,male,1,2000, +0.61777778,1.0236,0.7138,0.56333333,415,11/11/2019 2:00,male,1,2000, +0.82355556,0.78388889,0.689125,0.68935714,415,11/11/2019 2:08,male,1,2000, +0.61,0.76875,1.01366667,0.8416,415,11/4/2019 18:08,male,1,2000, +0.787,0.85316667,0.64566667,0.898,415,11/11/2019 2:01,male,1,2000, +0.95075,0.62809091,0.836625,0.8697,415,11/11/2019 2:12,male,1,2000, +0.623625,1.0465,0.758,0.93777778,415,11/5/2019 22:22,male,1,2000, +0.84385714,0.772,0.9198,0.70645455,415,11/11/2019 2:03,male,1,2000, +0.70546667,0.77485714,0.9715,0.64783333,415,11/11/2019 2:14,male,1,2000, +0.8094,0.68722222,0.6848,0.95933333,415,11/7/2019 14:31,male,1,2000, +0.87725,0.7565,0.71208333,0.67841176,415,11/11/2019 2:04,male,1,2000, +0.646,0.804,0.699,0.63509091,415,11/11/2019 2:16,male,1,2000, +0.7641,0.90188889,0.90366667,0.8389,416,10/14/2019 9:42,male,1,1996, +0.70045455,0.68855556,0.62666667,0.67466667,416,10/22/2019 1:29,male,1,1996, +0.9368,1.1258,1.12242857,0.89916667,417,10/14/2019 9:48,male,1,2000, +0.83909091,1.06285714,1.383,0.976,418,10/14/2019 9:48,male,1,2000, +0.93025,0.8846,1.00028571,0.741875,421,10/14/2019 9:48,male,1,2000, +0.65636364,0.52489474,0.66133333,0.64084615,422,11/6/2019 7:59,male,1,2000,3 +0.56535714,0.51342857,0.57185714,0.6696,422,11/11/2019 10:29,male,1,2000,3 +0.76641667,0.78,0.84558333,0.79275,422,10/14/2019 9:48,male,1,2000,3 +0.671625,0.651,0.59115,0.59777778,422,11/7/2019 8:02,male,1,2000,3 +0.52807692,0.5765,0.58038889,1.019,422,12/16/2019 19:45,male,1,2000,3 +0.747,0.6269,0.85338462,1.00328571,422,11/4/2019 8:02,male,1,2000,3 +0.57575,0.568,0.52955556,0.56971429,422,11/8/2019 8:04,male,1,2000,3 +0.71725,0.71444444,0.67005556,0.78033333,422,11/5/2019 7:49,male,1,2000,3 +0.63066667,0.58345455,0.74614286,0.66554545,422,11/11/2019 10:28,male,1,2000,3 +0.65875,0.75228571,0.81341667,0.6726,423,11/4/2019 8:11,male,1,2000, +0.57484615,0.54354545,0.6209,0.88772727,423,11/9/2019 7:57,male,1,2000, +0.64083333,0.59233333,0.60677778,0.58507692,423,11/6/2019 7:52,male,1,2000, +0.724375,0.59209091,0.61788889,0.61463158,423,11/10/2019 9:54,male,1,2000, +0.694,0.90522222,0.842,0.69115385,423,10/14/2019 9:48,male,1,2000, +0.722,0.65976923,0.60745455,0.67677778,423,11/7/2019 7:46,male,1,2000, +0.61236364,0.80177778,0.69691667,0.57423077,423,10/14/2019 9:59,male,1,2000, +0.665,0.62372727,0.74375,0.6401,423,11/8/2019 8:04,male,1,2000, +0.8034,0.9425,0.93571429,0.69716667,424,10/14/2019 9:48,male,1,2000, +0.7192,0.67235714,0.77825,0.7768,425,10/14/2019 9:49,male,1,2000, +0.8606,0.8486,0.8844,0.85211111,426,10/14/2019 13:40,male,1,2001, +0.70644444,0.72261538,0.74166667,0.62016667,426,10/14/2019 13:41,male,1,2001, +0.8685,0.85128571,0.94457143,0.84508333,427,10/14/2019 13:50,male,1,2000, +1.02814286,0.71666667,0.83366667,0.86144444,428,10/14/2019 13:39,male,1,2000, +1.77875,1.81125,1.861,1.936,429,10/20/2019 18:51,male,1,2000,4 +0.5391,0.54058333,0.582,0.59454545,429,12/17/2019 23:19,male,1,2000,4 +0.922,0.90885714,0.87388889,0.746,430,10/14/2019 13:47,male,1,2000, +0.86475,0.587,0.88436364,1.04345455,431,10/17/2019 20:37,male,1,2000, +0.841,0.822,0.551,1.126,431,11/5/2019 22:46,male,1,2000, +0.56433333,0.6315,0.678,0.818,431,11/5/2019 22:47,male,1,2000, +0.93855556,0.95933333,0.909625,1.849,431,10/14/2019 13:49,male,1,2000, +0.7028,0.584,1.2985,0.68628571,432,10/14/2019 13:44,male,0,2000, +0.81771429,0.893875,1.20275,0.82666667,433,10/14/2019 13:42,male,1,2000, +0.70318182,0.91722222,1.08275,1.05344444,433,11/7/2019 8:50,male,1,2000, +0.8694,0.85461538,0.73492308,0.8462,433,11/9/2019 8:22,male,1,2000, +0.699875,0.65357143,0.852,0.66745455,434,10/14/2019 13:41,male,1,2000, +0.895375,0.48777778,0.8795,1.01125,434,10/14/2019 13:39,male,1,2000, +0.87377778,0.737375,0.73423077,0.60236364,435,10/14/2019 13:46,male,1,2001, +1.0962,0.81183333,1.76975,0.85377778,435,10/14/2019 13:43,male,1,2001, +0.891,0.76828571,0.9173,1.003,435,10/14/2019 13:44,male,1,2001, +0.9282,0.6501,1.0436,0.8005,435,10/14/2019 13:45,male,1,2001, +1.501,0.85016667,0.84155556,1.3348,436,10/14/2019 13:47,female,1,2000, +3.56333333,1.337,1.22333333,1.3036,436,10/14/2019 13:44,female,1,2000, +1.46133333,1.667,1.2825,1.7135,436,10/14/2019 13:44,female,1,2000, +1.1322,1.1102,0.9645,1.2124,436,10/14/2019 13:46,female,1,2000, +0.90514286,0.66666667,1.14825,0.66525,437,10/14/2019 13:50,male,1,2000, +0.47907692,0.85257143,0.62830769,0.42641667,438,11/5/2019 18:04,male,1,2000,3 +0.73133333,0.94263636,0.68016667,0.75566667,438,11/9/2019 23:29,male,1,2000,3 +0.75216667,0.8511,0.54744444,0.8135,438,11/6/2019 18:40,male,1,2000,3 +0.66516667,0.61314286,0.54975,0.80342857,438,11/10/2019 22:45,male,1,2000,3 +0.729125,0.82066667,0.65276923,0.8007,438,10/14/2019 13:52,male,1,2000,3 +0.58816667,0.82233333,0.6885,0.9444,438,11/7/2019 19:51,male,1,2000,3 +0.65575,0.63277778,0.634,0.62169231,438,12/16/2019 21:01,male,1,2000,3 +0.6766,0.83325,0.88133333,0.792,438,11/4/2019 20:40,male,1,2000,3 +0.477,0.63833333,0.77877778,0.50815385,438,11/8/2019 20:34,male,1,2000,3 +0.88228571,0.683,0.823,0.681,439,11/7/2019 17:22,male,1,2000, +0.526,0.5573,0.581,0.69083333,439,11/11/2019 17:00,male,1,2000, +0.88228571,0.683,0.823,0.681,439,11/7/2019 17:22,male,1,2000, +0.5204,0.43253333,0.54525,0.61494737,439,11/11/2019 17:01,male,1,2000, +0.74127273,0.52376923,0.942,0.8452,439,11/10/2019 2:26,male,1,2000, +0.47022222,0.53775,0.65114286,0.8137,439,11/11/2019 17:02,male,1,2000, +0.81844444,0.85455556,0.68133333,0.84558333,439,10/14/2019 14:06,male,1,2000, +0.670625,0.54092308,0.51470588,0.93716667,439,11/11/2019 16:36,male,1,2000, +0.666,0.5615,0.7476,0.54416667,439,11/11/2019 16:52,male,1,2000, +0.591,0.578,0.67841667,0.70530769,440,10/14/2019 13:56,male,1,2000, +0.6516,0.53342857,0.69933333,0.58576471,440,11/10/2019 17:53,male,1,2000, +0.5768,0.596625,0.5814375,0.6382,440,11/10/2019 18:02,male,1,2000, +0.53629412,0.527875,0.61717647,0.646,440,11/10/2019 18:04,male,1,2000, +0.56692308,0.534,0.62975,0.68214286,440,10/23/2019 2:22,male,1,2000, +0.57244444,0.511,0.69526667,0.61325,440,11/10/2019 17:57,male,1,2000, +0.57325,0.50666667,0.78315385,0.67873333,440,10/23/2019 14:51,male,1,2000, +0.5185,0.56278261,0.77714286,0.64025,440,11/10/2019 17:59,male,1,2000, +0.6555,0.50366667,0.693,0.59833333,440,10/14/2019 13:52,male,1,2000, +0.63125,0.54857143,0.67625,0.74941667,440,11/10/2019 17:20,male,1,2000, +0.6775,0.513,0.638,0.56942857,440,11/10/2019 18:00,male,1,2000, +1.745,1.2065,1.5545,1.371,441,10/14/2019 13:52,male,1,2000, +0.80445455,0.92266667,0.74963636,0.9138,442,10/14/2019 13:54,female,1,2000, +1.451,0.9985,0.8288,0.60241667,443,10/14/2019 13:52,male,1,1999,3 +0.60471429,0.6407,0.64471429,0.6275,443,12/17/2019 2:03,male,1,1999,3 +0.86525,0.73655556,1.13285714,0.87933333,444,10/14/2019 13:52,male,1,2000, +0.69233333,0.76909091,0.66941667,0.6172,445,11/6/2019 14:09,male,1,2000, +0.612875,0.76690909,0.62409091,0.80466667,445,11/7/2019 10:27,male,1,2000, +0.61633333,0.7065,0.656,0.78,445,11/8/2019 17:45,male,1,2000, +0.76922222,0.88966667,0.93466667,0.9038,445,10/14/2019 13:53,male,1,2000, +0.69683333,0.5971,0.86353846,1.053375,446,11/4/2019 19:41,male,1,2000,4 +0.77908333,0.43376923,0.90475,1.0188,446,11/11/2019 8:00,male,1,2000,4 +0.7363,0.53788889,0.67583333,0.60893333,446,11/6/2019 9:59,male,1,2000,4 +0.55023077,0.59555556,0.785,0.8015,446,12/16/2019 23:47,male,1,2000,4 +0.785,0.7695,1.447,1.08,446,11/11/2019 7:54,male,1,2000,4 +0.6765,0.60977778,0.7689,0.76484615,446,10/14/2019 13:54,male,1,2000,4 +0.76333333,0.5865,1.031,0.85,446,11/11/2019 7:55,male,1,2000,4 +0.842,0.8585,0.85555556,0.85211111,447,11/7/2019 1:30,female,1,2000, +0.8138,0.807875,0.76845455,0.76064286,447,11/10/2019 20:11,female,1,2000, +1.00328571,1.13175,1.14666667,0.743,447,11/7/2019 4:54,female,1,2000, +0.85757143,0.6538,0.63866667,0.592,447,11/10/2019 20:53,female,1,2000, +0.92828571,1.0418,1.10875,1.034875,447,10/14/2019 13:53,female,1,2000, +0.74116667,0.6822,0.83,0.952625,447,11/8/2019 7:26,female,1,2000, +1.09333333,0.851,1.3575,1.108,447,11/4/2019 8:58,female,1,2000, +0.985625,0.79472727,0.85233333,0.7526,447,11/9/2019 7:36,female,1,2000, +0.98145455,1.16466667,1.0886,1.052,448,10/21/2019 18:25,male,1,2000,3 +0.76933333,0.63918182,0.73688889,0.8613,448,11/6/2019 7:42,male,1,2000,3 +0.678375,0.645625,0.7125,0.55678571,448,11/10/2019 9:38,male,1,2000,3 +1.25066667,1.16985714,1.0875,1.1698,448,10/21/2019 19:50,male,1,2000,3 +0.57285714,0.6322,0.81366667,1.08271429,448,11/7/2019 7:18,male,1,2000,3 +0.69033333,0.7578,0.872,0.783125,448,12/16/2019 21:36,male,1,2000,3 +1.5126,4.92066667,1.375,1.15266667,448,10/14/2019 13:52,male,1,2000,3 +0.8839,0.8335,0.752,1.13133333,448,11/4/2019 9:08,male,1,2000,3 +0.74983333,0.70918182,0.843125,1.02533333,448,11/8/2019 8:09,male,1,2000,3 +0.894875,1.3456,1.1038,1.11444444,448,10/21/2019 13:23,male,1,2000,3 +0.68154545,0.7827,0.70277778,0.92044444,448,11/5/2019 7:53,male,1,2000,3 +0.67978571,0.6168,0.94428571,0.709,448,11/9/2019 6:58,male,1,2000,3 +1.764,1.6086,0.875,1.40433333,449,10/18/2019 1:51,male,1,1999,4 +0.59814286,0.83428571,0.760375,0.9532,449,11/5/2019 12:06,male,1,1999,4 +0.61453846,0.65857143,0.54726667,0.66369231,450,10/16/2019 9:47,male,0,2001, +0.53376923,0.6752,0.62583333,0.66923077,450,10/22/2019 22:46,male,0,2001, +0.48185,0.672,0.53475,0.50441667,451,10/16/2019 10:03,male,1,2000, +0.57827273,0.591625,0.66485714,0.53929412,451,10/16/2019 9:47,male,1,2000, +0.5401,0.62445455,0.53705556,0.57385714,451,10/16/2019 9:55,male,1,2000, +0.62326667,0.5675,0.761125,0.7577,452,10/16/2019 9:48,male,1,1997, +0.65725,0.69436364,0.9262,0.9296,453,10/16/2019 9:56,male,1,2000, +0.51944444,0.37463636,0.56685714,0.5964,454,11/10/2019 15:19,male,0,2000, +0.8095,0.4435,0.484,0.5756,454,11/10/2019 15:13,male,0,2000, +0.68833333,0.82066667,0.5915,0.933125,454,11/10/2019 15:14,male,0,2000, +0.95177778,0.549125,0.42084615,0.658,454,11/10/2019 15:32,male,0,2000, +0.6905,1.307,0.666,1.856,454,11/10/2019 15:17,male,0,2000, +0.58688889,0.61764286,0.71018182,0.41946667,454,11/10/2019 15:33,male,0,2000, +0.4965,1.003,0.414,0.1385,454,11/10/2019 15:18,male,0,2000, +0.63111111,0.7562,0.6908,1.224625,454,10/16/2019 9:40,male,0,2000, +1.015,0.937,0.679,0.802,455,11/7/2019 13:11,male,1,2000, +0.807,0.8645,1.025,0.865,455,11/9/2019 7:17,male,1,2000, +0.6812,0.57957143,0.671375,0.5686,455,10/16/2019 9:43,male,1,2000, +0.7304375,1.089,0.90633333,0.90975,456,10/16/2019 9:40,male,0,2000, +0.768125,0.67436364,0.79641667,0.741,456,10/16/2019 9:41,male,0,2000, +0.65923077,0.78883333,0.59942857,0.58325,457,10/16/2019 9:44,male,1,2000, +0.79685714,0.97783333,0.934125,0.9955,458,10/16/2019 9:42,male,1,2000, +0.68875,0.81918182,0.68216667,0.60383333,459,10/16/2019 9:42,male,1,2000, +0.60138462,0.63818182,0.4709375,0.53790909,460,11/5/2019 18:18,male,1,2001, +0.5213125,0.43006667,0.4416,0.58728571,460,11/6/2019 18:17,male,1,2001, +0.7524,0.56057143,0.53018182,0.5134375,460,11/10/2019 13:00,male,1,2001, +0.86228571,0.4785,0.4416875,0.48216667,460,11/5/2019 18:23,male,1,2001, +0.59152941,0.52566667,0.4740625,0.63,460,11/10/2019 12:49,male,1,2001, +0.61225,0.78657143,0.4686,0.47,460,11/10/2019 13:02,male,1,2001, +0.49283333,0.63153333,0.41105882,0.37315,460,11/6/2019 18:08,male,1,2001, +0.5085,0.43768421,0.47225,0.552625,460,11/10/2019 12:52,male,1,2001, +0.5584375,0.52408333,0.4826875,0.58083333,460,11/10/2019 13:04,male,1,2001, +0.65954545,0.68583333,0.60822222,0.62171429,460,10/16/2019 9:45,male,1,2001, +0.5688125,0.60533333,0.4808125,0.48708333,460,11/6/2019 18:14,male,1,2001, +0.4225,0.47864706,0.88688889,0.45376923,460,11/10/2019 12:58,male,1,2001, +0.74557143,0.685625,0.74427273,0.95981818,462,11/4/2019 18:57,female,1,2000,4 +0.728875,0.818875,0.702,0.69293333,462,11/8/2019 19:05,female,1,2000,4 +0.83366667,0.779,0.7462,0.8092,462,11/5/2019 19:06,female,1,2000,4 +0.74575,0.7602,0.70038462,0.874125,462,11/9/2019 21:00,female,1,2000,4 +0.66941667,0.911,0.64546154,0.80066667,462,11/6/2019 19:03,female,1,2000,4 +0.69125,0.68915385,0.668,0.70915385,462,11/10/2019 18:09,female,1,2000,4 +0.75071429,0.801,0.6936,0.87258333,462,10/16/2019 9:45,female,1,2000,4 +0.9815,0.837,0.75371429,0.67072727,462,11/7/2019 19:11,female,1,2000,4 +0.7274,0.56383333,0.68857143,0.7405,463,10/16/2019 9:44,male,1,2000, +0.68877778,0.67307692,0.65055556,1.52333333,464,11/6/2019 9:22,male,0,2001,4 +0.603375,1.02566667,0.595,0.713,464,11/10/2019 12:20,male,0,2001,4 +0.66188889,0.8718,0.66414286,0.81342857,464,10/16/2019 9:48,male,0,2001,4 +0.67444444,0.6805,0.62952941,0.67109091,464,11/7/2019 8:35,male,0,2001,4 +0.5865,0.6146,0.5446,0.584,464,12/19/2019 17:43,male,0,2001,4 +0.6279375,0.73753846,0.627125,0.74271429,464,11/4/2019 8:20,male,0,2001,4 +0.81966667,0.77228571,0.6995,0.81266667,464,11/8/2019 7:08,male,0,2001,4 +0.59627273,0.67584615,0.68554545,0.6879,464,11/5/2019 8:24,male,0,2001,4 +0.58881818,0.66663636,0.58958333,0.56325,464,11/9/2019 10:54,male,0,2001,4 +0.8089,0.80888889,0.74661538,1.1005,465,10/16/2019 9:42,male,1,2000, +1.1272,1.0198,1.585,1.2068,466,10/16/2019 9:59,male,1,2000, +1.03233333,0.98385714,1.65283333,8.336,466,10/16/2019 9:42,male,1,2000, +1.151,0.991,0.966,0.8465,467,10/16/2019 9:48,male,0,2000, +1.0142,1.25525,2.022,1.107,467,10/22/2019 18:32,male,0,2000, +0.455,0.53011765,0.44975,0.50753846,468,10/16/2019 9:48,male,1,2000, +0.51607692,0.54975,0.44489474,0.49291667,468,10/16/2019 9:47,male,1,2000, +0.564,0.64836364,0.74508333,0.61258333,469,10/16/2019 9:49,male,1,2000, +0.44525,0.44541667,0.75454545,0.579,469,10/16/2019 9:50,male,1,2000, +0.728625,0.4886,0.718,0.73426667,470,10/16/2019 9:48,male,1,2000, +0.673,0.74533333,0.73830769,0.86875,471,10/16/2019 9:46,male,1,2000, +1.08566667,1.001,0.78036364,1.04183333,472,11/6/2019 7:41,male,1,2000,3 +0.961,1.289,0.61933333,0.744,472,11/10/2019 11:53,male,1,2000,3 +0.516,0.52775,0.53511111,0.52261538,472,10/16/2019 9:49,male,1,2000,3 +0.75554545,0.98742857,0.89911111,1.01466667,472,11/7/2019 7:42,male,1,2000,3 +0.889,0.83945455,1.245,1.09575,472,12/11/2019 23:18,male,1,2000,3 +0.76527273,0.647,0.8881,0.68377778,472,11/4/2019 7:34,male,1,2000,3 +0.908,0.67557143,0.8812,1.31514286,472,11/8/2019 7:49,male,1,2000,3 +0.758,0.793,1.05371429,1.52028571,472,11/5/2019 7:29,male,1,2000,3 +0.63786667,0.5815,0.8095,0.83922222,472,11/9/2019 8:01,male,1,2000,3 +1.0282,0.674,0.91377778,0.88822222,474,11/7/2019 8:20,male,1,2001, +1.00681818,0.65145455,0.81266667,0.78227273,474,11/10/2019 18:10,male,1,2001, +1.08714286,0.64633333,0.805,0.94557143,474,11/8/2019 7:57,male,1,2001, +1.01,0.939,0.9465,1.00216667,474,10/16/2019 9:47,male,1,2001, +1.02522222,0.7185,0.75633333,0.893625,474,11/9/2019 7:47,male,1,2001, +1.311,0.68066667,0.78,1.43,474,11/5/2019 8:14,male,1,2001, +0.85214286,0.77166667,0.69646154,0.54583333,474,11/10/2019 9:37,male,1,2001, +0.6295,0.53358824,0.67026667,0.66575,475,11/6/2019 9:33,male,1,2001, +0.52408333,0.61975,0.64757143,0.666,475,11/10/2019 15:48,male,1,2001, +0.73883333,0.81333333,0.72883333,0.78166667,475,10/16/2019 9:43,male,1,2001, +0.58808333,0.56636364,0.68472727,0.665,475,11/7/2019 7:33,male,1,2001, +0.752,0.77490909,0.83822222,0.820875,475,10/20/2019 11:48,male,1,2001, +0.59858333,0.58621429,0.66416667,0.70366667,475,11/8/2019 7:54,male,1,2001, +0.71385714,0.5685625,0.72409091,0.908,475,11/5/2019 7:07,male,1,2001, +0.59933333,0.59869231,0.63777778,0.63464286,475,11/9/2019 11:48,male,1,2001, +0.65745455,0.70525,0.61213333,0.63075,476,11/9/2019 13:44,male,1,2000, +0.584,0.62107143,0.6775,0.672,476,11/9/2019 13:45,male,1,2000, +1.165,0.85677778,0.78509091,0.93857143,476,11/8/2019 19:56,male,1,2000, +0.79533333,0.795625,0.832,0.91271429,476,11/9/2019 13:46,male,1,2000, +0.766125,0.72475,0.7253,0.687,476,11/8/2019 19:59,male,1,2000, +0.6785,0.652,0.64106667,0.68963636,476,11/9/2019 13:47,male,1,2000, +0.79490909,0.59772727,0.8717,0.93533333,476,11/8/2019 20:00,male,1,2000, +1.05911111,0.56366667,0.89033333,0.7949,477,10/19/2019 20:08,male,1,1998, +1.04366667,0.87166667,1.03466667,0.83166667,477,11/6/2019 1:14,male,1,1998, +0.68775,0.61863636,0.65291667,0.64735714,478,11/5/2019 7:38,male,1,2000,3 +0.5915,0.6264,0.83075,0.69414286,478,11/9/2019 7:55,male,1,2000,3 +0.631,0.53818182,0.578375,0.6135,478,11/6/2019 7:46,male,1,2000,3 +0.7176,0.59,0.5774,0.94122222,478,11/10/2019 8:02,male,1,2000,3 +0.80690909,0.70881818,0.737125,0.74977778,478,10/19/2019 14:07,male,1,2000,3 +0.56645455,0.56523077,0.56636364,0.52777778,478,11/7/2019 8:07,male,1,2000,3 +0.6205,0.61775,0.73073333,0.71190909,478,11/4/2019 7:49,male,1,2000,3 +0.59966667,0.55444444,0.67041667,0.762,478,11/8/2019 8:01,male,1,2000,3 +0.859,0.84885714,0.91090909,0.7796,480,11/5/2019 11:49,female,1,2000,3 +0.82025,0.88863636,0.80569231,0.67533333,480,11/9/2019 8:15,female,1,2000,3 +0.7166,0.84883333,0.8058125,0.61815385,480,11/6/2019 8:22,female,1,2000,3 +0.7345,0.832,1.036,0.79663636,480,11/10/2019 12:34,female,1,2000,3 +1.09125,1.368,0.97033333,1.165,480,10/20/2019 20:41,female,1,2000,3 +0.74525,0.79428571,0.65392857,0.92966667,480,11/7/2019 11:54,female,1,2000,3 +1.071,0.813,0.97342857,0.96283333,480,11/4/2019 11:45,female,1,2000,3 +0.71228571,0.81654545,0.8212,0.83533333,480,11/8/2019 8:22,female,1,2000,3 +0.72516667,0.85488889,0.856,0.75185714,481,10/22/2019 12:49,male,1,2000, +1.08516667,1.04755556,0.97266667,1.1069,481,10/22/2019 13:08,male,1,2000, +0.69176923,0.63506667,0.81375,0.97775,481,10/22/2019 11:49,male,1,2000, +1.3926,1.96466667,1.72266667,1.412,481,10/22/2019 13:26,male,1,2000, +0.6475,0.63955556,0.7142,0.79630769,481,10/22/2019 12:33,male,1,2000, +1.34057143,1.019,0.69553846,0.75958333,482,11/5/2019 7:01,female,1,1999, +0.78466667,0.60481818,0.72864286,0.5862,482,11/9/2019 6:37,female,1,1999, +0.9209,0.75116667,0.79557143,0.64477778,482,11/6/2019 7:16,female,1,1999, +0.83833333,0.737125,0.72721429,0.67811111,482,11/10/2019 8:41,female,1,1999, +0.66035294,1.0336,0.86011111,0.70025,482,11/7/2019 7:02,female,1,1999, +0.80783333,0.95266667,0.83109091,0.64972727,482,11/4/2019 6:48,female,1,1999, +0.96371429,0.694,0.6375,0.763,482,11/8/2019 7:22,female,1,1999, +0.8554,0.85333333,0.9854,1.5704,484,10/21/2019 16:21,male,1,2000, +0.886,0.77111111,0.770875,0.646,484,11/7/2019 8:50,male,1,2000, +0.95066667,0.725625,1.2585,1.14133333,484,11/4/2019 22:56,male,1,2000, +0.69283333,0.69475,0.92388889,0.7588,484,11/8/2019 8:56,male,1,2000, +1.07266667,2.066,1.67616667,1.9486,484,10/19/2019 20:42,male,1,2000, +0.6864,0.72333333,0.77444444,1.15775,484,11/5/2019 10:14,male,1,2000, +1.18725,0.58914286,0.82428571,0.88116667,484,11/10/2019 13:05,male,1,2000, +1.56775,0.74985714,1.047,1.31871429,484,10/19/2019 20:42,male,1,2000, +0.68125,0.6246,0.84433333,0.8573,484,11/6/2019 8:20,male,1,2000, +0.777,0.54325,0.62125,0.80425,484,11/11/2019 2:19,male,1,2000, +0.96233333,0.98385714,0.80455556,0.94414286,485,11/7/2019 8:14,male,0,2001,3 +0.92033333,0.84933333,0.77633333,0.96066667,485,10/18/2019 15:55,male,0,2001,3 +0.94511111,0.87271429,0.95481818,0.8035,485,11/8/2019 8:12,male,0,2001,3 +0.98442857,0.95828571,0.85533333,0.887,485,11/4/2019 8:36,male,0,2001,3 +0.83354545,0.8395,1.036125,0.88116667,485,11/5/2019 10:24,male,0,2001,3 +0.75035714,0.923375,0.68233333,0.77242857,485,11/9/2019 7:48,male,0,2001,3 +1.04577778,0.8858,0.9995,0.83528571,485,11/6/2019 8:21,male,0,2001,3 +0.6808,0.76566667,0.70646667,0.8417,485,11/10/2019 12:21,male,0,2001,3 +0.618,0.69415789,0.77666667,0.8184,486,10/16/2019 13:39,male,1,2000, +1.0431,0.78171429,0.77744444,0.8755,487,11/10/2019 18:12,male,1,2000,4 +0.76744444,0.6,0.754,0.71081818,487,11/10/2019 18:20,male,1,2000,4 +2.28125,0.70866667,1.064,0.91955556,487,10/16/2019 13:39,male,1,2000,4 +0.6168,0.65075,0.75728571,0.7729,487,11/10/2019 18:16,male,1,2000,4 +0.57073333,0.5594,0.5303125,0.59941667,487,11/10/2019 18:21,male,1,2000,4 +0.8977,0.81045455,0.870625,0.9584,487,10/16/2019 13:53,male,1,2000,4 +0.67083333,0.644375,0.661,0.61892857,487,11/10/2019 18:18,male,1,2000,4 +0.619,0.84572727,0.60976923,0.74055556,487,11/10/2019 18:22,male,1,2000,4 +0.8992,0.64215385,0.70525,0.53,487,10/17/2019 19:27,male,1,2000,4 +0.61458333,0.629375,0.76491667,0.74154545,487,11/10/2019 18:19,male,1,2000,4 +0.6385,0.658125,0.67345455,0.7455,488,10/16/2019 13:40,male,1,2000,4 +0.67081818,0.71391667,0.58746154,0.66233333,488,11/8/2019 10:02,male,1,2000,4 +0.73566667,0.8,0.69377778,0.69173333,488,11/4/2019 7:56,male,1,2000,4 +0.63625,0.813875,0.59890909,0.70391667,488,11/8/2019 10:04,male,1,2000,4 +0.6618,0.78836364,0.69721429,0.69928571,488,11/5/2019 9:53,male,1,2000,4 +0.72169231,0.69953846,0.653,0.67666667,488,11/10/2019 11:24,male,1,2000,4 +0.6898,0.70113333,0.76172727,0.8174,488,10/16/2019 13:39,male,1,2000,4 +0.56866667,0.71266667,0.64823077,0.6582,488,11/6/2019 18:54,male,1,2000,4 +0.61982353,0.63455556,0.6467,0.637,488,11/10/2019 11:26,male,1,2000,4 +0.47984615,0.57022727,0.46933333,0.5127,489,11/7/2019 15:17,female,1,2000,3 +0.6464,0.57192308,0.56209091,0.67678571,489,11/10/2019 15:47,female,1,2000,3 +1.2116,0.89966667,1.194,1.03625,489,10/16/2019 13:45,female,1,2000,3 +0.69825,0.62309091,0.74,0.7945,489,10/17/2019 12:47,female,1,2000,3 +0.97585714,0.714,0.75033333,0.75442857,489,11/8/2019 19:50,female,1,2000,3 +0.59875,0.6756,0.60515,0.745,489,12/11/2019 22:40,female,1,2000,3 +1.158125,0.958125,1.263,0.77,489,10/16/2019 13:46,female,1,2000,3 +0.611,0.67266667,0.59091667,0.80178571,489,11/4/2019 9:21,female,1,2000,3 +0.67072727,0.598125,0.5686,0.56905882,489,11/5/2019 17:39,female,1,2000,3 +0.89016667,0.67272727,0.81871429,0.86842857,489,11/9/2019 17:40,female,1,2000,3 +0.891,0.92157143,0.928625,0.7168,489,10/16/2019 13:47,female,1,2000,3 +0.994,0.61813333,0.75622222,0.79155556,489,11/6/2019 20:34,female,1,2000,3 +0.89016667,0.67272727,0.81871429,0.86842857,489,11/9/2019 17:40,female,1,2000,3 +0.7848,0.653,0.7156,0.95777778,489,10/17/2019 12:45,female,1,2000,3 +0.62836364,0.68926667,0.6095,0.58476923,490,11/5/2019 8:34,male,0,2001,3 +0.51653333,0.56642857,0.5050625,0.47507692,490,11/9/2019 8:02,male,0,2001,3 +0.58869231,0.54833333,0.60246154,0.56646154,490,11/6/2019 19:20,male,0,2001,3 +0.40964706,0.47353846,0.4590625,0.48484211,490,11/10/2019 10:23,male,0,2001,3 +0.71969231,0.98185714,0.777625,0.6915,490,10/16/2019 13:40,male,0,2001,3 +0.54264286,0.59333333,0.55455556,0.52291667,490,11/7/2019 20:20,male,0,2001,3 +0.67435294,1.13366667,0.67622222,0.667625,490,11/4/2019 7:12,male,0,2001,3 +0.4926875,0.47613333,0.4863125,0.49055556,490,11/8/2019 8:27,male,0,2001,3 +0.72433333,0.6586,0.781,0.869,492,10/16/2019 13:45,female,1,2001,3 +0.6595,0.6315,0.77166667,0.69444444,492,11/7/2019 8:06,female,1,2001,3 +0.62553333,0.65269231,0.607,0.59469231,492,11/10/2019 10:55,female,1,2001,3 +0.77442857,0.70873333,0.816,0.8,492,11/4/2019 7:04,female,1,2001,3 +0.99,0.8095,0.991,0.78133333,492,11/8/2019 7:41,female,1,2001,3 +1.27,0.94444444,1.01233333,0.9994,492,10/16/2019 13:43,female,1,2001,3 +0.56961538,0.711,0.65025,0.71433333,492,11/5/2019 9:36,female,1,2001,3 +0.6874,0.65636364,0.7225,0.6522,492,11/8/2019 7:42,female,1,2001,3 +0.744,0.636,0.726,1.90866667,492,10/16/2019 13:44,female,1,2001,3 +0.79541667,0.66190909,0.761,0.748,492,11/6/2019 6:30,female,1,2001,3 +0.70585714,0.7174375,0.76355556,0.69988889,492,11/9/2019 6:27,female,1,2001,3 +0.73961538,0.59528571,1.10666667,0.836,493,10/16/2019 13:43,male,1,2000, +0.56981818,0.5995,0.8189,0.59744444,493,10/16/2019 13:44,male,1,2000, +0.9639,1.089,0.78616667,0.87254545,494,11/4/2019 17:52,female,1,2000,3 +0.68985714,0.71566667,0.72875,0.56983333,494,11/8/2019 21:44,female,1,2000,3 +0.61066667,0.623125,0.70178571,0.63042857,494,11/5/2019 18:08,female,1,2000,3 +0.64676471,0.62841667,0.807,0.62257143,494,11/9/2019 19:41,female,1,2000,3 +0.95825,0.53276471,0.70077778,0.683,494,11/6/2019 17:55,female,1,2000,3 +0.627,0.64855556,0.61753846,0.52368421,494,11/10/2019 12:28,female,1,2000,3 +0.749,1.202,0.81266667,0.86691667,494,10/16/2019 13:43,female,1,2000,3 +1.10333333,0.64611111,0.8897,0.74042857,494,11/7/2019 18:30,female,1,2000,3 +0.7795,0.74757143,0.74471429,0.83425,495,10/16/2019 13:48,male,1,2000,5 +0.64457143,0.76266667,0.7436,0.803,495,11/11/2019 6:49,male,1,2000,5 +0.5558,0.61325,0.89075,0.58133333,495,11/15/2019 8:21,male,1,2000,5 +0.59914286,0.768,0.93275,0.8955,495,11/4/2019 8:17,male,1,2000,5 +0.60785714,0.73,0.907,1.02633333,495,11/12/2019 8:21,male,1,2000,5 +0.53611111,0.58553846,0.6482,0.639,495,11/16/2019 8:22,male,1,2000,5 +0.80588889,0.55111765,0.9415,0.59891667,495,11/5/2019 8:30,male,1,2000,5 +0.67607143,0.7808,0.83166667,0.76616667,495,11/13/2019 8:58,male,1,2000,5 +0.566,0.63184615,0.60927273,0.4814,495,11/17/2019 11:55,male,1,2000,5 +0.69311111,0.72566667,0.59555556,0.922,495,10/16/2019 13:39,male,1,2000,5 +0.76066667,0.68057143,0.8695,0.578,495,11/6/2019 8:49,male,1,2000,5 +0.5634,0.612125,0.82116667,0.7455,495,11/14/2019 8:35,male,1,2000,5 +0.72661538,0.77866667,0.85516667,0.72354545,496,10/16/2019 13:46,female,1,2000,0 +0.7428,0.6055,0.7405,0.61685714,496,11/6/2019 8:34,female,1,2000,0 +0.82444444,1.02444444,0.75714286,0.71427273,496,11/10/2019 6:54,female,1,2000,0 +0.77057143,0.62442105,0.92866667,0.842125,496,11/4/2019 8:15,female,1,2000,0 +0.57278571,0.60244444,0.7285,0.8982,496,11/7/2019 8:01,female,1,2000,0 +0.67625,0.537875,1.1015,0.55233333,496,11/5/2019 8:47,female,1,2000,0 +0.991,0.724,0.53457143,0.7575,496,11/8/2019 7:58,female,1,2000,0 +0.877,1.1155,0.8274,0.91253846,496,10/16/2019 13:44,female,1,2000,0 +0.54790909,0.71525,0.6648,0.75071429,496,11/5/2019 8:48,female,1,2000,0 +0.75692308,0.8545,0.71321429,0.594,496,11/9/2019 7:51,female,1,2000,0 +0.739,0.816875,0.59475,0.744,497,11/8/2019 15:06,male,1,2000, +0.884875,0.83033333,1.13475,1.33225,497,10/16/2019 13:38,male,1,2000, +0.74977778,0.73814286,0.7671,0.87127273,497,11/5/2019 8:28,male,1,2000, +0.6936,0.77942857,0.6225,1.19027273,497,11/8/2019 15:24,male,1,2000, +0.743,0.86225,0.59630769,0.73513333,497,11/6/2019 9:08,male,1,2000, +0.63366667,0.67775,0.6114,0.51393333,498,10/16/2019 13:39,male,1,2000, +0.79444444,0.778625,0.99588889,0.924,499,10/16/2019 13:38,male,1,2001, +0.56655556,0.760875,0.72528571,0.6953,499,10/16/2019 13:39,male,1,2001, +1.53633333,0.6045,0.91125,0.78766667,500,10/16/2019 13:38,male,1,2000, +0.78709091,0.68476923,0.667875,0.6633,501,10/16/2019 13:38,male,1,2000, +0.57491667,0.63545455,0.7018,0.73666667,501,11/7/2019 8:04,male,1,2000, +0.5687,1.00966667,0.5794,0.70766667,501,11/4/2019 7:01,male,1,2000, +0.6392,0.71975,0.74475,0.741,501,11/8/2019 7:13,male,1,2000, +0.58313333,0.64057143,0.684,0.60763636,501,11/5/2019 9:17,male,1,2000, +0.75042857,0.69773333,0.7138,0.75311111,501,11/9/2019 7:27,male,1,2000, +0.63333333,0.71316667,0.71363636,0.60284615,501,11/6/2019 8:45,male,1,2000, +0.56745455,0.6646,0.6454,0.63175,501,11/10/2019 21:54,male,1,2000, +0.61830769,0.72,0.63811111,0.73655556,502,10/16/2019 13:38,male,1,1920, +0.61722222,0.801,0.7636,0.6735,503,11/6/2019 10:00,male,1,2000, +0.903,0.709,0.93771429,0.77485714,503,11/4/2019 7:53,male,1,2000, +0.769,0.61172727,0.77025,0.68914286,503,11/7/2019 11:04,male,1,2000, +0.8351,0.69735714,0.7187,0.7838,503,11/4/2019 8:09,male,1,2000, +0.73736364,0.76990909,0.7115,0.63933333,503,11/8/2019 7:33,male,1,2000, +0.787375,0.6815,0.95083333,0.70825,503,11/4/2019 22:27,male,1,2000, +0.61775,0.6431,0.821,0.537875,503,11/10/2019 9:00,male,1,2000, +1.094,1.21272727,1.01533333,0.92911111,505,10/16/2019 13:40,male,1,2000, +0.75475,0.823,0.749625,0.84525,505,10/22/2019 14:14,male,1,2000, +0.7475,1.15925,1.51716667,1.0355,505,11/5/2019 10:46,male,1,2000, +0.924375,0.85228571,0.89890909,0.7475,505,11/6/2019 10:11,male,1,2000, +0.65742857,0.66053846,0.70272727,0.71775,506,10/16/2019 13:44,male,1,2000,2 +0.519,0.62581818,0.56981818,0.62464286,506,11/7/2019 8:01,male,1,2000,2 +0.895,0.649875,0.650125,0.61236364,506,11/4/2019 8:03,male,1,2000,2 +0.67966667,0.5822,0.71975,0.69725,506,11/8/2019 8:10,male,1,2000,2 +0.6718,0.6975,0.6568,0.54375,506,11/5/2019 8:11,male,1,2000,2 +0.55111765,0.45064286,0.60155556,0.544375,506,11/9/2019 10:38,male,1,2000,2 +0.6844,0.54947619,0.67375,0.6042,506,11/6/2019 8:14,male,1,2000,2 +0.6815,0.768,0.57853333,0.60783333,506,11/10/2019 8:14,male,1,2000,2 +0.926,1.17975,1.08066667,1.1565,507,10/16/2019 13:42,male,1,2000,3 +0.509,0.55714286,0.4832,0.559625,507,10/21/2019 21:46,male,1,2000,3 +2.09957143,1.80575,1.7215,2.2765,507,10/21/2019 23:34,male,1,2000,3 +1.02,0.62126667,0.714,0.67409091,507,11/6/2019 16:04,male,1,2000,3 +0.933625,0.61583333,0.96172727,0.88055556,507,10/21/2019 20:08,male,1,2000,3 +0.483,0.5106,0.58606667,0.6295,507,10/21/2019 21:58,male,1,2000,3 +0.77472727,1.07228571,0.75333333,0.7086,507,11/4/2019 22:08,male,1,2000,3 +0.74925,0.92888889,0.64216667,0.974875,507,11/7/2019 8:13,male,1,2000,3 +0.61466667,0.58069231,0.70127273,0.6275,507,10/21/2019 20:46,male,1,2000,3 +1.388,1.1062,1.309,1.3505,507,10/21/2019 22:09,male,1,2000,3 +0.98266667,0.715,0.68325,0.73,507,11/5/2019 22:32,male,1,2000,3 +0.62133333,0.697,0.74877778,0.752,507,11/8/2019 8:02,male,1,2000,3 +0.4945,0.572,0.65316667,0.63688235,507,10/21/2019 21:23,male,1,2000,3 +1.791,2.15466667,1.45,2.406,507,10/21/2019 23:11,male,1,2000,3 +0.84784615,0.85577778,0.694625,0.8655,507,11/6/2019 15:58,male,1,2000,3 +0.64911111,0.836,0.5993125,0.626,507,11/9/2019 8:01,male,1,2000,3 +1.2421,0.805,0.85583333,0.98844444,508,10/16/2019 13:39,male,1,2001, +0.58707692,0.72990909,0.82571429,0.826,508,11/7/2019 8:31,male,1,2001, +0.74533333,0.67922222,0.74988889,0.82811111,508,11/4/2019 8:06,male,1,2001, +0.68046667,0.56366667,0.647,0.76357143,508,11/8/2019 7:16,male,1,2001, +0.72309091,0.58555556,0.76692308,0.6389,508,11/5/2019 8:57,male,1,2001, +0.78216667,0.5334,0.80083333,0.74407143,508,11/9/2019 8:05,male,1,2001, +0.7884,0.826875,0.98222222,0.78758333,508,11/6/2019 8:46,male,1,2001, +0.5485,0.526125,0.7755,0.74576923,508,11/10/2019 10:08,male,1,2001, +0.729875,0.5965,0.65027273,0.6257619,509,10/16/2019 13:41,male,1,2000, +0.47078947,0.47670588,0.4605,0.53046154,510,11/6/2019 9:28,male,1,2000,4 +0.508,0.46745,0.5112,0.5330625,510,12/17/2019 21:55,male,1,2000,4 +0.59916667,0.56471429,0.58346154,0.58190909,510,10/23/2019 0:11,male,1,2000,4 +0.55063636,0.54464286,0.48378947,0.44907143,510,11/7/2019 8:01,male,1,2000,4 +0.565,0.5380625,0.49922222,0.5002,510,11/4/2019 7:38,male,1,2000,4 +0.49176471,0.4388125,0.50608333,0.481,510,11/8/2019 7:33,male,1,2000,4 +0.559,0.47618182,0.49028571,0.46718182,510,11/5/2019 9:19,male,1,2000,4 +0.5675,0.464125,0.498,0.557,510,11/9/2019 7:34,male,1,2000,4 +1.07175,1.23516667,1.143875,1.33016667,511,10/22/2019 10:53,male,1,2000, +0.74842857,0.81144444,0.6595,1.48811111,511,11/6/2019 10:41,male,1,2000, +0.85236364,0.94175,0.9477,1.09533333,511,10/22/2019 1:08,male,1,2000, +2.723,2.951,2.1004,2.47925,511,10/22/2019 11:08,male,1,2000, +0.6216,0.71257143,0.63527273,0.67005882,511,11/7/2019 8:31,male,1,2000, +0.716,0.79854545,0.81533333,0.872,511,10/22/2019 1:30,male,1,2000, +0.80945455,0.61875,0.67807692,0.9348,511,11/4/2019 19:35,male,1,2000, +0.65633333,0.73009091,0.755875,0.55064706,511,11/8/2019 17:09,male,1,2000, +0.988,0.960875,0.82488889,1.1088,511,10/22/2019 1:43,male,1,2000, +0.66177778,0.68906667,0.676,0.73963636,511,11/5/2019 10:24,male,1,2000, +0.566,0.86228571,0.59477778,0.64592308,512,10/21/2019 18:44,male,1,2000, +0.71611111,0.797,0.74445455,0.71372727,512,11/6/2019 9:09,male,1,2000, +0.634,0.58315385,0.631,0.63872727,512,11/10/2019 14:29,male,1,2000, +0.99033333,0.8959,0.825,0.69985714,512,10/22/2019 18:44,male,1,2000, +0.61718182,0.52641176,0.728625,0.63583333,512,11/7/2019 22:08,male,1,2000, +0.7224375,0.63883333,0.61475,0.8942,512,11/4/2019 8:07,male,1,2000, +0.76785714,0.6341,0.75336364,0.6366,512,11/8/2019 17:41,male,1,2000, +0.82988889,0.88309091,0.859125,0.84057143,512,10/21/2019 18:32,male,1,2000, +0.62682353,0.58763636,0.65355556,0.71811111,512,11/5/2019 9:35,male,1,2000, +0.73125,0.7058,0.57044444,0.62092308,512,11/9/2019 19:44,male,1,2000, +0.9832,0.75857143,1.06411111,0.868,513,11/7/2019 7:30,female,1,1999, +0.91071429,0.94566667,0.936875,0.9786,513,11/4/2019 7:19,female,1,1999, +0.70763158,0.78325,0.84642857,0.8138,513,11/8/2019 22:15,female,1,1999, +0.98677778,0.91666667,0.99944444,0.92028571,513,11/5/2019 14:31,female,1,1999, +0.75527273,0.7115,0.76863636,0.96483333,513,11/9/2019 21:23,female,1,1999, +0.818625,0.5665,0.666,0.8457,513,11/6/2019 10:03,female,1,1999, +0.75975,0.66721429,0.76875,0.859,513,11/10/2019 13:06,female,1,1999, +0.53861538,0.62209091,0.8371,0.67318182,516,11/8/2019 13:46,male,1,2000, +0.6793125,0.6805,0.71875,0.7858,516,11/5/2019 9:41,male,1,2000, +0.6315,0.5552,0.69791667,0.81090909,516,11/9/2019 22:54,male,1,2000, +0.68,0.67566667,0.863625,0.78475,516,11/6/2019 9:51,male,1,2000, +0.65566667,0.68985714,0.76823077,0.65325,516,11/10/2019 11:43,male,1,2000, +0.6153,0.62872727,0.75192308,0.73644444,516,11/7/2019 19:46,male,1,2000, +0.662,0.5845,0.64923077,0.6627,517,11/6/2019 8:52,male,1,2000, +0.521,0.50328571,0.54972727,0.52747368,517,11/12/2019 9:31,male,1,2000, +0.5958,0.58093333,0.68954545,0.64614286,517,11/7/2019 7:17,male,1,2000, +0.58933333,0.59041667,0.688,0.66113333,517,11/8/2019 8:15,male,1,2000, +0.83533333,0.72814286,0.8345,0.704,517,11/5/2019 7:41,male,1,2000, +0.53707143,0.4935,0.62984615,0.6464,517,11/9/2019 7:18,male,1,2000, +0.57007692,0.4987,0.5595,0.68969231,519,11/7/2019 8:13,male,1,2000, +1.10071429,1.07444444,1.084,0.8622,519,11/4/2019 8:13,male,1,2000, +1.0319,0.72925,0.61107143,0.73657143,519,11/8/2019 7:59,male,1,2000, +0.97442857,0.78008333,0.8394,0.9563,519,11/5/2019 7:52,male,1,2000, +0.74375,0.91575,0.66372727,0.84885714,519,11/9/2019 7:22,male,1,2000, +0.82907692,0.68471429,0.734,1.08085714,519,11/6/2019 8:46,male,1,2000, +0.83716667,0.57052941,0.4916,0.8735,519,11/10/2019 8:07,male,1,2000, +2.118,0.984,1.161,0.83933333,520,11/4/2019 22:13,male,1,2000, +0.93816667,0.724375,0.862,0.856,520,11/8/2019 23:34,male,1,2000, +1.03,0.9408,0.981,0.94846154,520,11/5/2019 7:01,male,1,2000, +0.9668,1.3185,0.84944444,1.01611111,520,11/9/2019 6:10,male,1,2000, +1.06077778,0.767625,1.0355,0.9472,520,11/6/2019 6:55,male,1,2000, +1.01657143,0.91528571,1.13,0.951,520,11/10/2019 11:23,male,1,2000, +1.037,0.815625,0.85642857,0.96633333,520,11/7/2019 6:14,male,1,2000, +0.74666667,0.88614286,0.65461538,0.689,521,11/4/2019 7:32,female,1,2000,2 +0.729125,0.62957143,0.71614286,0.51325,521,11/8/2019 7:13,female,1,2000,2 +0.76,0.58372727,0.63416667,1.13122222,521,11/5/2019 9:48,female,1,2000,2 +0.69791667,0.57441176,0.7585,0.563,521,11/9/2019 7:08,female,1,2000,2 +0.62588889,0.63209091,0.58675,0.5775,521,11/6/2019 9:20,female,1,2000,2 +0.6849,0.68572727,1.0675,0.819,521,11/10/2019 10:52,female,1,2000,2 +1.229125,1.05475,0.900625,0.71525,521,10/16/2019 21:32,female,1,2000,2 +0.5778,0.730875,0.65725,0.52464286,521,11/7/2019 7:24,female,1,2000,2 +0.86616667,1.0216,0.94275,0.94871429,522,11/4/2019 7:46,female,1,2000,2 +0.83725,0.98966667,0.809875,0.6105,522,11/8/2019 7:35,female,1,2000,2 +0.8665,1.007875,0.76028571,1.128125,522,11/5/2019 10:03,female,1,2000,2 +0.79466667,1.24728571,0.94,0.86522222,522,11/9/2019 7:27,female,1,2000,2 +0.801375,1.291625,0.909375,0.96516667,522,11/6/2019 9:41,female,1,2000,2 +0.87533333,0.94971429,0.84073333,0.84616667,522,11/10/2019 16:59,female,1,2000,2 +1.03275,1.31671429,1.2275,0.85642857,522,10/16/2019 21:33,female,1,2000,2 +0.9765,0.9225,0.898,0.9659,522,11/7/2019 7:47,female,1,2000,2 +0.68881818,0.7715,0.92525,0.67511111,524,11/8/2019 8:33,female,1,2000,3 +0.836125,0.68372727,0.74963636,0.83088889,524,11/4/2019 7:51,female,1,2000,3 +0.63314286,0.6933,0.79591667,0.61921429,524,11/9/2019 8:14,female,1,2000,3 +0.5615,0.771,0.73142857,0.66333333,524,11/5/2019 9:41,female,1,2000,3 +0.6774,0.74545455,0.74083333,0.858375,524,11/10/2019 10:06,female,1,2000,3 +0.71511111,0.63633333,0.89325,0.6975,524,11/6/2019 9:33,female,1,2000,3 +1.08266667,1.3916,1.017,1.015,524,10/19/2019 20:24,female,1,2000,3 +0.704,0.63483333,0.73576923,0.67809091,524,11/7/2019 8:34,female,1,2000,3 +1.12677778,0.75642857,0.90871429,1.29083333,526,10/16/2019 20:59,male,1,2000, +2.025,1.2096,1.581,1.568,527,10/16/2019 21:37,male,1,2000,4 +0.60290909,0.45582609,0.6384,0.583875,527,10/17/2019 19:55,male,1,2000,4 +0.6092,0.46391667,0.68525,1.06133333,527,11/5/2019 6:38,male,1,2000,4 +0.61915385,0.53708333,0.54883333,0.72083333,527,11/9/2019 6:13,male,1,2000,4 +1.112,1.66916667,1.241,1.614,527,10/16/2019 21:49,male,1,2000,4 +0.89,0.792,1.03666667,0.60266667,527,10/17/2019 20:53,male,1,2000,4 +0.57746154,0.45258333,0.59322222,1.04272727,527,11/6/2019 6:25,male,1,2000,4 +0.57018182,0.455,0.61433333,0.73161538,527,11/10/2019 10:50,male,1,2000,4 +0.72481818,1.0285,0.73925,0.92575,527,10/16/2019 22:01,male,1,2000,4 +3.531,4.496,3.3435,2.94633333,527,10/18/2019 7:31,male,1,2000,4 +0.581,0.503,0.53542857,0.61931579,527,11/7/2019 7:24,male,1,2000,4 +0.80622222,1.0256,0.77563636,0.81509091,527,10/17/2019 19:54,male,1,2000,4 +0.55828571,0.717875,0.63633333,0.70066667,527,11/4/2019 6:25,male,1,2000,4 +0.56125,0.47822222,0.56344444,0.67542857,527,11/8/2019 7:26,male,1,2000,4 +0.685,0.9642,0.80028571,1.22142857,528,10/21/2019 16:25,male,1,1994, +1.11866667,0.78442857,1.19425,0.85271429,529,10/16/2019 22:04,male,1,1978, +0.628,1.82766667,0.950625,1.978,530,10/16/2019 22:28,female,1,2001, +0.51964286,0.58876923,0.49777778,0.5745,530,11/10/2019 16:13,female,1,2001, +0.4724,0.50605882,0.51227273,0.5344375,530,11/10/2019 16:20,female,1,2001, +0.50359091,0.55375,0.62164286,0.5776,530,11/10/2019 16:05,female,1,2001, +0.505,0.59415385,0.54490909,0.55108333,530,11/10/2019 16:14,female,1,2001, +0.50592308,0.5131,0.5616,0.618,530,11/10/2019 16:06,female,1,2001, +0.49746154,0.5088,0.56766667,0.51558824,530,11/10/2019 16:15,female,1,2001, +0.538125,0.4982,0.55113333,0.5455,530,11/10/2019 16:07,female,1,2001, +0.50483333,0.47313333,0.56273333,0.5308,530,11/10/2019 16:18,female,1,2001, +0.69383333,0.87522222,0.70088889,0.66829412,531,10/16/2019 22:24,male,1,1984, +0.6923,0.75233333,1.37616667,0.89916667,532,10/16/2019 22:36,male,1,1987, +1.6385,1.9525,5.467,1.221,533,10/17/2019 20:27,female,1,1961, +1.4274,1.0275,1.18866667,1.768,534,10/16/2019 22:49,male,1,1968, +2.0755,1.98866667,2.49033333,1.391,535,10/16/2019 23:04,male,1,1956, +4.619,2.513,2.7064,2.1675,538,10/26/2019 18:35,female,1,1966,3 +0.70022222,0.72554545,0.75263636,0.882625,538,11/10/2019 10:37,female,1,1966,3 +1.06125,1.15742857,1.396,1.11571429,538,11/10/2019 10:43,female,1,1966,3 +1.4382,1.93325,1.307,1.34166667,538,10/26/2019 19:00,female,1,1966,3 +0.69445455,0.649,0.8238,0.93414286,538,11/10/2019 10:39,female,1,1966,3 +0.97866667,1.2415,1.14655556,1.16457143,538,11/10/2019 10:44,female,1,1966,3 +1.004,1.20475,1.563,1.33742857,538,10/20/2019 14:29,female,1,1966,3 +2.86933333,2.443,1.96475,2.3355,538,10/26/2019 20:05,female,1,1966,3 +0.93418182,0.81975,0.87188889,0.85483333,538,11/10/2019 10:40,female,1,1966,3 +1.27977778,0.83614286,1.18977778,0.836,538,10/26/2019 18:11,female,1,1966,3 +0.91766667,0.8922,0.8762,1.3265,538,11/10/2019 10:35,female,1,1966,3 +1.20383333,1.18916667,1.085125,2.182,538,11/10/2019 10:41,female,1,1966,3 +0.71913333,0.70785714,0.77033333,0.82545455,539,10/17/2019 16:05,male,0,1996, +0.876,0.748625,0.6647,0.6774,540,11/4/2019 6:45,female,1,2000,2 +0.772625,0.6355,0.61690909,0.54010526,540,11/6/2019 7:38,female,1,2000,2 +0.67771429,0.58461538,0.6732,0.53688889,540,11/10/2019 14:47,female,1,2000,2 +0.718,0.67733333,0.71021429,0.98728571,540,11/5/2019 7:32,female,1,2000,2 +0.7196,0.572625,0.62925,0.59833333,540,11/7/2019 6:39,female,1,2000,2 +0.68958333,0.5144,0.794625,0.65272727,540,11/8/2019 6:19,female,1,2000,2 +0.68981818,1.40633333,1.20233333,0.936,540,10/17/2019 16:15,female,1,2000,2 +0.75988889,0.5585,0.70916667,0.55,540,11/9/2019 15:27,female,1,2000,2 +1.05516667,1.21277778,0.9686,1.12916667,542,10/17/2019 17:15,male,1,1978, +0.8895,1.095,1.0665,1.023,544,10/17/2019 16:25,male,1,1950, +1.079375,1.5295,1.0915,1.22183333,545,10/17/2019 16:54,male,1,1960, +0.6772,0.67585714,0.72877778,0.82071429,547,10/17/2019 17:07,male,1,1984, +1.194,1.11357143,1.4812,1.49214286,549,10/17/2019 19:19,male,1,1988, +1.3835,2.8224,1.76566667,1.121,550,10/17/2019 19:46,male,1,1974, +1.567,2.25475,1.6435,1.5305,550,10/17/2019 19:47,male,1,1974, +0.61163636,0.72814286,0.695,0.5176,551,10/17/2019 19:45,male,0,1985, +1.7908,2.9384,2.029,2.111,552,10/17/2019 20:05,female,1,1977, +0.64772727,0.58914286,0.74072727,0.505,553,10/17/2019 19:59,male,1,1978, +0.6455,0.566375,0.656,0.4721,554,10/17/2019 20:17,female,1,1968, +2.164,1.4235,2.71866667,1.72266667,555,10/17/2019 20:31,male,1,1964, +0.5295,1.03,0.768,0.911,556,10/17/2019 21:10,female,1,1989, +0.746,1.29466667,1.4214,1.3625,556,10/19/2019 12:29,female,1,1989, +0.88966667,0.718,0.8827,0.85046154,557,10/20/2019 20:45,female,1,1977, +1.05911111,0.95816667,0.9792,0.931,562,10/21/2019 22:42,female,1,1987, +2.919,1.123,1.05,1.81925,563,10/19/2019 19:29,male,1,1984, +1.215625,1.65466667,1.241375,0.804,563,10/21/2019 23:15,male,1,1984, +0.82,1.06685714,1.01288889,0.97271429,564,10/21/2019 18:42,female,1,1977, +1.26957143,0.96842857,1.33125,1.5532,564,10/22/2019 13:10,female,1,1977, +0.82,1.06685714,1.01288889,0.97271429,564,10/21/2019 18:42,female,1,1977, +2.6875,2.0695,2.69066667,2.59133333,565,10/21/2019 17:20,male,1,1963, +2.776,2.26375,1.928,3.035,565,10/21/2019 17:35,male,1,1963, +1.51757143,1.7255,1.4982,1.784,566,10/21/2019 16:39,female,1,1956, +0.91842857,0.81115385,0.7872,1.0062,567,10/17/2019 23:15,male,1,1975, +1.3434,1.0592,1.09757143,2.4795,568,10/18/2019 12:22,female,1,1981, +1.0436,0.7249,1.23428571,0.78863636,568,10/19/2019 10:59,female,1,1981, +0.7825,0.7297,0.87866667,0.77546154,569,10/18/2019 12:41,male,1,1980, +0.77657143,1.0175,0.89511111,0.81244444,570,10/18/2019 13:26,female,1,1978, +0.762,0.6095,0.725,0.749,571,10/18/2019 14:09,male,1,1978, +0.9075,0.83133333,1.32,0.916,571,10/19/2019 13:51,male,1,1978, +1.075625,0.92681818,0.964,0.77744444,575,10/18/2019 16:30,male,0,1977, +0.67642857,0.97116667,0.9015,1.04275,580,10/18/2019 18:19,female,1,1981, +2.1156,1.55014286,1.816,1.2534,580,10/18/2019 17:52,female,1,1981, +1.85075,1.4405,1.6426,1.15,580,10/18/2019 17:53,female,1,1981, +1.152125,1.24083333,1.27525,1.1695,580,10/18/2019 17:54,female,1,1981, +3.0595,6.214,2.141,2.19316667,581,10/18/2019 17:55,male,1,1955, +0.64911765,0.6036,0.9555,0.74671429,582,10/19/2019 14:04,male,1,2000, +2.15357143,1.41166667,1.751,2.084,582,10/19/2019 14:19,male,1,2000, +0.68376923,0.63091667,0.809625,0.587,582,10/19/2019 13:21,male,1,2000, +1.9765,2.177,2.0215,2.10475,582,10/19/2019 14:39,male,1,2000, +1.126,1.22716667,1.39633333,1.1722,582,10/19/2019 13:46,male,1,2000, +1.2745,1.322,1.43625,0.79983333,583,10/18/2019 17:59,female,1,1976, +2.3915,2.78,2.64,1.52575,584,10/18/2019 18:17,female,1,1960, +2.319,1.914,1.828,3.0345,585,10/18/2019 18:34,male,1,1960, +0.84571429,1.21354545,0.70355556,0.64116667,587,10/18/2019 18:48,male,1,1982, +0.750375,0.97114286,0.89163636,0.52958333,588,10/18/2019 20:39,male,1,1995, +0.68709091,0.70166667,0.72436364,0.88418182,588,10/18/2019 20:56,male,1,1995, +0.648,0.61,0.612,0.64685714,588,10/18/2019 18:54,male,1,1995, +1.167,6.822,1.2365,1.28875,589,10/18/2019 18:56,male,1,1980, +0.96157143,0.83485714,1.09233333,0.79233333,589,10/18/2019 18:57,male,1,1980, +0.82725,1.1695,1.05588889,0.98655556,591,10/18/2019 19:05,male,1,1947, +1.4844,1.924,1.3795,1.48975,591,10/18/2019 19:06,male,1,1947, +0.724,0.64790909,0.58321429,0.5535,592,10/18/2019 19:00,male,1,1984, +0.82785714,0.69327273,0.76528571,0.5765,593,10/21/2019 20:41,male,1,1989, +1.07625,1.1555,1.48772727,0.8412,594,10/18/2019 19:22,male,1,1958, +0.880375,0.74966667,0.96027273,0.6154,595,10/18/2019 19:17,male,1,1987, +1.061,1.539,0.89742857,1.54,596,10/18/2019 19:40,female,1,1975, +1.5015,1.98966667,1.673625,2.367,597,10/18/2019 20:15,male,1,1966, +0.77516667,0.6875,0.8933,0.69177778,598,10/18/2019 20:56,female,1,1987,2 +1.060125,0.855,0.98733333,0.7739,599,10/19/2019 10:14,male,1,1989, +0.75344444,0.83828571,0.734,0.82254545,600,10/19/2019 14:26,male,0,1985, +3.22033333,5.005,4.095,2.8885,601,10/18/2019 21:29,male,1,1954, +0.62228571,0.6878,0.84957143,0.57286667,602,10/19/2019 14:05,female,1,1985, +1.312,2.143,1.918,1.222,603,10/20/2019 15:03,female,1,1977, +0.932,1.15566667,1.22566667,1.6635,604,10/19/2019 13:54,female,1,1969, +0.86457143,1.2715,0.89983333,1.17144444,605,10/18/2019 21:15,female,1,1964, +1.414,1.0963,1.2706,1.0394,606,10/19/2019 13:33,male,1,1955, +1.09166667,1.33583333,1.39633333,1.367625,608,10/18/2019 22:14,male,1,1979,2 +1.77575,1.49475,1.4535,1.236,608,10/20/2019 18:49,male,1,1979,2 +1.83,1.3728,1.372,1.1052,609,10/18/2019 22:37,female,1,1949,2 +0.9857,1.147,1.1456,0.73444444,610,10/18/2019 22:56,male,1,1970,2 +0.839125,1.01725,0.93011111,0.89328571,611,10/18/2019 23:10,female,1,1962,3 +0.5702,0.6318,0.58021429,0.6774,613,10/19/2019 0:37,male,1,2000, +0.45747059,0.5268,0.58973333,0.54985714,613,10/19/2019 0:38,male,1,2000, +1.618,1.6185,1.454,1.747,614,10/19/2019 2:47,male,1,1954, +1.8588,1.378,1.16466667,1.38466667,615,10/19/2019 10:43,female,1,1989, +0.6644,0.76118182,0.613875,0.67344444,616,10/19/2019 11:08,male,1,1989, +1.359875,1.371,1.7052,1.4514,617,10/19/2019 11:24,female,1,1988, +0.59146667,0.7417,0.60233333,0.567,618,10/19/2019 11:27,male,1,1987, +0.606,0.736,0.7532,0.62446154,620,10/19/2019 11:21,male,1,1989, +2.00225,2.24566667,2.074,1.7744,622,10/19/2019 11:48,female,1,1957, +0.8145,0.807,0.8741,0.8633,623,10/19/2019 11:47,male,1,1978, +0.8624,1.013,1.40777778,1.34,624,10/19/2019 11:50,female,1,1979, +1.027,1.01183333,0.75185714,1.2115,626,10/19/2019 11:58,male,1,1969, +2.14833333,1.8458,2.027,2.20475,627,10/19/2019 12:17,male,1,1964, +2.69075,1.787,2.286,2.50033333,629,10/19/2019 12:54,female,1,1945, +0.7276,0.7875,0.99875,0.8341,630,10/19/2019 12:50,male,1,1987, +1.101625,1.02577778,1.261,1.06257143,631,10/19/2019 13:10,female,0,1987, +0.672,1.031,0.6528,0.81966667,632,10/19/2019 13:22,female,1,1985, +1.4376,0.84885714,0.82608333,0.89371429,632,10/19/2019 13:11,female,1,1985, +0.78711111,0.765,0.90083333,0.82153846,633,10/22/2019 16:11,female,1,1980, +0.749,0.9445,0.757,0.7715,633,11/10/2019 22:12,female,1,1980, +0.89066667,1.03225,0.7474,0.971,633,11/10/2019 22:20,female,1,1980, +1.2342,1.36885714,1.52575,1.497,633,10/21/2019 19:53,female,1,1980, +0.99883333,1.26822222,0.85833333,1.195125,633,10/22/2019 16:28,female,1,1980, +0.775875,1.19585714,1.145,0.59375,633,11/10/2019 22:14,female,1,1980, +0.63841667,1.2276,1.33766667,0.962375,633,11/10/2019 22:21,female,1,1980, +0.84077778,1.0578,0.756,1.0434,633,10/21/2019 21:14,female,1,1980, +1.07433333,1.3965,1.36,1.18928571,633,10/22/2019 16:29,female,1,1980, +0.69271429,1.05,1.01333333,0.844,633,11/10/2019 22:16,female,1,1980, +4.0465,4.301,3.078,3.38975,633,10/21/2019 22:36,female,1,1980, +0.70033333,0.76533333,0.75233333,0.585,633,11/10/2019 22:09,female,1,1980, +0.72457143,1.106125,0.94772727,0.73057143,633,11/10/2019 22:18,female,1,1980, +1.17416667,1.5226,1.13088889,1.15,633,10/20/2019 11:41,female,1,1980, +0.93818182,0.60558333,0.907375,0.7896,633,10/22/2019 15:28,female,1,1980, +3.5935,2.128,1.3275,1.65566667,634,10/19/2019 13:55,male,1,1969, +2.0248,4.672,1.23866667,2.0715,635,10/19/2019 13:58,female,1,1952, +1.4244,1.0974,1.0189,0.985,636,10/19/2019 14:12,female,1,1984, +0.738,0.62093333,0.63076923,0.72925,638,10/19/2019 14:25,male,1,1985, +2.86433333,1.727,1.86866667,1.36242857,639,10/19/2019 14:36,female,0,1960, +1.08675,1.0537,1.19685714,1.091,640,10/19/2019 14:42,female,1,1977, +0.7254,0.61978571,0.62516667,0.785,641,10/19/2019 14:43,male,1,1981, +0.885,0.75728571,1.09422222,1.1806,642,10/19/2019 14:56,female,1,2001, +1.882,2.424,1.146,1.756,643,10/19/2019 14:57,female,1,1953, +1.007,0.7172,1.17725,1.061875,644,10/19/2019 15:07,male,1,1983, +1.7075,1.8684,1.4825,1.5052,645,10/19/2019 15:18,female,1,1973, +0.87571429,1.05871429,0.72275,0.708,648,10/19/2019 15:38,female,1,1980, +0.70375,0.945,0.7231,0.66527273,649,10/19/2019 15:28,female,1,1987, +0.5828125,0.55988889,0.5565,0.57061538,650,10/19/2019 16:49,male,1,1970, +0.789375,1.186,0.76605556,0.88328571,651,10/19/2019 15:41,female,1,1986, +0.7403,0.67292308,0.827125,0.851,653,10/19/2019 15:38,female,1,1989, +0.99325,1.15433333,1.31466667,0.75377778,654,10/19/2019 16:01,male,1,2001, +0.89471429,0.67927273,0.689,0.6144,654,10/19/2019 16:02,male,1,2001, +0.90622222,0.96175,1.21211111,0.834625,654,10/19/2019 15:57,male,1,2001, +0.884,0.80644444,1.2145,0.81711111,654,10/19/2019 15:59,male,1,2001, +1.43266667,0.81883333,0.8295,0.88633333,655,10/19/2019 15:49,female,1,1981, +1.44566667,1.618,1.1135,0.94057143,656,10/20/2019 11:24,male,1,1975, +1.387,1.247,1.4396,1.49733333,657,10/19/2019 16:04,female,1,1961, +1.93966667,1.86,1.5632,1.54175,657,10/19/2019 16:05,female,1,1961, +2.35714286,1.808,2.591,1.9745,657,10/19/2019 16:05,female,1,1961, +0.719,0.81266667,0.76742857,0.79185714,658,10/19/2019 16:04,male,1,1988, +1.76366667,2.2874,2.021,1.14583333,659,10/19/2019 16:09,female,1,1963, +1.04757143,0.78444444,0.76523077,0.62111111,660,10/19/2019 16:19,male,1,1964, +1.35866667,1.07766667,1.080625,1.481,662,10/19/2019 16:33,female,1,1978, +0.69933333,0.53325,0.892,0.948,663,10/19/2019 16:46,male,1,2000, +1.3508,1.663,1.25783333,1.32777778,664,10/19/2019 16:38,female,1,1954, +0.6288,0.6438,0.72454545,0.83114286,665,10/19/2019 16:57,female,1,2000, +1.85728571,1.0616,1.454,1.17583333,669,10/19/2019 16:57,male,1,1986, +1.1966,1.69533333,1.29375,1.33066667,672,10/19/2019 22:42,male,1,1975, +1.664,2.104,2.808,1.61675,672,10/19/2019 22:40,male,1,1975, +3.1415,2.85933333,1.28533333,1.7245,673,10/21/2019 18:55,female,1,2000, +2.62816667,1.754,1.6185,2.626,674,10/19/2019 17:02,male,1,1982, +4.11566667,1.8565,1.60266667,1.49033333,676,10/20/2019 16:16,male,1,1967, +1.573,1.5834,1.46214286,1.3594,677,10/19/2019 19:22,female,1,1985, +1.573,1.5834,1.46214286,1.3594,677,10/19/2019 19:22,female,1,1985, +0.7934,0.73054545,0.61388889,0.821,678,10/19/2019 19:23,female,1,1987,3 +0.65645455,0.50983333,0.76908333,0.5365,678,10/19/2019 19:24,female,1,1987,3 +1.55766667,1.4732,1.28785714,1.25833333,679,10/20/2019 9:30,female,1,1973, +1.858,1.753,1.43366667,1.65816667,680,10/19/2019 19:32,female,1,1972, +1.33811111,1.19811111,1.0955,0.77666667,682,10/19/2019 19:40,female,1,1962, +0.853,1.088,0.833,0.86066667,683,10/19/2019 19:41,female,1,1980, +0.74942857,1.06925,0.889625,0.61871429,684,10/20/2019 14:44,male,1,1983, +3.28466667,3.35433333,3.0115,1.897,685,10/19/2019 19:47,male,1,1965, +1.369625,1.688,1.483,1.621,687,10/19/2019 19:50,male,1,1974, +1.07466667,0.958625,0.847875,1.1546,688,10/19/2019 19:53,male,1,1969, +0.70075,0.919,0.532,1.129,690,10/19/2019 19:55,female,1,1988, +0.70075,0.919,0.532,1.129,690,10/19/2019 19:55,female,1,1988, +1.8124,1.23666667,1.2505,1.26833333,691,10/19/2019 20:01,male,1,1965, +0.72344444,0.57836364,0.53345455,0.74606667,692,10/19/2019 19:56,male,1,1985, +1.3665,1.89,1.367,1.33966667,693,10/19/2019 20:03,female,1,1972, +1.851,2.0025,1.8385,1.4775,694,10/20/2019 17:20,male,1,1965, +1.2932,1.4652,1.47,1.30633333,695,10/19/2019 20:17,male,1,1974, +0.737625,0.741875,0.7175,0.5998,696,10/19/2019 20:15,female,1,1979, +1.57266667,1.07433333,1.51916667,1.549,697,10/19/2019 20:15,female,1,1980, +5.98,1.035,2.987,7.223,698,10/19/2019 20:29,female,1,1946, +1.146,1.11633333,0.48,0.838,699,10/19/2019 20:24,male,1,1988, +0.74022222,0.72275,0.62565,0.9974,700,11/7/2019 23:35,male,0,1986,4 +0.69166667,0.5613,0.65275,0.72145455,700,11/9/2019 22:03,male,0,1986,4 +0.726,0.58975,0.696,0.7506,700,11/7/2019 23:50,male,0,1986,4 +0.55070588,0.54525,0.62541667,0.59472727,700,11/10/2019 11:16,male,0,1986,4 +0.7305,0.53264286,0.709,0.6669375,700,11/8/2019 0:04,male,0,1986,4 +0.573,0.591,0.55438462,0.54958824,700,11/10/2019 11:30,male,0,1986,4 +0.81257143,0.8086,0.96166667,0.923,700,10/19/2019 20:26,male,0,1986,4 +0.6911875,0.553125,0.64514286,0.78966667,700,11/9/2019 21:45,male,0,1986,4 +0.93828571,1.32133333,1.13225,1.195125,702,10/19/2019 20:42,male,1,2000, +0.72614286,0.567,0.65115385,0.8745,702,11/5/2019 20:51,male,1,2000, +1.03054545,0.736,0.6033,0.61342857,702,11/8/2019 19:21,male,1,2000, +1.422,1.28175,1.33414286,1.81516667,702,10/19/2019 21:06,male,1,2000, +0.6655,0.62166667,0.767,0.68666667,702,11/5/2019 20:53,male,1,2000, +0.6972,0.67364706,0.644,0.70433333,702,10/19/2019 21:24,male,1,2000, +0.64207692,0.637625,0.6614,0.743875,702,11/6/2019 19:48,male,1,2000, +0.62435714,0.55881818,0.62822222,0.63878571,702,11/12/2019 14:22,male,1,2000, +4.6,2.12625,2.335,1.48766667,702,10/19/2019 20:30,male,1,2000, +2.2355,2.59,2.3615,2.83366667,702,10/19/2019 21:36,male,1,2000, +0.65781818,0.61285714,0.63033333,0.6912,702,11/7/2019 20:02,male,1,2000, +0.68053846,0.61077778,0.6278,0.65233333,702,11/12/2019 14:23,male,1,2000, +1.255125,0.58964286,0.72633333,0.78455556,703,10/19/2019 20:33,male,1,1974, +1.24725,1.29,1.31875,1.258,704,10/20/2019 12:38,female,1,1971, +1.1889,0.76414286,1.019,1.22314286,704,10/20/2019 12:39,female,1,1971, +0.85109091,1.02633333,1.18283333,1.7785,705,10/19/2019 21:20,male,1,1979, +0.8308,1.488,0.7185,0.7746,705,10/19/2019 21:30,male,1,1979, +1.963,1.1618,4.333,1.38666667,705,10/19/2019 21:16,male,1,1979, +1.3745,1.1355,0.72536364,1.0076,706,10/19/2019 20:37,male,1,1986, +3.865,2.424,2.528,2.741,707,10/19/2019 20:48,female,1,1958, +1.72683333,1.12266667,2.5178,1.17,708,10/19/2019 20:46,female,1,1973, +0.91057143,0.572,1.252,1.35028571,709,10/19/2019 20:49,male,1,1961, +0.8575,0.9851,1.1326,0.8413,709,10/19/2019 20:50,male,1,1961, +1.864,1.412,2.25233333,1.634,710,10/19/2019 20:52,male,1,1962, +1.231,1.86233333,2.417,1.348,711,10/19/2019 21:01,female,1,1981, +1.11116667,0.642,1.037,0.8951,712,10/19/2019 21:12,male,1,1981, +1.62383333,1.49457143,2.00466667,2.257,713,10/19/2019 21:06,female,1,1951, +1.5248,1.571,2.194,2.27766667,715,10/19/2019 22:01,female,1,1966, +1.43771429,1.44566667,1.41,1.9115,715,10/19/2019 22:02,female,1,1966, +1.08675,1.20066667,1.82083333,1.15971429,715,10/19/2019 21:38,female,1,1966, +1.036,1.107,0.78771429,1.0325,716,10/19/2019 21:34,male,1,1970, +0.77581818,0.86542857,0.7272,0.7656,718,10/19/2019 21:55,male,1,1987, +2.247,2.4115,2.931,2.1515,719,10/19/2019 22:13,female,1,1945, +2.12875,3.3,3.2175,1.764,719,10/21/2019 16:11,female,1,1945, +1.80916667,1.9995,2.0536,2.0235,720,10/19/2019 22:07,female,1,1967, +1.08714286,0.75166667,0.8095,0.9608,721,10/22/2019 17:58,male,1,1999, +1.3612,0.608,0.6436,0.6153125,721,11/11/2019 3:43,male,1,1999, +0.66472727,0.60236364,0.71111111,0.9042,721,10/22/2019 17:52,male,1,1999, +1.00242857,1.28225,1.16816667,1.18588889,721,10/22/2019 17:59,male,1,1999, +0.68827273,0.57255556,0.77155556,0.624375,721,11/11/2019 3:44,male,1,1999, +0.8412,0.793875,0.927,0.69,721,10/22/2019 17:53,male,1,1999, +1.49066667,1.7065,1.4255,1.833,721,10/22/2019 18:00,male,1,1999, +0.65018182,0.82355556,0.74425,0.80927273,721,11/11/2019 3:45,male,1,1999, +0.94975,1.06766667,0.86957143,0.8603,721,10/22/2019 17:54,male,1,1999, +0.6775,0.84477778,0.70690909,0.7637,721,11/11/2019 3:42,male,1,1999, +0.82928571,1.04085714,0.93475,1.00833333,721,10/22/2019 17:51,male,1,1999, +1.906,1.8926,1.46433333,1.58433333,721,10/22/2019 17:55,male,1,1999, +1.95466667,1.759,2.2272,1.796,724,10/20/2019 15:04,male,1,1950, +0.73063636,0.61090909,0.75488889,0.68908333,726,10/19/2019 23:18,male,1,1989, +0.892625,0.79714286,0.8794,1.05675,728,10/20/2019 0:11,male,1,1978, +1.41733333,1.69814286,1.3356,1.90666667,729,10/20/2019 0:43,female,1,1968, +0.8526,0.89663636,0.91475,0.84727273,730,10/20/2019 13:05,male,1,1985, +0.7277,0.83025,0.91957143,0.71,730,10/20/2019 0:38,male,1,1985, +1.33366667,1.763,1.684,1.748,732,10/20/2019 10:10,female,1,1977, +2.44666667,1.338,2.988,2.72116667,734,10/21/2019 16:03,male,1,1973, +1.3195,1.9995,1.4815,1.72233333,735,10/21/2019 16:28,male,1,1980, +0.7535,0.6858,0.69763636,0.78058333,736,10/20/2019 11:41,female,1,1985, +1.4752,1.3194,0.97863636,0.72371429,737,10/20/2019 11:09,male,1,1959, +1.00857143,0.90922222,1.09414286,1.1758,739,10/20/2019 13:44,female,1,1989, +1.32,1.613375,1.9325,1.327,740,10/20/2019 11:18,female,1,1960, +1.4954,1.59933333,1.32466667,1.48175,741,10/20/2019 11:26,male,0,1972, +1.175,1.23125,1.2485,1.032,742,10/20/2019 11:28,male,1,1979, +1.6366,2.40125,1.485,1.4206,744,10/20/2019 11:40,female,1,1976, +1.18814286,0.917,0.997,0.954,745,10/20/2019 11:38,male,1,1977, +0.82423077,0.72046154,0.856,1.426,746,10/20/2019 11:55,female,1,1983, +1.117125,0.9784,1.1575,0.834,747,10/20/2019 11:49,female,1,1989, +0.7027,0.97288889,0.67141667,0.731,749,10/20/2019 15:46,female,1,2001, +0.59275,0.94183333,0.60607143,0.5805,749,10/20/2019 16:06,female,1,2001, +1.0042,1.29075,1.020625,1.2196,750,10/20/2019 12:22,female,1,1989, +1.17722222,1.465,1.4088,1.413,751,10/20/2019 12:41,male,1,1956, +0.96116667,1.2368,1.1422,0.96366667,752,10/20/2019 12:27,female,1,1987, +1.16383333,1.3955,1.492,1.263,753,10/20/2019 12:25,male,1,1984, +0.8202,0.768375,0.97757143,0.786,754,10/20/2019 12:29,male,1,1969, +0.797375,0.87325,0.9743,0.6471,755,11/10/2019 23:56,female,0,2000, +1.50366667,1.106,0.91814286,1.29133333,755,11/11/2019 1:46,female,0,2000, +0.86355556,0.9355,1.111,1.17714286,755,11/4/2019 9:53,female,0,2000, +0.66244444,0.77116667,0.7008,0.7658,755,11/11/2019 0:52,female,0,2000, +0.65642857,0.9908,0.7262,0.5159375,755,11/5/2019 11:22,female,0,2000, +0.9115,1.22,0.89914286,0.97025,755,11/11/2019 1:13,female,0,2000, +1.0315,0.666,1.02,0.66185714,755,11/10/2019 23:44,female,0,2000, +0.77611111,0.74763636,0.71666667,0.7335,755,11/11/2019 1:25,female,0,2000, +0.75557143,0.66922222,1.13533333,0.86214286,756,10/20/2019 12:40,female,1,1987, +2.053,1.3518,1.608,1.7944,757,10/20/2019 12:44,male,1,1957, +2.229,2.438,2.412,1.81766667,758,10/20/2019 12:48,female,1,1975, +1.17428571,1.151,1.19055556,1.0765,759,10/20/2019 13:00,female,1,1977, +0.708,0.8862,0.903,0.61007143,760,10/20/2019 12:47,female,1,1990, +2.33633333,1.79166667,1.42,1.343,761,10/20/2019 12:54,female,1,1974, +1.41322222,0.67792308,0.696,0.7905,762,10/20/2019 12:50,female,1,1989, +1.6164,1.2995,1.452,1.34071429,763,10/20/2019 12:59,female,1,1985, +0.57891667,0.60146154,0.57407143,0.59675,765,10/20/2019 13:01,male,1,1984, +0.5475,0.60925,0.54866667,0.701,766,10/20/2019 13:11,male,1,1976, +1.3915,1.202,1.637,2.60775,767,10/20/2019 13:13,female,1,1985, +1.25555556,1.2376,0.9175,1.1108,768,10/20/2019 13:21,male,1,1979, +0.80171429,0.625,0.8789,0.63154545,769,10/20/2019 13:24,female,1,1983, +1.55325,0.77485714,1.418,1.19766667,770,10/20/2019 13:24,female,1,2000, +1.469875,1.1484,1.56,1.44975,771,10/20/2019 13:32,male,1,1937, +0.9592,1.2126,1.0685,0.957,773,10/20/2019 18:53,female,1,1987, +1.26988889,0.8708,1.48333333,1.37828571,774,10/20/2019 13:41,female,1,1986, +2.524,2.742,2.038,2.137,776,10/20/2019 13:47,female,1,1957, +3.55,3.9105,2.65,3.0445,777,10/20/2019 13:48,male,1,1956, +0.736125,0.65954545,0.89772727,0.70155556,778,10/20/2019 13:59,female,1,1979, +1.14783333,1.18457143,1.713,1.38425,779,10/20/2019 14:01,female,1,1988, +0.8585,0.787,0.91663636,0.8284,780,10/20/2019 14:05,female,1,1969, +0.9675,0.92575,1.00814286,0.94281818,781,10/20/2019 14:15,female,1,1948, +0.9204,1.20475,1.2105,0.995375,782,10/20/2019 14:14,male,1,1988, +1.50014286,1.54333333,1.4682,1.0925,783,10/20/2019 14:15,male,1,1961, +0.66585714,1.20871429,0.78608333,0.74255556,785,10/20/2019 14:28,male,1,1976, +0.66335714,0.87375,0.85984615,0.64877778,786,10/20/2019 14:36,female,1,1999, +0.56646667,0.648,0.93818182,0.7025,787,10/20/2019 14:41,male,1,1988, +0.90942857,0.90688889,1.0718,1.242625,788,10/20/2019 14:42,female,1,1980, +0.87,0.829375,1.237,0.9775,789,10/20/2019 14:48,male,1,1986, +1.2135,1.064,1.1915,1.3,790,10/20/2019 14:49,male,1,1973, +1.02525,0.966125,0.8985,0.8452,791,10/20/2019 14:56,female,1,1980, +0.64366667,0.57157143,0.72614286,0.7325,793,10/20/2019 15:02,male,1,1967, +1.158,1.1995,1.35125,1.59528571,795,10/20/2019 15:10,male,1,1963, +1.78475,1.09366667,1.8282,1.28,797,10/20/2019 15:22,male,1,1980, +0.97327273,1.089,0.99,1.0855,798,10/20/2019 15:16,female,1,1954, +1.06811111,1.1266,1.21,1.494,799,10/20/2019 15:20,male,1,1988, +1.17333333,1.203,0.928,0.9146,801,10/20/2019 15:31,female,1,1984, +0.6288,0.62842857,0.99377778,0.91166667,802,10/20/2019 15:26,male,1,1985, +0.753,0.77144444,0.8242,0.99266667,803,10/20/2019 15:33,female,1,1989, +0.5222,0.6496,0.61855556,0.65242857,804,11/5/2019 7:54,male,1,2000,4 +0.5825,0.50035,0.61909091,0.5324,804,11/9/2019 7:48,male,1,2000,4 +0.642,0.75,0.50766667,0.581125,804,11/6/2019 7:57,male,1,2000,4 +0.55688889,0.6139,0.63088889,0.55004348,804,11/10/2019 10:05,male,1,2000,4 +0.62141667,0.60690909,0.642375,0.60794118,804,10/20/2019 15:54,male,1,2000,4 +0.6747,0.66555556,0.56191667,0.55633333,804,11/7/2019 8:00,male,1,2000,4 +0.677,0.57783333,0.6432,0.776,804,12/16/2019 17:44,male,1,2000,4 +0.53706667,0.6355,0.91966667,0.50489474,804,11/4/2019 9:24,male,1,2000,4 +0.61430769,0.57435714,0.63883333,0.5615,804,11/8/2019 8:02,male,1,2000,4 +2.724,1.74025,1.60766667,3.01225,805,10/20/2019 15:41,male,0,1952, +0.57155556,0.91233333,1.0829,0.94144444,806,10/20/2019 15:46,male,1,1972, +1.893,1.64575,1.3545,2.01,807,10/20/2019 15:53,male,1,1960, +2.18266667,2.70866667,2.557,3.29566667,809,10/20/2019 15:59,male,1,1949, +1.4384,1.1408,1.2058,1.0527,811,10/20/2019 16:00,female,1,1979, +1.01666667,1.030125,0.875,1.01566667,812,10/20/2019 16:01,female,1,1986, +0.5532,0.6040625,0.56372727,0.59164286,814,10/20/2019 16:11,male,1,1984, +1.36,1.6635,1.4034,1.43375,815,10/20/2019 16:15,female,1,1966, +0.63276923,0.5862,1.14633333,0.7005,817,10/20/2019 16:26,male,1,1974, +0.783,0.72809091,1.1386,0.7905,818,10/20/2019 16:43,male,1,1989, +1.3732,1.30866667,1.41142857,1.56133333,819,10/20/2019 16:32,male,1,1954, +0.829125,1.093,0.65946154,0.754,820,10/22/2019 20:29,female,1,1971, +0.7918,1.039,1.011,0.65783333,820,10/22/2019 19:50,female,1,1971, +1.032,0.916,1.454,1.097,820,10/22/2019 19:53,female,1,1971, +1.2285,1.26185714,1.60366667,1.36183333,821,10/20/2019 16:37,male,1,1951, +0.652,0.81225,0.57025,0.71114286,823,10/20/2019 16:37,male,1,1981, +1.70875,1.6195,1.23571429,1.41,824,10/20/2019 16:43,female,1,1981, +1.413,1.2945,1.65666667,1.12691667,825,10/20/2019 16:40,male,1,1952, +1.319,1.356,1.839,1.651,826,10/20/2019 16:45,female,1,1977, +1.39433333,1.294,1.25,1.2322,826,10/20/2019 16:47,female,1,1977, +4.70866667,2.2635,2.9715,3.896,827,10/20/2019 16:47,male,1,1949, +0.82166667,0.80635714,0.84442857,0.7823,828,10/20/2019 17:14,female,1,1982, +0.688,0.89371429,1.12190909,2.22133333,828,10/22/2019 21:04,female,1,1982, +0.76866667,0.75858333,0.79536364,0.6885,828,10/22/2019 21:19,female,1,1982, +0.52711111,0.63191667,0.561625,0.589,829,10/20/2019 16:46,male,1,2002, +0.7047,0.744,0.62188889,0.65825,830,10/20/2019 16:52,male,1,1973, +1.88233333,2.3335,1.215,1.85771429,831,10/20/2019 16:56,male,1,1954, +0.882,0.83858333,1.34,1.092875,832,10/20/2019 16:57,male,1,1976, +0.882,0.83858333,1.34,1.092875,832,10/20/2019 16:57,male,1,1976, +0.751,0.80372727,0.70376923,1.97833333,833,10/20/2019 16:57,male,1,1987, +0.86833333,0.7841,0.70722222,0.75,835,10/20/2019 17:12,female,1,1984, +0.76766667,0.72111111,0.795,0.78354545,836,10/20/2019 17:13,male,1,1988, +1.18614286,1.48525,1.45,1.95475,837,10/20/2019 17:26,female,1,1967, +0.750375,1.0852,0.8287,0.8806,840,10/20/2019 17:23,female,1,1988, +1.28355556,1.671,1.0978,1.26075,841,10/20/2019 17:27,male,1,1974, +2.8425,1.874,2.104,1.79785714,842,10/21/2019 18:49,male,1,1941, +0.8305,1.1286,0.82242857,0.86233333,843,10/20/2019 17:44,male,1,1975, +1.5445,1.185,1.731,1.67833333,843,10/20/2019 17:43,male,1,1975, +1.514875,1.37983333,1.46033333,1.56066667,845,10/20/2019 17:48,female,1,1964, +0.7924,0.8136,0.65445455,0.79425,846,10/20/2019 18:10,male,1,1983, +1.68633333,1.40216667,1.4865,1.2098,848,10/20/2019 17:51,female,1,1980, +4.71466667,1.04316667,1.1928,1.419,849,10/20/2019 17:56,male,1,1971, +0.75588889,0.77166667,0.6625,0.64115385,850,10/20/2019 17:54,male,1,1986, +1.0155,0.8014,0.9675,1.4906,851,10/20/2019 18:29,female,1,1988, +0.9232,1.059625,0.89727273,0.93783333,852,10/20/2019 18:04,male,1,1959, +1.93375,2.62233333,2.999,1.9355,853,10/20/2019 18:13,male,1,1957, +0.80914286,0.9516,0.91071429,0.73690909,854,10/20/2019 18:13,female,1,1977, +0.5645,0.53258333,0.49278947,0.6115,855,10/20/2019 18:36,male,1,1974, +0.57153846,0.90933333,0.8671,0.72827273,857,10/20/2019 18:32,male,1,1988, +0.72817647,0.70866667,0.85085714,0.96133333,857,10/20/2019 18:58,male,1,1988, +0.7745,0.678,0.82133333,0.7855,857,10/20/2019 19:06,male,1,1988, +1.08316667,1.129,1.282,1.276625,857,10/20/2019 18:31,male,1,1988, +1.4795,1.805,1.69,1.73833333,858,10/20/2019 18:30,male,1,1948, +2.5615,2.262,2.721,2.34,859,10/20/2019 18:32,male,1,1955, +1.61033333,1.832,1.8244,1.627,860,10/20/2019 18:34,male,1,1965, +0.50988235,0.566,0.68333333,0.60866667,861,10/20/2019 18:57,male,1,2000, +0.985625,0.9398,1.157125,1.567,863,10/20/2019 21:29,female,1,1976, +2.776,2.424,2.5376,2.376,864,10/20/2019 18:52,female,1,1976, +1.2385,1.6175,1.81825,1.20075,865,10/20/2019 18:51,female,0,1973, +0.81933333,1.22566667,1.0215,2.175,868,10/20/2019 18:54,female,0,1996, +1.0216,1.40222222,1.116,0.853,870,10/20/2019 19:01,female,1,1980, +1.70283333,1.34757143,1.35766667,1.48225,871,10/20/2019 19:07,female,1,1981, +1.323,1.589,1.17777778,0.94766667,871,10/20/2019 20:14,female,1,1981, +1.791,1.7656,1.26171429,1.13033333,872,10/20/2019 19:12,female,1,1967, +1.20866667,1.32585714,2.29975,1.4764,873,10/20/2019 19:14,male,1,1966, +0.964,1.01128571,0.90275,1.1057,874,10/20/2019 19:14,female,1,1978, +1.9675,1.8092,1.65725,1.53,876,10/20/2019 19:18,male,1,1964, +2.9272,1.08733333,1.5312,2.235,878,10/20/2019 19:32,female,1,1976, +1.00577778,1.35375,2.58066667,1.2116,880,10/20/2019 19:32,male,1,1980, +2.137,1.63533333,1.1948,0.91266667,881,10/20/2019 19:37,female,1,1966, +1.076,1.18733333,1.57333333,1.549,882,10/20/2019 19:40,male,1,1939, +0.81371429,0.7637,0.79433333,0.74944444,883,10/29/2019 18:21,male,1,1967, +1.21433333,1.348,1.309,1.528,884,10/29/2019 18:33,female,1,1950, +2.53633333,2.02428571,2.884,1.256,885,10/20/2019 19:55,female,1,1967, +1.475,1.0574,1.51,1.75366667,887,10/20/2019 20:01,female,1,1977, +0.77488889,0.59083333,1.32125,0.826,888,10/20/2019 20:05,female,1,1989, +0.81569231,0.95228571,1.126,0.9735,889,10/20/2019 20:10,female,1,1978, +1.02783333,1.1945,1.0504,0.68171429,890,10/20/2019 20:24,female,1,1976, +1.484,1.2728,1.01016667,1.27133333,893,10/20/2019 20:43,male,1,1985, +0.797,1.06842857,1.02422222,0.89433333,893,10/20/2019 20:44,male,1,1985, +1.09775,0.870375,0.82672727,1.0148,894,10/20/2019 21:08,male,1,1997, +0.63885714,0.92333333,0.61671429,0.76345455,895,10/20/2019 21:00,male,1,1988, +1.1815,2.2795,1.0364,1.2658,896,10/20/2019 20:51,male,1,1992, +1.01291667,1.7285,1.237,1.46625,897,10/20/2019 21:08,female,1,1980, +1.69975,1.40633333,1.42466667,1.0924,899,10/20/2019 21:27,male,1,1967, +1.3205,1.49766667,1.8816,3.601,900,10/20/2019 21:29,male,1,1977, +0.69533333,0.84871429,0.7718,0.8515,902,10/20/2019 21:33,female,1,1980, +0.80325,0.7013,0.721125,0.78415385,902,10/20/2019 21:34,female,1,1980, +0.68855556,0.52386957,0.648,0.76075,903,10/20/2019 21:29,male,1,1974, +2.59533333,2.10166667,1.66066667,2.032,905,10/20/2019 21:36,male,1,1954, +1.264,1.401,1.7095,1.451125,905,10/20/2019 21:37,male,1,1954, +1.12483333,0.959625,1.216625,1.15425,906,10/21/2019 19:19,male,1,1963, +1.13428571,1.4285,1.41833333,1.12844444,907,10/20/2019 21:43,male,1,1969, +1.15085714,1.03366667,0.88727273,0.89711111,908,10/20/2019 21:49,male,1,1985, +0.77755556,0.622625,0.80792308,0.937125,909,10/20/2019 21:54,male,1,1985, +2.4315,2.70633333,1.5595,1.91525,910,10/20/2019 22:04,female,1,1946, +0.746875,0.659125,0.803,1.29788889,911,10/20/2019 22:09,male,1,1980, +1.141,1.13066667,1.25166667,1.42185714,912,10/20/2019 22:06,female,1,1970, +1.629,1.4638,1.23714286,1.768,913,10/20/2019 22:11,male,1,1980, +0.82623077,0.8725,0.936,1.05,914,10/20/2019 22:23,male,1,1964, +1.0935,1.51333333,1.149,1.25,914,10/20/2019 22:19,male,1,1964, +0.928375,0.94185714,1.0745,0.876,914,10/20/2019 22:22,male,1,1964, +1.13157143,0.923,1.31825,0.969,915,10/20/2019 22:15,female,1,1985, +0.7205,0.973,0.891,0.90883333,916,10/20/2019 22:18,male,1,1974, +0.887,0.671,0.652,0.80166667,917,10/21/2019 23:34,male,1,1982, +0.5164,0.55816667,0.8279,0.7097,918,10/20/2019 22:25,male,1,1984, +0.987625,0.99783333,0.84630769,0.9138,920,10/20/2019 22:30,male,1,1971, +0.8818,1.2898,0.9075,0.96181818,921,10/20/2019 22:45,male,1,1968, +1.45966667,1.36866667,1.39825,1.377625,922,10/20/2019 23:07,male,1,1965, +1.07866667,1.32666667,1.17142857,1.317875,923,10/20/2019 23:07,male,1,1957, +1.85,2.014,1.58366667,1.8125,924,10/20/2019 23:15,female,1,1957, +3.0915,2.9985,1.949,1.949,924,10/20/2019 23:12,female,1,1957, +1.44166667,1.5385,1.6235,1.76571429,924,10/20/2019 23:16,female,1,1957, +2.107,2.562,3.842,2.398,924,10/20/2019 23:13,female,1,1957, +2.9635,2.3375,2.914,2.5445,924,10/20/2019 23:17,female,1,1957, +1.4712,1.30225,1.27525,1.74433333,924,10/20/2019 23:14,female,1,1957, +1.9975,2.1015,1.60871429,2.911,924,10/20/2019 23:18,female,1,1957, +1.3295,1.31411111,1.57475,1.2376,925,10/20/2019 23:23,female,1,1950, +2.26366667,2.159,1.3365,1.107,926,10/20/2019 23:38,female,1,1980, +1.22625,0.91766667,0.93016667,0.748,927,10/20/2019 23:46,female,1,1999, +0.84077778,0.827,0.82044444,0.936,928,10/20/2019 23:50,male,1,1985, +0.71828571,0.838375,0.5715,0.6651875,929,10/20/2019 23:54,male,1,1983, +0.59811111,0.71744444,0.6195,0.89857143,930,10/21/2019 0:20,male,0,1986, +0.682,1.009875,0.8184,0.31328571,931,10/21/2019 1:21,male,1,1985, +0.87416667,0.6279,0.78545455,0.91742857,932,10/21/2019 1:37,male,1,1980, +1.333,1.3388,1.5335,0.99283333,933,10/21/2019 18:28,male,1,1987, +0.26227273,1.14616667,0.9421,0.6017,934,10/21/2019 1:50,female,1,1973, +1.499,1.46657143,1.93425,1.466,935,10/21/2019 6:22,female,1,1979, +0.95366667,1.00366667,0.812,0.978,936,10/21/2019 9:22,male,1,1984, +0.684875,0.676875,0.6718125,0.61561538,937,11/10/2019 10:50,male,1,2000, +0.73133333,0.84633333,0.6462,0.7284,937,11/7/2019 8:01,male,1,2000, +0.76166667,0.75977778,0.71218182,0.69608333,937,11/10/2019 10:04,male,1,2000, +0.6522,0.77666667,0.6208,0.8924,937,11/8/2019 10:05,male,1,2000, +0.6225,0.76066667,0.611,0.7534,937,11/10/2019 10:42,male,1,2000, +0.56322222,0.8995,0.73566667,0.8134,937,11/10/2019 7:29,male,1,2000, +0.57325,0.68957143,0.59230769,0.6215,937,11/10/2019 10:44,male,1,2000, +0.58714286,0.67188235,0.766125,0.8054,937,11/10/2019 9:11,male,1,2000, +0.65427273,0.58316667,0.56376923,0.595125,937,11/10/2019 10:48,male,1,2000, +0.992875,1.4604,1.1374,0.94866667,938,11/10/2019 19:47,male,1,2000, +1.82025,1.2915,1.5605,1.691875,938,11/10/2019 19:36,male,1,2000, +0.75725,0.8572,0.9848,0.86355556,938,11/10/2019 19:49,male,1,2000, +1.3265,1.069375,1.38557143,1.11466667,938,11/10/2019 19:39,male,1,2000, +0.82,0.67166667,0.7775,0.69415385,938,11/10/2019 19:51,male,1,2000, +0.92772727,0.9072,1.01175,1.0884,938,11/10/2019 19:45,male,1,2000, +0.70283333,0.60316667,0.6664,0.7597,938,11/10/2019 19:53,male,1,2000, +0.61083333,0.95842857,0.6671,0.75581818,939,10/23/2019 0:21,male,1,2000, +0.751,0.976,0.744,0.634,940,11/3/2019 12:37,male,1,2000, +0.975,0.963,1.063,1.0272,940,11/3/2019 13:14,male,1,2000, +1.22783333,1.5095,1.214,1.2622,943,10/23/2019 21:31,female,1,2000, +0.87525,0.94133333,0.9629,0.924125,947,10/21/2019 10:41,male,1,1964, +3.198,1.514,1.03933333,1.0485,952,10/21/2019 10:52,female,1,1971, +1.78933333,0.6152,0.922,0.95475,952,10/21/2019 10:53,female,1,1971, +1.42116667,1.298,1.17346154,1.43433333,956,10/21/2019 11:23,male,1,1963, +2.21575,1.425,4.991,2.08033333,957,10/21/2019 11:43,male,1,1949, +3.38575,1.4485,1.716,2.992,958,10/21/2019 12:26,female,0,1980, +1.6922,1.29716667,1.264,2.05816667,959,10/21/2019 13:31,male,1,1977, +0.3972,0.45644444,0.47573333,0.50576923,966,11/10/2019 22:26,male,1,1999, +0.3985,0.41475,0.517,0.4272,966,11/10/2019 22:33,male,1,1999, +0.45633333,0.49865,0.504,0.43511111,966,11/10/2019 22:27,male,1,1999, +0.428125,0.46333333,0.40166667,0.43306667,966,11/10/2019 22:35,male,1,1999, +0.42708333,0.51775,0.41935714,0.4621,966,11/10/2019 22:30,male,1,1999, +0.47714286,0.56153333,0.49653333,0.54138462,966,11/10/2019 22:24,male,1,1999, +0.42986667,0.49617647,0.4492,0.418,966,11/10/2019 22:31,male,1,1999, +0.88872727,0.574375,0.897625,0.91466667,969,10/21/2019 14:09,male,1,1975, +2.4282,1.859,1.958,1.9632,970,10/21/2019 14:14,male,1,1948, +0.61392857,0.756,0.62107692,0.783375,971,10/21/2019 14:19,male,1,1988, +1.3666,1.25177778,1.52925,1.1516,972,10/21/2019 14:49,male,1,1969, +0.698625,1.0846,0.9025,1.02422222,973,10/21/2019 14:36,male,1,1986, +1.89333333,1.64266667,2.294,2.17625,974,10/21/2019 14:49,male,1,1977, +1.23642857,1.821,1.46525,2.0018,975,10/21/2019 15:02,male,1,1963, +1.51471429,1.06016667,1.7525,0.81009091,976,10/21/2019 15:26,male,1,1988, +1.35725,1.59166667,1.758,1.51333333,977,10/21/2019 15:20,female,1,1957, +1.155375,2.2215,1.622,1.4474,978,10/21/2019 15:24,female,1,1984, +2.03,2.128,2.2375,1.13675,979,10/21/2019 15:26,male,1,1969, +0.94022222,1.374,1.02475,1.12225,980,10/21/2019 15:26,female,1,1973, +0.94771429,0.961,0.93288889,0.85866667,981,10/21/2019 15:33,male,1,1986, +0.7944,0.95011111,0.74671429,0.65791667,982,10/21/2019 15:41,male,1,1965, +0.7582,0.94318182,0.9603,0.768625,983,10/21/2019 15:54,female,1,1954, +1.9924,1.67185714,1.226,1.903,984,10/21/2019 15:56,male,1,1981, +0.9288,1.08266667,0.8665,0.72491667,986,10/21/2019 16:02,male,1,1988, +0.827,1.5988,1.358,1.596,987,10/21/2019 16:05,male,1,1960, +0.56691667,0.75275,0.62269231,0.7125,988,10/21/2019 16:07,male,1,1994, +0.72128571,0.79888889,0.6705,0.47241176,989,10/21/2019 16:14,male,1,1986, +1.05633333,1.997,1.70985714,1.5265,990,10/21/2019 16:15,male,1,1965, +2.896,2.3546,2.931,2.61466667,991,10/21/2019 16:18,male,1,1950, +1.89183333,1.825,2.273,1.9565,992,10/21/2019 16:29,female,1,1968, +1.8075,1.604,1.56066667,1.66766667,993,10/21/2019 17:32,female,0,1980, +1.2816,1.496,1.3802,1.0638,993,10/22/2019 16:53,female,0,1980, +0.86366667,1.534,1.82733333,1.02866667,994,10/21/2019 16:49,female,0,1978, +1.22166667,0.52354545,0.95228571,0.812125,996,10/21/2019 16:22,male,1,1983, +0.49954545,0.55307692,0.583,0.49047059,997,10/21/2019 16:34,male,1,1997, +0.74478571,0.709,0.7887,0.9955,998,10/21/2019 16:30,female,1,1984, +0.65628571,2.262,0.997,0.983,999,10/21/2019 16:36,male,1,2000, +0.73933333,1.231,0.81675,1.1218,1002,10/21/2019 16:55,male,1,2000, +0.7736,1.006125,0.8783,0.9566,1003,10/21/2019 16:44,male,1,1975, +2.5935,3.074,4.381,2.14166667,1004,10/21/2019 16:46,female,1,1966, +1.54275,1.5602,1.53975,1.49816667,1005,10/21/2019 16:52,male,1,1954, +0.69233333,0.51117647,0.62716667,0.66425,1006,10/21/2019 16:52,male,0,1988, +0.59326667,0.45321429,0.848,0.549,1009,10/21/2019 16:56,female,1,1995, +1.02,0.935,1.3455,0.999,1011,10/21/2019 17:53,female,1,1971, +1.3502,1.62916667,1.0036,1.01914286,1013,10/21/2019 17:12,female,1,1980, +1.4866,1.13,0.9365,0.9926,1013,10/21/2019 17:13,female,1,1980, +1.148,2.193,4.398,1.33566667,1014,10/21/2019 17:19,male,1,1980, +0.77175,0.6243,0.69722222,0.79938462,1016,10/21/2019 17:33,male,1,1983, +0.80723077,0.669,0.86857143,0.82225,1017,10/21/2019 17:16,male,1,1973, +1.546,1.33614286,0.996,1.4495,1018,10/21/2019 17:21,female,1,1980, +1.20133333,0.98644444,1.07977778,1.21983333,1019,10/21/2019 17:25,male,1,1974, +0.62491667,0.615,0.70977778,0.957875,1020,10/21/2019 17:47,male,1,1981, +5.353,3.456,2.9255,6.874,1021,10/21/2019 17:36,female,1,1960, +1.024,1.163625,2.29633333,1.453,1022,10/21/2019 17:34,male,1,1985, +1.26366667,1.33655556,0.95633333,1.28783333,1023,10/21/2019 17:36,female,1,1985, +0.6534,0.88769231,0.5755,0.71154545,1025,10/21/2019 17:39,male,1,1988, +1.40475,1.39166667,1.64,1.448,1028,10/21/2019 17:51,male,1,1961, +0.86833333,0.97375,1.382,0.94525,1029,10/22/2019 16:24,female,1,1983, +1.0373,1.0715,1.28933333,1.25522222,1030,10/22/2019 17:16,male,1,1972, +1.26957143,1.44766667,1.9338,1.205,1031,10/22/2019 17:38,male,1,1966, +1.217,1.48466667,1.29,0.8535,1031,10/22/2019 17:37,male,1,1966, +3.03975,4.652,5.486,5.919,1032,10/21/2019 17:57,male,1,1968, +1.76633333,1.7845,1.61966667,1.84016667,1033,10/22/2019 18:21,male,1,1953, +3.20633333,1.522,1.6775,1.586,1035,10/21/2019 18:01,male,1,1956, +3.56433333,1.10016667,1.6302,1.06733333,1036,10/21/2019 17:59,female,1,1974, +1.18355556,1.50633333,1.2098,1.54366667,1038,10/21/2019 18:06,female,1,2005, +3.092,3,2.9028,2.68,1039,10/21/2019 18:11,male,1,1959, +1.876,2.09266667,1.8132,1.30033333,1040,10/21/2019 18:08,male,1,1982, +4.205,0.979,1.3732,1.37633333,1041,10/21/2019 18:12,male,1,1994, +2.043,2.05325,1.58757143,1.515,1042,10/21/2019 18:16,female,1,1971, +2.3745,1.447,1.8452,1.45066667,1043,10/21/2019 18:25,male,1,1968, +1.3734,2.05066667,1.24057143,0.993,1044,10/21/2019 18:38,female,1,1971, +0.76308333,0.791,0.62453846,0.99566667,1045,10/21/2019 18:28,male,1,1985, +1.263,1.128,1.31075,0.74571429,1046,10/21/2019 18:29,female,1,1980, +0.856,0.467,0.685,1.257,1047,10/21/2019 18:29,male,1,1990, +0.55383333,0.69416667,0.78671429,0.66614286,1048,10/21/2019 18:26,male,1,1953, +0.913,0.969,0.99371429,1.177875,1051,10/21/2019 18:32,male,0,1986, +0.509,0.67514286,0.61991667,0.64214286,1052,10/21/2019 18:32,female,1,1985, +1.07171429,1.0775,1.21383333,1.0738,1053,10/21/2019 19:30,male,1,1981, +1.1592,1.13066667,1.01185714,1.167125,1054,10/21/2019 18:36,male,0,1988, +1.375,1.29,1.23685714,1.36933333,1055,10/21/2019 18:38,female,1,1967, +1.38542857,1.5496,1.403,1.2186,1056,10/21/2019 18:40,female,1,1958, +0.7714,0.86033333,1.3095,1.03933333,1057,10/21/2019 18:48,male,1,1984, +0.89883333,0.889625,1.10666667,1.0637,1057,10/22/2019 20:31,male,1,1984, +1.789,2.47833333,1.743,2.194,1058,10/21/2019 18:51,male,1,1954, +1.07333333,1.11425,1.104,1.85314286,1059,10/21/2019 18:52,male,1,1967, +0.67433333,0.68988889,1.04944444,0.746,1060,10/21/2019 18:56,female,1,1985, +0.69930769,0.74277778,0.7266,0.56908333,1061,10/21/2019 18:55,male,1,1983, +4.465,1.3074,3.6855,2.60325,1062,10/21/2019 18:56,female,1,1977, +0.77711111,0.80188889,0.85777778,1.15166667,1063,10/21/2019 19:09,female,1,1979, +0.7024,0.5988,0.94257143,0.73971429,1063,10/21/2019 19:19,female,1,1979, +1.049,0.855,0.92281818,0.7345,1064,10/21/2019 19:21,male,1,1981, +1.232,0.79655556,0.928375,0.8655,1064,10/21/2019 21:05,male,1,1981, +0.92325,1.15416667,1.0395,1.0215,1064,10/21/2019 19:18,male,1,1981, +0.53926667,0.6593,0.7507,0.64575,1066,11/5/2019 11:03,female,1,1971,3 +0.65864286,0.58208333,0.6769,0.6896,1066,11/9/2019 11:38,female,1,1971,3 +0.7042,0.63121429,0.766,0.641,1066,11/6/2019 12:02,female,1,1971,3 +0.77285714,0.675,0.73446154,0.6671,1066,11/10/2019 10:31,female,1,1971,3 +1.2166,1.36575,1.39314286,1.343,1066,10/21/2019 19:08,female,1,1971,3 +0.635625,0.55355556,0.623,0.73411111,1066,11/7/2019 15:32,female,1,1971,3 +0.75933333,0.60316667,0.608,0.703125,1066,11/4/2019 14:39,female,1,1971,3 +0.57585714,0.50783333,0.67316667,0.69209091,1066,11/8/2019 13:40,female,1,1971,3 +0.83425,0.64875,0.971625,0.60592857,1067,10/21/2019 19:13,male,1,1983, +0.69653333,0.9935,0.95428571,0.69816667,1068,10/22/2019 20:29,female,0,1981, +0.65825,0.8447,1.07957143,0.85925,1068,10/21/2019 19:14,female,0,1981, +0.6081,0.756,0.7722,0.60711111,1070,10/21/2019 19:33,male,1,1985, +0.88741667,0.9968,1.131,0.84971429,1071,10/21/2019 23:04,female,1,2000, +1.7365,1.382,1.74,1.38633333,1071,10/21/2019 19:26,female,1,2000, +2.95833333,1.072625,1.133,2.81,1072,10/21/2019 19:28,female,1,1977, +0.6535,0.82909091,0.828625,0.861625,1072,10/21/2019 19:29,female,1,1977, +1.4465,1.3,1.22133333,2.989,1075,10/21/2019 19:27,female,1,1967, +2.066,2.171,2.728,1.83028571,1076,10/21/2019 19:23,male,1,1968, +0.581375,0.60107692,0.65775,0.72869231,1078,10/21/2019 19:31,male,1,1985, +1.3835,1.874,1.996,1.64014286,1080,10/21/2019 19:30,female,1,1958, +1.789,1.51814286,1.43266667,1.84316667,1081,10/22/2019 20:28,male,1,1974, +0.83183333,0.91314286,1.30416667,0.98575,1081,10/21/2019 19:33,male,1,1974, +1.65833333,1.18266667,1.453,1.42375,1083,10/21/2019 19:49,female,1,1981, +1.321,1.425,1.25328571,1.446,1084,10/21/2019 20:15,female,1,1985, +0.69842857,0.739,0.70257143,0.90342857,1086,10/21/2019 19:34,male,1,1988, +1.94033333,1.58633333,1.9212,1.57966667,1087,10/21/2019 20:12,male,1,1975, +0.77783333,0.68758824,0.6962,0.782,1089,10/21/2019 19:38,female,1,1989, +0.404,1.13271429,1.0205,1.05816667,1090,10/21/2019 19:50,male,1,1967, +2,2.01857143,1.944,2.15433333,1091,10/21/2019 20:51,male,1,1953, +0.70190909,0.65154545,0.83444444,0.813375,1093,10/21/2019 19:44,male,1,1984, +2.835,2.126,1.837,1.589,1094,10/21/2019 20:37,male,1,1967, +2.353,3.0085,1.91375,3.136,1096,10/21/2019 19:48,female,1,1971, +0.70423077,0.87325,0.61444444,0.93616667,1098,10/21/2019 19:49,male,1,1986, +2.1582,2.26466667,1.4085,1.377,1100,10/21/2019 19:57,female,1,1981, +0.98044444,1.176,1.0935,1.0741,1101,10/21/2019 19:50,male,1,1956, +0.756125,0.73861538,0.8045,0.87244444,1102,10/21/2019 19:55,male,1,1986, +1.79433333,1.645125,0.907,1.22975,1103,10/21/2019 19:59,female,1,1972, +1.49,1.70333333,1.316,1.578,1104,10/21/2019 19:55,female,1,1950, +1.402,1.96466667,1.40433333,2.048,1105,10/21/2019 20:36,female,1,1963, +3.77025,3.512,2.954,2.122,1105,10/22/2019 20:26,female,1,1963, +0.73325,0.95,1.0015,0.7045,1106,10/21/2019 19:57,male,1,1988, +0.6546,0.76114286,0.82408333,0.914875,1108,10/21/2019 19:58,male,1,2000,4 +0.61866667,0.66881818,0.6885,0.66526667,1108,11/10/2019 22:02,male,1,2000,4 +0.60475,0.84733333,0.633,0.64392308,1108,11/5/2019 22:21,male,1,2000,4 +0.68841667,0.64,0.631,0.6376875,1108,11/10/2019 22:03,male,1,2000,4 +0.657375,0.847375,0.764,0.7691,1108,11/10/2019 22:00,male,1,2000,4 +0.6955,0.558,0.74375,0.6905,1108,11/10/2019 22:04,male,1,2000,4 +0.5938,0.6666,0.6235,0.6995,1108,11/10/2019 22:01,male,1,2000,4 +0.87527273,0.93828571,0.72972727,0.67475,1109,10/21/2019 20:02,male,1,1987, +0.71416667,0.73025,0.73216667,0.6822,1109,10/21/2019 21:14,male,1,1987, +0.84525,0.95109091,0.98122222,0.9125,1109,10/21/2019 20:03,male,1,1987, +0.573,0.78,0.54833333,0.76333333,1109,10/21/2019 21:15,male,1,1987, +0.8004,0.84592308,1.20028571,0.87071429,1109,10/21/2019 20:04,male,1,1987, +0.63125,0.72441667,0.93888889,0.717,1109,10/21/2019 20:01,male,1,1987, +0.71555556,0.98922222,0.98583333,0.7829,1109,10/21/2019 21:13,male,1,1987, +1.2701,1.2475,1.263,1.281,1110,10/21/2019 20:02,male,1,1974, +1.7515,1.52933333,2.23366667,1.992,1111,10/21/2019 20:10,female,1,1955, +1.48622222,1.604,1.86133333,1.8285,1112,10/21/2019 20:07,male,1,1958, +0.71755556,0.84066667,1.324,1.02044444,1113,10/21/2019 20:12,female,1,1985, +0.64233333,0.75490909,1.01533333,1.20928571,1114,10/21/2019 20:11,male,0,1975, +2.301,4.527,1.8255,2.79366667,1115,10/21/2019 20:12,female,0,1960, +1.5175,1.669,1.468,2.00175,1116,10/21/2019 20:12,male,1,1969, +2.31,2.5895,2.0515,2.03671429,1118,10/21/2019 20:16,male,1,1955, +1.22314286,1.46533333,1.3586,1.086,1119,10/21/2019 20:15,male,1,1965, +1.19225,0.99,2.22583333,0.9768,1121,10/21/2019 20:17,male,1,1980, +0.6533,0.56194118,0.61116667,0.78975,1123,10/21/2019 20:19,male,1,1986, +0.904,1.189,1.07122222,1.215875,1124,10/21/2019 20:19,male,1,1968, +1.24071429,1.52257143,1.28233333,1.2678,1125,10/21/2019 20:20,female,1,1959, +0.76925,0.97616667,1.07088889,1.16857143,1126,10/21/2019 20:22,female,1,1981, +0.74433333,1.014625,1.04316667,0.95788889,1127,10/21/2019 20:23,male,1,1971, +0.66254545,0.61691667,0.73833333,0.72845455,1128,10/21/2019 20:27,male,0,1982, +1.0674,1.05222222,0.98988889,1.0966,1129,10/21/2019 20:30,female,1,1975, +0.95828571,1.21971429,1.487,1.1408,1129,10/21/2019 20:31,female,1,1975, +0.73966667,0.87925,1.07816667,0.70044444,1129,10/21/2019 20:28,female,1,1975, +1.4625,1.716,1.92283333,1.43442857,1129,10/21/2019 20:32,female,1,1975, +0.8465,1.2974,1.0191,0.82428571,1129,10/21/2019 20:29,female,1,1975, +1.2426,1.3465,1.16871429,1.2662,1129,10/21/2019 21:19,female,1,1975, +1.43933333,2.006,1.70157143,1.15433333,1130,10/21/2019 20:31,female,1,1956, +0.545,0.48408333,0.52228571,0.88654545,1131,10/21/2019 20:36,male,1,1983, +8.0165,2.551,1.91033333,2.2515,1132,10/21/2019 20:37,female,1,1955, +2.735,1.918,2.1764,2.3565,1133,10/21/2019 20:35,female,1,1952, +1.845,1.6825,1.545,3.287,1134,10/21/2019 20:38,female,1,1971, +0.98866667,0.90666667,1.43125,0.78742857,1135,10/21/2019 20:38,female,1,1983, +1.21533333,1.1615,1.24383333,3.1215,1136,10/21/2019 20:40,male,1,1969, +1.3046,1.325,1.41342857,1.26925,1137,10/21/2019 22:33,male,1,1966, +1.205875,1.161,1.32366667,1.27225,1138,10/21/2019 21:11,male,1,1979, +1.22025,0.91785714,1.07788889,1.18228571,1139,10/21/2019 20:47,female,1,1986, +0.56,0.7366,1.0615,0.6085,1140,10/21/2019 20:49,male,1,1983, +1.7635,1.594,1.64975,3.504,1141,10/21/2019 20:50,female,1,1947, +1.6578,1.453,1.32828571,1.03133333,1142,10/21/2019 20:52,female,1,1974, +1.13985714,1.04183333,1.32066667,1.01685714,1143,10/21/2019 20:59,male,1,1963, +2.36633333,1.641,1.93766667,1.92,1145,10/21/2019 20:59,male,1,1976, +2.45733333,2.47833333,3.1805,2.88566667,1146,10/21/2019 21:04,male,1,1966, +1.9454,1.81425,1.5235,1.5605,1147,10/21/2019 21:05,male,1,1967, +1.0785,0.96866667,3.235,1.07,1148,10/21/2019 21:08,female,1,1964, +1.3006,1.58255556,1.522,1.4148,1149,10/21/2019 21:04,male,1,1958, +1.12475,0.96571429,0.99033333,0.91925,1150,10/21/2019 21:06,female,1,1975, +1.51633333,1.26925,1.6125,1.1536,1151,10/21/2019 21:05,male,1,1969, +1.2915,0.869,0.99963636,0.6945,1152,10/21/2019 21:14,male,0,1986, +0.63390909,1.117,0.90411111,0.95383333,1153,10/21/2019 21:14,female,1,1966, +1.3465,1.55975,0.97030769,1.37375,1153,10/21/2019 21:15,female,1,1966, +1.8915,2.002,2.03125,2.3038,1154,10/21/2019 21:17,male,1,1988, +3.13766667,2.68733333,1.567,1.9925,1155,10/21/2019 21:17,female,1,1947, +3.5105,3.3955,4.091,3.7465,1157,10/21/2019 21:20,female,0,1949, +0.75825,0.91933333,0.7265,1.44566667,1158,10/21/2019 21:20,female,1,1983, +1.3146,1.219625,1.22675,1.004,1159,10/21/2019 21:21,male,1,1966, +1.675,1.414875,1.4795,1.44966667,1161,10/21/2019 21:27,male,1,1963, +1.4245,2.105,2.0294,2.5046,1162,10/21/2019 21:28,female,1,1982, +1.102625,1.10633333,1.153,1.189,1163,10/21/2019 21:28,male,1,1955, +1.50125,1.087,1.361,1.02522222,1165,10/21/2019 21:32,male,1,1966, +2.35766667,2.1774,2.109,2.077,1166,10/21/2019 21:42,female,0,1966, +1.53825,2.16666667,1.5986,1.7928,1166,10/21/2019 21:45,female,0,1966, +2.19766667,2.6105,2.45466667,2.099,1166,10/21/2019 21:40,female,0,1966, +1.2452,1.82814286,0.975,1.114,1167,10/21/2019 21:34,male,1,1958, +0.9862,1.592,1.16171429,0.95985714,1168,10/21/2019 21:35,female,1,1984, +1.7672,1.576,1.8095,1.4795,1169,10/21/2019 21:44,female,1,1975, +1.43225,1.32583333,1.41785714,0.98566667,1170,10/21/2019 21:45,female,0,1977, +0.63614286,0.69435714,0.86163636,0.81471429,1171,10/21/2019 21:42,male,1,1989, +0.59854545,0.780125,0.8382,0.8152,1172,10/21/2019 21:45,male,1,1992, +1.01314286,1.14516667,1.18483333,1.14257143,1173,10/21/2019 21:53,male,1,1988, +1.1035,1.623,1.02742857,1.10583333,1174,10/21/2019 22:03,male,1,1972, +1.235,1.37816667,1.6755,1.064375,1175,10/21/2019 21:59,female,1,1981, +0.881,0.932,0.7607,0.93466667,1176,10/21/2019 22:01,male,1,1956, +1.80814286,2.12066667,1.356,0.890125,1177,10/21/2019 22:07,male,1,1964, +1.946,1.7495,1.523,1.8824,1178,10/21/2019 22:07,female,1,1986, +1.7462,1.374625,2.212,1.2774,1180,10/21/2019 23:00,male,1,1966, +1.82083333,2.0665,1.8515,1.91866667,1181,10/21/2019 22:24,female,1,1944, +1.0055,0.86225,1.17933333,0.97323077,1182,10/21/2019 22:33,female,1,1983, +0.67141667,0.55276923,0.823875,0.57921429,1183,10/21/2019 22:33,male,1,1977, +0.903625,0.89614286,0.71677778,0.80116667,1184,10/21/2019 22:46,female,1,1925, +2.4456,2.038,1.4895,2.58575,1185,10/21/2019 22:36,male,1,1968, +1.12725,1.58525,1.2714,1.13042857,1186,10/21/2019 22:58,female,1,1964, +0.58233333,0.58375,0.51013333,0.64353333,1187,10/21/2019 22:52,male,1,1981, +0.87266667,0.951125,1.0424,1.087125,1188,10/21/2019 22:54,male,1,1988, +1.09933333,1.05025,1.17285714,1.22533333,1189,10/21/2019 23:25,male,1,1959, +0.9835,0.92566667,0.9745,1.0404,1190,10/21/2019 23:22,female,0,2000, +0.8013,0.839625,0.735,0.91242857,1192,10/21/2019 23:39,female,1,1988, +1.7635,1.64433333,1.4985,1.841,1195,10/22/2019 1:12,male,1,1958, +1.76766667,1.28775,0.8745,1.06990909,1196,10/22/2019 19:52,male,1,1959, +1.4875,1.7102,1.7286,1.50116667,1196,10/22/2019 19:25,male,1,1959, +1.39366667,1.4135,1.591625,2.00066667,1197,10/22/2019 7:23,male,1,1964, +0.86128571,1.09966667,0.84145455,1.31983333,1198,10/22/2019 10:11,male,1,1988, +0.62281818,0.767,0.66266667,0.72363636,1199,10/22/2019 10:42,male,0,1988, +0.6807,0.72153333,0.708,0.8027,1200,10/22/2019 11:02,female,1,1979, +0.6807,0.72153333,0.708,0.8027,1200,10/22/2019 11:02,female,1,1979, +0.7338,0.67509091,0.68933333,0.74644444,1202,10/22/2019 11:17,male,1,1983, +0.7338,0.67509091,0.68933333,0.74644444,1202,10/22/2019 11:17,male,1,1983, +0.63546154,0.68728571,0.7382,0.82390909,1204,10/22/2019 11:30,male,1,1974, +0.63546154,0.68728571,0.7382,0.82390909,1204,10/22/2019 11:30,male,1,1974, +2.10133333,2.4145,1.9885,2.48375,1206,10/22/2019 11:43,male,1,1958, +0.627,0.521,0.66133333,0.8186,1207,10/22/2019 11:52,male,1,1983, +0.87291667,0.87414286,0.91216667,0.908625,1209,10/22/2019 11:50,male,1,1968, +0.87291667,0.87414286,0.91216667,0.908625,1209,10/22/2019 11:50,male,1,1968, +1.3716,1.22371429,1.851,1.7505,1210,10/22/2019 12:11,male,1,1974, +1.16171429,1.571,1.2232,1.02566667,1211,10/22/2019 12:20,male,1,1955, +1.02814286,0.859,0.8523,1.2828,1212,10/22/2019 12:29,male,1,1986, +1.35757143,1.545,1.38833333,1.228375,1213,10/22/2019 12:41,female,1,1982, +0.634875,0.84514286,0.66115385,0.79472727,1214,10/22/2019 12:57,female,1,1981, +0.60366667,0.59515385,0.64633333,0.71593333,1215,10/22/2019 12:59,male,1,1974, +1.55666667,2.144,1.58077778,1.54575,1216,10/22/2019 12:57,female,1,1961, +0.739375,0.9087,0.7752,0.79144444,1217,10/22/2019 13:01,male,1,1979, +1.7495,1.58433333,1.033,1.2065,1217,10/22/2019 16:45,male,1,1979, +0.69708333,0.90533333,0.7444,1.2005,1218,10/22/2019 13:12,male,1,1966, +0.56244444,0.63908333,0.631,0.563,1219,10/22/2019 13:14,female,1,1982, +1.8025,1.212,1.73033333,1.054,1219,10/22/2019 19:16,female,1,1982, +0.53927273,0.7865,0.58928571,0.9062,1220,10/22/2019 13:16,male,1,1984, +1.02377778,1.06622222,1.28933333,0.936,1222,10/22/2019 13:28,male,1,1959, +1.15466667,1.1614,1.048,1.1156,1223,10/22/2019 13:29,male,1,1976, +0.69283333,0.8484,0.67471429,0.678,1224,10/22/2019 13:31,male,1,1972, +1.368,0.81266667,1.567,1.223,1226,10/22/2019 13:57,male,1,1989, +0.66618182,0.78914286,0.81066667,0.79911111,1228,10/22/2019 14:00,female,1,1979, +1.027,0.947,1.06133333,2.6845,1229,10/22/2019 20:34,male,0,2000, +1.466,1.3956,1.555,1.46571429,1231,10/22/2019 14:12,male,1,1955, +1.41,1.5005,1.5002,1.7855,1232,10/22/2019 14:16,male,1,1965, +0.89866667,0.773,0.867,0.65745455,1233,10/22/2019 14:45,male,1,1974, +1.5942,1.006,0.815,1.2038,1234,10/22/2019 15:06,male,1,1988, +1.5405,1.192625,0.93233333,1.14385714,1236,10/22/2019 15:42,female,1,1964, +1.10142857,1.052625,0.829,1.1915,1237,10/22/2019 15:51,female,1,1989, +0.866,1.3055,1.095,1.19666667,1237,10/22/2019 15:52,female,1,1989, +1.57683333,1.0726,1.26133333,2.1286,1239,10/22/2019 23:01,male,1,1969, +1.085,0.80316667,0.87622222,1.0132,1241,10/22/2019 16:12,male,1,1989, +0.5212,0.5663,0.61583333,0.51390909,1242,10/22/2019 16:17,male,0,1982, +2.14114286,1.405,1.298,1.4715,1243,10/22/2019 16:35,female,1,1963, +1.0445,1.3005,1.56542857,0.97811111,1245,10/22/2019 16:36,female,1,1985, +1.336,1.43385714,1.60333333,1.438,1246,10/22/2019 16:41,female,1,1967, +1.74,2.198,1.9875,1.91366667,1248,10/22/2019 16:57,male,1,1955, +0.8275,0.81044444,0.9183,1.09416667,1249,10/22/2019 17:07,female,1,1980, +1.6428,1.28642857,1.73225,2.608,1250,10/22/2019 17:01,male,1,1948, +1.72425,1.4465,1.484875,1.3,1251,10/22/2019 18:51,female,1,1978, +2.19366667,2.5575,2.07833333,2.079,1252,10/22/2019 17:06,female,1,1958, +1.38366667,1.429875,1.3666,1.379,1254,10/22/2019 17:01,male,1,1973, +0.78271429,1.2982,1.03642857,1.42314286,1255,10/22/2019 19:22,female,0,1980, +1.514,1.39433333,1.57733333,1.66633333,1256,10/22/2019 21:44,male,1,1957, +1.45516667,1.0655,1.17266667,1.34325,1256,10/22/2019 21:46,male,1,1957, +1.34816667,1.3644,1.66225,7.268,1257,10/22/2019 17:13,female,1,1979, +1.5695,0.92966667,1.13385714,1.67366667,1258,10/22/2019 17:11,male,1,1964, +1.30466667,1.65725,2.98,2.074,1259,10/22/2019 17:14,female,1,1986, +1.76377778,2.15933333,1.5245,1.342,1260,10/22/2019 17:10,male,0,1947, +0.90744444,1.3945,1.03685714,1.030875,1261,10/22/2019 17:16,female,1,1988, +0.7002,0.8364,0.70630769,0.92266667,1262,10/22/2019 17:21,male,1,1975, +0.55922222,0.7511,0.58725,0.68854545,1263,10/22/2019 17:20,male,1,1985, +4.41733333,2.141,1.9275,2.2395,1264,10/22/2019 17:25,female,1,1969, +1.11533333,1.07111111,1.0506,1.13928571,1265,10/22/2019 17:55,female,1,1982, +0.7232,0.707,0.971125,0.81766667,1266,10/22/2019 17:39,male,1,1980, +0.6485,0.8435,0.70588889,0.75269231,1266,10/22/2019 17:32,male,1,1980, +1.25014286,0.85322222,0.78675,1.17683333,1267,10/22/2019 17:30,female,1,1984, +1.054,0.99958333,0.8978,0.81466667,1268,10/22/2019 17:39,female,1,1971, +0.842,1.18233333,1.092,0.90157143,1269,10/22/2019 17:30,female,1,1986, +1.11414286,0.92071429,1.128,1.63725,1271,10/22/2019 17:39,female,1,1957, +1.2922,1.50714286,1.0832,1.88533333,1271,10/22/2019 17:40,female,1,1957, +1.6566,1.724,1.78942857,1.73966667,1272,10/22/2019 17:44,female,1,1970, +0.64163158,0.697,0.6907,0.66514286,1273,10/22/2019 17:45,female,1,1984, +0.67992308,0.67357143,0.68236364,0.64411111,1274,10/22/2019 17:47,male,1,1983, +2.915,2.87633333,2.75933333,2.7,1275,10/22/2019 17:53,female,1,1968, +1.76433333,1.537375,1.3745,1.401,1276,10/22/2019 17:48,female,1,1980, +0.79655556,1.00033333,0.9825,1.088,1277,10/22/2019 17:51,male,1,1985, +2.291,0.9224,1.99822222,1.57233333,1278,10/22/2019 18:09,male,1,1978, +1.56675,2.047,1.479625,1.58233333,1279,10/22/2019 18:11,male,1,1951, +0.58909091,0.628,0.73357143,0.666,1280,10/22/2019 17:51,female,1,1980, +0.70214286,0.553375,0.77933333,0.82516667,1280,11/4/2019 8:09,female,1,1980, +1.417,1.7885,1.9704,1.714,1281,10/22/2019 17:51,male,1,1958, +1.87457143,1.291,1.2628,1.444,1282,10/22/2019 17:59,female,1,1977, +1.821,1.59666667,1.0515,1.32257143,1284,10/22/2019 18:03,male,1,1970, +0.88071429,0.61872727,0.66533333,0.7014,1285,10/22/2019 18:14,male,1,1979, +2.566,1.6045,1.2645,0.98866667,1286,10/22/2019 18:18,male,1,1961, +1.09157143,1.409,1.43116667,1.78725,1288,10/22/2019 18:19,female,0,1971, +0.59509091,0.92757143,0.75727273,0.63,1289,10/22/2019 18:07,male,1,1988, +0.82628571,0.76466667,0.7766,0.49211111,1290,10/22/2019 18:10,male,1,1987, +0.789,0.864,0.88575,0.925,1291,10/22/2019 18:17,male,1,1973, +1.1634,1.10833333,3.092,3.47,1292,10/22/2019 18:10,female,1,1944, +1.3475,1.3556,1.48366667,0.937,1293,10/22/2019 18:10,male,1,1971, +0.648,1.168,0.7406,1.26425,1294,10/22/2019 18:12,female,1,1971, +1.74166667,1.678,2.0296,1.36975,1295,10/22/2019 18:18,female,1,1982, +1.53733333,1.62216667,1.849,1.417125,1295,10/22/2019 18:19,female,1,1982, +1.17233333,0.9921,1.5678,1.23225,1296,10/22/2019 18:15,male,1,1967, +1.027,0.579,1.3,1.2855,1297,10/22/2019 18:21,female,1,1963, +0.9102,0.94833333,0.77427273,0.945,1298,10/22/2019 18:19,male,1,1987, +1.143,1.294375,1.29188889,1.42875,1300,10/22/2019 18:21,female,1,1978, +1.16976923,1.14533333,1.251,1.16233333,1301,10/22/2019 18:22,female,1,1978, +2.95866667,3.15233333,1.483,2.87133333,1302,10/22/2019 18:22,male,1,1964, +1.94,4.059,1.74133333,2.0256,1303,10/22/2019 18:35,male,1,1961, +0.904875,0.73725,0.89166667,0.8725,1304,11/4/2019 18:35,female,1,2000, +1.60116667,1.48433333,1.59566667,1.03933333,1304,10/22/2019 18:54,female,1,2000, +0.904875,0.73725,0.89166667,0.8725,1304,11/4/2019 18:35,female,1,2000, +2.9975,2.099,2.515,2.2585,1304,10/22/2019 19:17,female,1,2000, +1.4765,0.64006667,0.6235,0.83,1304,11/5/2019 9:53,female,1,2000, +2.46733333,1.6715,1.136,1.21216667,1304,10/22/2019 19:37,female,1,2000, +0.8983,0.85877778,0.71175,0.785,1304,11/6/2019 18:47,female,1,2000, +1.47366667,1.726,2.228,1.816,1305,10/22/2019 18:23,male,1,1964, +1.026,1.49,1.1485,1.19985714,1306,10/22/2019 18:27,male,1,1967, +1.3265,1.26425,0.92633333,0.87383333,1308,10/22/2019 18:27,female,1,1973, +0.8235,0.9695,1.34566667,1.37628571,1309,10/22/2019 18:27,male,1,1984, +0.7378,0.61953846,0.79228571,0.56966667,1310,10/22/2019 18:28,male,1,1984, +2.0415,2.08333333,2.08925,1.9334,1311,10/22/2019 18:28,male,1,1969, +0.6788,0.75614286,0.64225,0.81158333,1312,10/22/2019 18:55,male,0,1986, +0.9992,0.6399,0.76708333,1.27742857,1313,10/22/2019 18:35,female,1,1986, +2.264,1.688,1.097,1.91933333,1315,10/22/2019 21:16,female,1,1978, +1.197,1.21883333,2.03283333,1.2266,1315,10/22/2019 21:24,female,1,1978, +1.1838,1.70633333,0.89641667,1.201,1315,10/22/2019 21:28,female,1,1978, +1.351,2.3025,2.16483333,1.48025,1316,10/22/2019 18:35,male,1,1940, +0.7159,0.6815,0.661,0.70833333,1317,10/22/2019 18:30,female,1,1985, +0.932,1.276,1.57266667,1.0154,1318,10/22/2019 18:45,male,1,1969, +0.69025,0.71854545,0.812,0.68823077,1319,10/22/2019 18:37,male,1,1985, +3.639,2.5918,3.287,3.23466667,1321,10/22/2019 18:40,female,1,1947, +1.17283333,0.9933,1.22433333,1.17566667,1324,10/22/2019 18:55,male,1,1974, +0.563,0.608,0.78225,0.6291,1325,10/22/2019 18:43,male,1,1985, +0.6784,0.81471429,0.71915385,0.62215385,1326,10/22/2019 18:43,male,1,1986, +1.2505,0.928,0.95688889,0.544625,1327,10/22/2019 18:46,female,1,1982, +1.30457143,1.14,1.4826,1.8582,1328,10/22/2019 18:45,male,1,1942, +1.30457143,1.14,1.4826,1.8582,1328,10/22/2019 18:45,male,1,1942, +1.52014286,2.358,2.148,2.11183333,1328,10/22/2019 18:46,male,1,1942, +0.75333333,0.67325,0.7666,0.7164,1329,11/4/2019 7:38,male,0,2000,4 +0.6618,0.63592308,0.67915385,0.84385714,1329,11/8/2019 8:07,male,0,2000,4 +0.76722222,0.63511111,0.7935,0.719,1329,11/5/2019 7:44,male,0,2000,4 +0.6635,0.656,0.59792308,0.727375,1329,11/11/2019 23:35,male,0,2000,4 +0.63345455,0.68409091,0.986125,0.719,1329,11/6/2019 8:04,male,0,2000,4 +0.67364286,0.660625,0.60141667,0.89177778,1329,10/22/2019 18:49,male,0,2000,4 +0.76883333,0.65416667,0.67177778,0.73242857,1329,11/7/2019 7:37,male,0,2000,4 +2.24125,0.77257143,1.36042857,1.4515,1330,10/22/2019 18:50,male,1,1982, +1.472,1.3126,2.188,2.0444,1332,10/22/2019 18:53,male,1,1957, +3.2615,1.55483333,1.3364,1.3714,1333,10/22/2019 18:53,male,1,1967, +0.98413333,0.8884,1.07133333,1.0065,1335,10/22/2019 18:52,female,1,1968, +2.37266667,2.0385,2.076,2.455,1336,10/22/2019 18:53,female,1,1949, +2.37266667,2.0385,2.076,2.455,1336,10/22/2019 18:53,female,1,1949, +2.37266667,2.0385,2.076,2.455,1336,10/22/2019 18:53,female,1,1949, +1.05,1.149,1.05675,1.27366667,1337,10/22/2019 18:52,male,0,1975, +0.6073,0.59361538,0.69333333,0.68181818,1338,10/22/2019 18:52,male,1,1987, +0.60776923,0.49028571,0.56118182,0.60228571,1340,10/22/2019 19:03,male,1,1984, +0.88783333,0.776,1.08118182,2.13975,1341,10/22/2019 21:20,male,1,2001, +0.631,1.032,0.9466,0.65875,1341,10/22/2019 21:26,male,1,2001, +0.7666,0.726,0.90409091,1.34228571,1341,10/22/2019 21:21,male,1,2001, +0.65135294,0.61718182,0.67521429,0.693,1341,10/22/2019 21:23,male,1,2001, +0.744,0.6065,1.0269,1.12514286,1341,10/22/2019 21:25,male,1,2001, +0.764,1.07375,1.039,0.71516667,1342,10/22/2019 19:04,male,1,1984, +2.43366667,1.9904,2.056,1.213,1343,10/22/2019 19:14,male,1,1949, +1.05238462,0.58171429,0.67871429,0.53792308,1343,11/11/2019 22:09,male,1,1949, +0.492,0.51322222,0.36146667,0.61222222,1343,11/11/2019 22:10,male,1,1949, +0.6767,0.96818182,0.76071429,0.678,1344,10/22/2019 19:02,female,1,1989, +0.6515,0.6514,0.61289474,0.69372727,1345,10/22/2019 19:01,male,1,1972, +0.8387,0.53566667,0.8108,0.78876923,1346,10/23/2019 0:19,male,1,2000, +1.03971429,1.028,0.917875,1.07755556,1347,10/22/2019 19:03,male,1,1989, +0.666,1.02771429,0.8945,1.16957143,1349,10/22/2019 19:07,female,1,1986, +1.05,0.6968,1.0265,0.9805,1350,10/22/2019 19:15,female,1,1997, +0.965,0.547,0.524,0.93,1351,10/22/2019 19:09,female,1,1979, +0.58094118,0.7872,0.68661538,0.7054,1352,10/22/2019 19:09,male,1,1985, +1.12772727,1.71833333,0.8234,1.422,1353,10/22/2019 19:11,male,1,1966, +0.99827273,0.93142857,1.2176,1.2746,1354,10/22/2019 19:13,male,1,1988, +0.62813333,0.6646,0.61154545,0.93271429,1355,10/22/2019 19:13,male,1,1960, +2.09185714,1.74833333,1.484,1.043,1359,10/22/2019 19:19,male,1,1975, +1.127,0.8969,0.85166667,0.80585714,1360,10/22/2019 19:20,male,1,1984, +0.89772727,0.8558,1.171,0.915,1362,10/22/2019 19:19,male,1,1969, +1.64066667,0.5815,1.455875,1.462125,1363,10/22/2019 19:23,male,1,1958, +1.2402,1.0772,0.88325,1.2015,1364,10/22/2019 19:22,female,1,1960, +1.0168,1.0344,1.2063,0.945625,1365,10/22/2019 19:22,female,1,1988, +1.00266667,0.695,1.098125,1.4665,1366,10/22/2019 19:27,male,1,1965, +1.04766667,0.97866667,1.093,1.14322222,1367,10/22/2019 19:23,male,1,1956, +1.8685,1.9418,2.6045,2.116,1368,10/22/2019 19:28,male,0,1957, +1.77775,1.8545,2.162,2.9275,1369,10/22/2019 19:32,female,1,1956, +0.57278571,0.8185,0.76241667,0.82133333,1370,10/22/2019 19:35,male,1,1999, +0.69422222,1.114,0.72413333,0.64485714,1370,10/27/2019 2:44,male,1,1999, +1.54357143,1.3164,1.323,1.351,1371,10/22/2019 19:49,male,1,1964, +0.61,0.619,0.62370588,0.60344444,1371,11/10/2019 14:24,male,1,1964, +0.5152,0.609875,0.52338889,0.62375,1371,11/10/2019 14:29,male,1,1964, +1,0.4995,0.70825,0.6202,1371,10/22/2019 19:48,male,1,1964, +0.79328571,0.92257143,0.78185714,0.6352,1372,10/22/2019 19:31,male,1,1974, +0.73485714,0.75522222,0.958,0.814,1373,10/22/2019 19:35,male,1,1986, +3.4555,1.907,1.34885714,2.0795,1374,10/22/2019 19:34,male,1,1948, +2.0695,1.33366667,1.64583333,1.73275,1375,10/22/2019 19:38,female,1,1976, +1.54633333,1.85933333,1.47783333,1.2635,1377,10/22/2019 19:40,female,1,1959, +0.947,0.66644444,0.8688,0.69033333,1378,10/22/2019 19:42,male,1,1988, +0.6385,0.63611111,1.02055556,0.66911111,1379,10/22/2019 19:46,male,1,1969, +1.681375,2.0944,1.448,1.941,1380,10/22/2019 19:47,female,1,1974, +1.46175,1.4635,1.3745,1.385,1380,10/22/2019 20:40,female,1,1974, +1.22266667,1.96233333,1.4355,1.11671429,1382,10/22/2019 19:46,male,1,1958, +2.58733333,2.02366667,2.56533333,2.377,1383,10/22/2019 19:49,female,1,1974, +1.6084,1.1445,0.89533333,0.848,1384,10/22/2019 19:56,male,1,1983, +0.84881818,1.0915,0.85125,1.13588889,1386,10/22/2019 19:53,female,1,1980, +0.68090909,0.63741667,0.72857143,0.63842857,1387,10/22/2019 19:54,male,1,1977, +0.83,0.697,0.65771429,0.94275,1388,10/22/2019 20:06,male,1,2002, +1.0378,1.23616667,1.22114286,1.199,1389,10/22/2019 19:55,male,1,1989, +1.1155,1.1792,1.36025,1.22033333,1390,10/22/2019 19:56,female,1,1983, +2.681,2.68575,2.609,2.4935,1391,10/22/2019 20:01,female,1,1963, +1.159125,2.959,1.592,1.31775,1392,10/22/2019 19:56,male,0,1975, +0.825,0.89325,1.00911111,0.96033333,1393,10/22/2019 19:58,male,1,1989, +1.03816667,0.79588889,0.986,1.05616667,1394,10/22/2019 20:02,female,1,1988, +0.76511111,0.88242857,1.10833333,0.62181818,1395,10/22/2019 20:08,female,1,1984, +0.699,0.6905,0.67383333,0.641,1395,10/22/2019 20:22,female,1,1984, +1.265375,0.85533333,1.69175,1.230875,1396,10/22/2019 23:41,male,1,1944, +1.5984,1.40575,1.08,1.799875,1397,10/22/2019 20:05,female,1,1969, +0.75566667,0.68169231,0.65445455,0.77777778,1398,10/22/2019 20:05,male,1,2000,4 +0.70675,0.6941,0.61311111,0.63938462,1398,11/6/2019 7:08,male,1,2000,4 +0.64736364,0.666,0.8968,0.883,1398,11/3/2019 13:18,male,1,2000,4 +0.6242,0.5518,0.61566667,0.65775,1398,11/8/2019 7:09,male,1,2000,4 +0.66511111,0.75309091,0.64788889,0.7026,1398,11/4/2019 7:06,male,1,2000,4 +0.69444444,0.62030769,0.62972727,0.69216667,1398,11/9/2019 7:06,male,1,2000,4 +0.72566667,0.8888,0.68271429,0.8586,1398,11/5/2019 7:13,male,1,2000,4 +0.66821429,0.5955,0.634,0.64933333,1398,11/10/2019 9:51,male,1,2000,4 +7.217,2.754,3.759,3.914,1399,10/22/2019 20:10,female,1,1966, +1.35133333,1.78575,1.11172727,1.2874,1400,10/22/2019 20:38,female,1,2000, +0.697,0.89127273,0.59288889,0.64723077,1400,10/22/2019 20:08,female,1,2000, +0.54766667,0.6075,0.56236364,0.62654545,1400,10/22/2019 20:50,female,1,2000, +0.66236364,0.99255556,0.70033333,0.73428571,1400,10/22/2019 20:22,female,1,2000, +1.59966667,1.4565,1.243,1.029,1400,10/22/2019 20:26,female,1,2000, +2.64625,1.251,1.518,0.857,1401,10/22/2019 20:09,male,1,1972, +0.59353333,0.688625,0.68046154,0.60344444,1402,10/22/2019 20:08,male,1,1973, +1.0518,1.12688889,1.06983333,1.4048,1403,10/22/2019 20:09,male,1,1971, +0.94988889,1.8095,1.674,1.115375,1404,10/22/2019 20:09,female,0,1968, +1.51033333,1.739,1.42233333,1.5165,1405,10/22/2019 20:14,male,1,1966, +1.51885714,1.754,1.541,1.735,1405,10/22/2019 20:15,male,1,1966, +1.558,1.432,0.98116667,0.99985714,1406,10/22/2019 20:14,female,1,2000, +1.79833333,2.8215,1.94925,2.0475,1407,10/22/2019 20:22,female,1,1967, +1.22966667,1.49683333,1.3528,2.084,1408,10/22/2019 20:14,male,1,1983, +0.6092,0.6289,0.5409375,0.63088889,1409,10/22/2019 20:14,male,1,1989, +1.07357143,0.6165,0.7374,0.741375,1410,10/22/2019 20:16,male,1,1981, +0.8945,1.3454,1.481,1.03366667,1411,10/22/2019 20:18,male,1,1956, +2.574,1.97,2.2225,2.5755,1412,10/22/2019 20:19,female,0,1948, +0.50616667,0.504,0.52827273,0.627,1413,10/22/2019 20:20,male,1,1987, +1.04766667,0.73193333,0.81288889,0.91244444,1414,10/22/2019 20:24,male,1,1968, +1.04333333,0.9164,1.12533333,1.479125,1416,10/22/2019 20:23,male,1,1980,3 +1.22966667,0.89077778,1.0811,1.5575,1416,10/22/2019 20:38,male,1,1980,3 +0.59845455,0.81114286,0.65272727,0.69942857,1417,10/22/2019 20:23,male,1,2002, +1.21275,1.228,1.73528571,1.1228,1419,10/22/2019 21:00,male,1,1969, +0.68566667,0.811,1.294,0.922,1423,10/22/2019 20:29,male,1,1985, +0.973625,0.9163,0.92588889,0.74233333,1424,10/22/2019 20:30,male,1,1965, +1.174,0.90725,0.96783333,1.04114286,1425,10/22/2019 20:33,female,1,1968, +0.76388889,0.71054545,0.79475,0.824,1426,10/22/2019 20:33,male,1,1988, +2.357,2.52,1.872,1.86783333,1427,10/22/2019 20:54,male,1,1952, +0.92566667,0.810875,0.77844444,0.7255,1428,10/22/2019 20:34,male,1,1988, +1.06544444,0.95514286,0.97716667,0.84388889,1429,10/22/2019 20:36,female,1,1975, +0.71185714,0.89375,0.66475,0.81684615,1430,10/22/2019 20:37,male,1,1988, +1.6435,1.537,1.6,1.56216667,1432,10/22/2019 20:42,female,0,1979, +0.75416667,0.84585714,0.71627273,0.880625,1433,10/22/2019 20:43,female,1,2001, +0.81957143,0.79144444,0.81533333,0.9312,1434,10/22/2019 20:44,male,1,1986, +0.49,0.8345,0.673,0.73566667,1435,10/22/2019 21:19,male,1,1998, +0.8665,0.69390909,1.015375,0.981,1437,10/22/2019 20:49,male,1,1980, +0.99344444,1.079,0.86642857,0.96916667,1438,10/22/2019 20:45,male,0,1987, +1.33,1.227,1.22066667,1.0355,1439,10/22/2019 20:47,male,1,1967, +1.358125,1.09542857,1.1268,1.0534,1440,10/22/2019 20:49,female,1,1973, +1.57225,1.176,1.239,1.703,1441,10/22/2019 20:46,female,1,1987, +1.06925,1.49233333,1.20066667,1.396,1442,10/22/2019 20:50,male,0,1957, +0.63766667,0.8571,0.73883333,0.75983333,1442,11/4/2019 7:41,male,0,1957, +1.65833333,0.96890909,0.94892308,1.118,1443,10/22/2019 20:49,female,1,1972, +1.31233333,1.3375,1.11683333,1.4712,1444,10/22/2019 20:50,male,1,1973, +1.2555,1.22375,1.74466667,1.3318,1445,10/22/2019 20:49,male,1,1986, +3.12633333,3.6995,3.761,4.254,1446,10/23/2019 0:16,female,1,1948, +0.68681818,0.7301,0.86044444,0.6645,1447,10/22/2019 20:51,male,1,1977, +1.337,1.346,1.3855,1.35614286,1448,10/22/2019 20:55,male,1,1958, +0.9158,0.8752,0.98809091,0.98722222,1449,10/22/2019 20:53,female,1,1980, +2.12875,3.138,2.9325,3.0185,1450,10/22/2019 20:56,male,1,1968, +1.15885714,3.526,1.151,2.239,1451,10/22/2019 20:56,female,1,1976, +0.97488889,1.12375,0.86575,1.120875,1452,10/22/2019 21:41,male,1,1975, +1.3665,1.23866667,1.66275,1.51033333,1453,10/22/2019 21:00,male,1,1977, +0.949,0.91788889,0.79627273,0.79166667,1454,10/22/2019 21:03,male,1,1976, +0.71188889,0.721625,0.62214286,0.52457143,1455,10/22/2019 21:04,male,1,1987, +0.77255556,1.01442857,0.7234,0.8136,1456,10/22/2019 21:08,male,1,1972, +1.1974,1.21,1.16242857,1.565,1457,10/22/2019 21:07,female,1,1990, +0.608,0.56753333,0.704625,0.487,1458,10/22/2019 21:07,male,1,1986, +1.5845,2.41433333,2.50433333,1.883,1459,10/22/2019 21:12,male,1,1954, +1.9535,2.69366667,1.987,3.663,1460,10/22/2019 21:14,female,1,1984, +1.345,0.584,0.63325,0.628,1461,10/22/2019 21:17,female,1,1999, +1.1552,0.95475,0.9525,1.205,1462,10/22/2019 21:13,female,1,1964, +1.8155,1.7376,1.60266667,2.044,1463,10/22/2019 21:15,female,0,1964, +0.638875,0.501,0.660625,0.82757143,1464,10/22/2019 21:14,female,1,1983, +0.6125,0.531,0.516,0.65688889,1466,10/22/2019 21:15,male,1,1986, +0.71983333,0.771,0.82111111,1.0852,1467,10/22/2019 21:21,male,1,1985, +0.672625,0.62985714,0.59892308,0.63483333,1468,10/22/2019 21:30,male,1,2001, +1.17916667,2.22733333,1.639,1.67,1469,10/22/2019 21:22,male,1,1956, +2.758,3.01333333,2.797,2.90866667,1470,10/22/2019 21:24,female,1,1945, +1.332,1.3404,1.22175,1.7305,1472,10/22/2019 21:30,female,0,1978, +2.2524,3.19566667,3.042,2.709,1473,10/22/2019 21:33,male,1,1958, +0.94,1.09425,1.17825,0.897,1474,10/22/2019 21:34,male,1,1967, +0.55363636,1.4706,0.73218182,0.767,1476,10/22/2019 21:35,male,1,1986, +0.767625,0.64275,0.7201,0.77536364,1477,10/22/2019 21:37,male,1,1995, +1.42325,0.73642857,0.81885714,1.09557143,1478,10/22/2019 21:39,male,1,1988, +1.48033333,1.1825,1.06416667,1.03614286,1479,10/22/2019 21:40,male,0,1965, +1.05985714,1.06775,1.6624,1.20775,1480,10/22/2019 22:27,male,1,1986, +0.77975,0.77533333,0.98575,0.72141667,1481,10/22/2019 21:50,male,1,1966, +0.77975,0.77533333,0.98575,0.72141667,1481,10/22/2019 21:50,male,1,1966, +1.11066667,1.12875,1.1046,1.14916667,1482,10/22/2019 21:50,male,1,1964, +1.532,2.88833333,2.406,1.44,1483,10/22/2019 21:55,male,1,1956, +1.4925,1.208,1.4805,1.60133333,1484,10/22/2019 21:59,female,1,1974, +1.004875,0.843375,1.1295,1.11914286,1485,10/22/2019 21:55,male,1,1976, +0.49673333,0.5916,0.63669231,0.47163636,1487,11/10/2019 15:48,male,1,2000, +0.55838462,0.83283333,0.605,0.609625,1487,10/22/2019 22:10,male,1,2000, +0.59788889,0.55646667,0.5945,0.5616875,1487,11/10/2019 16:14,male,1,2000, +0.5766,0.58058333,0.5826,0.55111111,1487,11/10/2019 14:51,male,1,2000, +0.50211765,0.55583333,0.705,0.54226667,1487,11/10/2019 16:27,male,1,2000, +0.56876471,0.48771429,0.58421429,0.636,1487,11/10/2019 15:17,male,1,2000, +0.52866667,0.46326316,0.55991667,0.52525,1487,11/10/2019 16:38,male,1,2000, +1.12975,1.20925,1.41214286,1.161,1488,10/22/2019 22:33,male,1,1988, +2.2085,1.89166667,2.74133333,2.416,1490,10/22/2019 22:12,male,1,1985, +3.9595,4.485,3.2235,2.811,1490,10/22/2019 22:24,male,1,1985, +2.049,1.57333333,1.6045,1.641,1491,10/22/2019 22:11,male,1,1956, +1.63266667,1.7185,2.11766667,1.64114286,1492,10/22/2019 22:12,male,1,1988, +0.65033333,0.58766667,0.6025,0.65733333,1493,10/22/2019 22:14,male,1,1988, +4.1645,4.243,3.22466667,3.2785,1494,10/22/2019 22:23,male,1,1958, +2.985,2.785,3.701,3.145,1494,10/22/2019 23:35,male,1,1958, +0.96114286,0.9016,0.84333333,1.08266667,1495,10/22/2019 22:18,male,1,1986, +0.97633333,1.0658,1.209125,0.8311,1496,10/22/2019 22:24,female,1,1986, +0.61527273,0.45466667,0.69244444,0.71007692,1498,10/22/2019 22:18,male,1,1997, +2.20275,1.46275,1.7264,1.3312,1500,10/22/2019 22:21,male,1,1986, +0.7115,0.8252,0.733,0.86077778,1501,10/22/2019 22:22,male,1,1990, +2.002,1.88514286,1.5785,1.76133333,1503,10/22/2019 22:25,female,1,1976, +0.983,0.90844444,1.59785714,1.108,1504,10/22/2019 22:23,male,1,1962, +0.66375,0.6675,0.786,0.725,1505,10/22/2019 22:29,male,1,1985, +1.150125,0.992,1.09471429,1.0795,1508,10/22/2019 22:30,male,1,1987, +0.86866667,0.68433333,0.74177778,0.9328,1509,10/22/2019 22:31,male,1,1989, +0.9429,0.83628571,0.82090909,0.9226,1510,10/22/2019 22:37,male,1,1970, +0.83866667,0.58528571,0.647125,0.614,1511,10/22/2019 22:37,female,1,1988, +1.955,3.889,1.95033333,2.16066667,1512,10/22/2019 22:39,female,1,1978, +0.99428571,0.8785,0.903,1.1722,1513,10/22/2019 22:38,male,1,1971, +0.60572727,0.67871429,0.7585,0.66954545,1514,10/22/2019 22:46,male,1,1986, +3.26,2.9975,1.79025,3.3815,1515,10/22/2019 22:53,female,1,1964, +2.905,2.9605,1.8905,2.6505,1516,10/22/2019 22:47,female,0,1976, +0.56884615,0.5645,0.50557143,0.602125,1517,10/22/2019 22:47,male,1,1986, +1.3848,1.35085714,1.60925,1.1792,1518,10/22/2019 22:54,male,1,1966, +0.97066667,1.20185714,1.7145,1.37033333,1519,10/22/2019 22:47,male,1,1964, +5.237,4.9265,3.642,3.54233333,1520,10/22/2019 22:52,female,1,1953, +1.243,1.048625,1.38133333,1.40157143,1521,10/22/2019 22:54,male,1,1966, +1.01777778,0.8628,1.1418,1.162,1522,10/22/2019 22:53,female,1,1975, +1.6575,1.3724,1.27983333,1.0004,1523,10/22/2019 22:55,female,1,1985, +1.7315,1.40044444,1.196,1.7205,1524,10/22/2019 22:55,female,1,1947, +0.96328571,0.817,1.48633333,1.17771429,1525,10/22/2019 23:00,male,1,1986, +0.97033333,1.1465,1.28022222,0.82871429,1526,10/22/2019 23:18,female,1,1987, +0.91,0.88442857,0.83255556,0.888,1528,10/22/2019 23:06,female,1,1981, +1.0665,0.92116667,1.5065,1.038125,1529,10/22/2019 23:05,female,1,1969, +0.802,0.639,0.89866667,1.051625,1530,10/22/2019 23:11,male,1,1973, +1.573,3.089,1.96142857,2.26,1532,10/22/2019 23:13,male,0,1965, +0.62314286,0.628,0.56509091,0.80527273,1533,10/22/2019 23:12,male,1,1981, +0.70025,0.71863636,0.80166667,1.02266667,1535,10/22/2019 23:14,male,1,1999, +0.84472727,0.87,0.962375,0.9725,1536,10/22/2019 23:15,female,1,1986, +0.94466667,1.035,0.90636364,0.9668,1537,10/22/2019 23:19,male,1,1973, +1.681,1.643,1.433625,1.52625,1539,10/22/2019 23:19,female,1,1975, +2.798,1.34883333,0.8755,1.05925,1540,10/22/2019 23:19,female,1,1984, +0.98314286,0.97441667,0.92233333,1.126,1541,10/22/2019 23:21,male,1,1968, +1.1536,0.87975,1.32644444,0.95,1542,10/22/2019 23:30,male,1,1985, +0.64116667,0.5979,0.6504,0.79791667,1543,10/22/2019 23:23,male,1,1989, +0.74230769,0.85588889,0.8775,1.01566667,1544,10/23/2019 1:09,male,1,1989, +3.9715,3.419,3.38433333,2.9185,1545,10/22/2019 23:30,female,1,1954, +0.60308333,0.48333333,0.5248,0.732,1546,10/23/2019 0:17,male,1,1997, +0.6452,0.76916667,0.8191,0.85675,1547,10/22/2019 23:31,female,1,1980, +0.758375,0.7499,0.7245,0.97066667,1548,10/22/2019 23:32,male,1,1985, +1.0668,1.2464,1.0405,1.06977778,1550,10/22/2019 23:36,male,1,1968, +1.8785,1.5548,1.73575,1.656,1552,10/22/2019 23:37,female,1,1970, +0.62088889,0.66392857,0.88585714,0.71858333,1553,10/22/2019 23:38,male,1,1976, +0.59291667,0.72109091,0.64372727,0.60284615,1555,10/22/2019 23:41,male,1,2000,4 +0.52226667,0.55713333,0.63016667,0.96433333,1555,11/23/2020 13:44,male,1,2000,4 +1.05575,2.1595,2.252,1.59575,1557,10/22/2019 23:44,male,1,1964, +1.74666667,1.77025,1.566,1.803,1558,10/22/2019 23:50,male,1,1948, +0.65172727,0.53957143,0.6735625,0.4142,1559,10/22/2019 23:50,male,1,1977, +0.66181818,0.73491667,0.7256,0.776625,1560,10/22/2019 23:54,male,1,1963, +1.154,1.23577778,1.25175,1.195,1560,10/23/2019 0:10,male,1,1963, +0.926125,1.06716667,1.14022222,0.9292,1561,10/22/2019 23:54,female,1,1986, +1.8625,2.2256,1.74733333,2.12575,1563,10/22/2019 23:57,male,1,1962, +0.6676,0.63930769,0.71063636,0.52515385,1564,10/23/2019 0:00,male,1,1973, +1.05257143,1.29675,1.056125,1.09175,1565,10/22/2019 23:58,male,1,1967, +1.286,1.6748,1.293,1.12342857,1566,10/23/2019 0:03,male,1,1977, +4.015,4.945,4.141,4.205,1568,10/23/2019 0:10,male,1,1942, +1.86266667,1.5498,2.653,2.2612,1569,10/23/2019 0:10,female,1,1947, +1.5768,1.799,1.5395,2.2986,1569,10/23/2019 0:25,female,1,1947, +0.91216667,1.172125,0.771125,1.191,1570,10/23/2019 0:10,male,1,1981, +0.62672727,0.82783333,1.10714286,1.13377778,1571,10/23/2019 0:14,female,1,1973, +1.592,0.8972,0.8085,1.0098,1572,10/23/2019 1:13,male,1,1988, +0.66331579,0.6415,0.8846,0.62709091,1573,10/23/2019 0:18,female,1,1983, +0.8078,1.8124,1.777,1.23016667,1574,10/23/2019 0:25,male,1,1973, +2.528,2.991,2.23675,2.604,1575,10/23/2019 0:26,male,1,1962, +1.22590909,1.19383333,1.421,1.5355,1577,10/23/2019 0:40,male,1,1985, +0.93088889,1.14166667,1.084,1.4518,1577,10/23/2019 0:48,male,1,1985, +1.05871429,0.96722222,0.94485714,1.069,1578,10/23/2019 0:33,male,1,1965, +3.042,2.9798,2.425,1.604,1579,10/23/2019 0:35,female,1,1976, +0.63091667,0.60255556,0.68488889,0.72942857,1580,10/23/2019 0:34,male,1,1986, +0.837,0.97083333,1.0125,1.20385714,1581,10/23/2019 0:38,female,1,1988, +2.8135,1.67883333,1.76025,1.59525,1582,10/23/2019 0:39,male,1,1960, +2.56033333,4.0225,2.668,2.605,1583,10/23/2019 0:38,female,1,1956, +1.02925,0.8381,1.02257143,0.91433333,1584,10/23/2019 0:43,male,1,1984, +1.15116667,1.4015,0.89641667,1.6015,1585,10/23/2019 0:44,female,1,1945, +0.68225,0.71918182,0.77388889,0.9159,1586,10/23/2019 0:47,male,1,1979, +3.343,2.178,2.30533333,4.876,1587,10/23/2019 0:52,female,1,1942, +1.0452,0.913,0.74122222,0.77116667,1588,10/23/2019 0:53,male,1,1972, +1.563,1.88175,2.28533333,1.67633333,1589,10/23/2019 0:56,female,1,1957, +0.92242857,0.80975,0.9465,0.9276,1592,10/23/2019 1:01,male,1,1989, +1.032625,1.4896,1.02418182,1.2,1593,10/23/2019 1:00,female,1,1988, +1.01842857,1.01636364,0.9926,1.09183333,1594,10/23/2019 1:07,female,1,1987, +0.68,0.569,0.82142857,0.77525,1595,10/23/2019 1:09,female,1,1989, +0.669,1.0418,0.814,0.755,1596,10/23/2019 1:11,male,1,1986, +0.905,0.75081818,1.1515,0.96175,1597,10/23/2019 1:11,male,1,1975, +1.1795,0.921,1.15485714,1.174,1599,10/23/2019 1:16,male,1,1975, +0.686875,0.54485714,0.7052,0.881,1600,10/23/2019 1:25,male,1,1987, +1.10725,1.15755556,1.171375,1.40525,1602,10/23/2019 1:29,female,1,1965, +2.7566,1.969,2.01425,2.707,1604,10/23/2019 1:37,male,1,1950, +1.2004,0.91016667,0.994875,0.9912,1605,10/23/2019 1:38,male,1,1967, +1.48866667,1.467,1.5375,1.79225,1606,10/23/2019 1:40,male,1,1964, +0.93025,0.65744444,0.88785714,1.10011111,1607,10/23/2019 1:56,male,1,1977, +0.8375,0.67925,0.79716667,0.80123077,1608,10/23/2019 1:48,female,1,1985, +2.34925,2.523,2.47966667,2.0875,1610,10/23/2019 1:55,male,1,1944, +1.28,0.91142857,1.212,1.0178,1612,10/23/2019 2:19,female,0,1980, +0.64316667,0.531,0.65525,0.73633333,1613,10/23/2019 2:18,male,1,1970, +0.98988889,1.1948,1.183,1.22428571,1614,10/23/2019 2:27,male,1,1989, +0.61436364,0.62653333,0.76133333,0.60053333,1615,10/23/2019 2:29,female,1,1982, +0.54133333,0.4539375,0.58535714,0.55654545,1616,10/23/2019 2:30,male,1,1987, +1.02542857,1.08933333,0.97322222,1.07042857,1617,10/23/2019 2:37,male,1,1970, +0.78411111,1.185,0.84922222,0.9198,1617,10/23/2019 2:36,male,1,1970, +2.704,2.1565,1.98925,2.817,1619,10/23/2019 2:52,male,1,1948, +1.5838,1.27483333,1.2146,1.20616667,1620,10/23/2019 2:54,male,1,1967, +2.4595,2.26833333,1.8215,2.1595,1621,10/23/2019 3:04,male,1,1966, +1.908,1.39575,1.406,1.37816667,1622,10/23/2019 3:02,male,1,1958, +0.689,0.7054,0.67314286,0.590875,1623,10/23/2019 3:07,male,1,1987, +2.16225,1.6165,1.7065,1.6335,1624,10/23/2019 3:15,male,1,1943, +4.198,2.1545,2.39333333,2.094,1624,10/23/2019 3:17,male,1,1943, +0.66423077,0.71433333,0.8726,0.96875,1625,10/23/2019 4:10,male,1,1986, +1.535,1.53733333,1.01225,1.33775,1626,10/23/2019 4:16,male,1,1957, +2.627,2.39666667,4.02,2.448,1627,10/23/2019 6:19,male,1,1964, +2.62333333,1.61525,1.2155,0.71675,1630,10/23/2019 15:20,female,1,1999, +0.95271429,0.92625,0.8957,0.9682,1632,10/23/2019 15:42,female,1,1988, +2.27775,1.6155,1.6788,2.523,1633,10/23/2019 16:04,female,1,1963, +1.095,0.88466667,1.035,0.969,1636,10/23/2019 17:11,female,1,1986, +0.855125,1.145375,0.76375,1.02625,1639,10/24/2019 15:27,male,1,1990, +0.957,0.551,1.05475,0.99133333,1640,10/24/2019 15:47,male,1,1982, +2.371,2.911,2.20233333,2.72366667,1641,10/26/2019 16:37,male,1,1965, +0.82928571,0.85814286,0.74425,0.68566667,1643,10/23/2019 17:55,female,1,1976, +1.1945,0.928,1.3455,1.228125,1644,10/23/2019 18:42,male,1,1967, +2.181,1.672,1.56766667,2.0845,1645,10/26/2019 15:59,female,1,1973, +2.539,3.645,1.49,3.54166667,1646,10/26/2019 17:39,male,1,1957, +1.01714286,0.988,1.3165,1.469,1647,10/23/2019 18:16,male,1,1974, +0.63177778,0.58561538,0.61358333,0.57406667,1648,10/23/2019 18:25,male,1,1975, +1.058,1.6944,1.003,1.15671429,1649,10/23/2019 18:44,male,1,1979, +1.07111111,1.10325,0.863875,1.24583333,1650,10/23/2019 18:51,female,1,1988, +0.67177778,0.58508333,0.83091667,0.6621,1651,10/23/2019 18:57,male,1,1988, +0.89990909,0.99125,0.69683333,0.68081818,1652,10/23/2019 19:03,female,1,1974, +1.58785714,1.78033333,1.7875,1.96,1653,10/23/2019 19:11,male,1,1958, +1.01725,1.06785714,0.9165,0.94433333,1654,10/23/2019 19:16,female,1,1967, +0.6472,0.61646154,0.60873333,0.66988889,1655,10/23/2019 19:19,male,1,1967, +0.579,0.522875,0.51538462,0.58077778,1656,10/23/2019 19:23,male,1,1977, +0.977375,0.937625,1.13483333,0.877875,1657,10/23/2019 20:06,female,1,1969, +5.469,1.655,2.2196,1.94325,1658,10/23/2019 20:05,male,1,1987, +0.595875,0.836625,0.8491,0.76115385,1660,10/23/2019 20:16,male,1,1982, +2.6595,1.6655,2.424,2.20975,1662,10/23/2019 20:30,female,1,1956, +1.35133333,1.53733333,1.591,1.8166,1665,10/23/2019 20:53,male,1,1953, +0.53123077,0.69441667,0.83683333,0.65678571,1666,10/23/2019 22:20,female,1,1989, +0.703,0.963,0.74542857,0.64666667,1669,10/23/2019 21:38,male,1,2000, +1.33222222,1.34766667,1.23733333,1.33216667,1672,10/23/2019 21:55,male,1,1950, +0.83433333,1,0.859,1.05788889,1673,10/24/2019 17:13,male,1,1972, +0.71227273,0.805,1.2974,1.14527273,1675,10/24/2019 17:24,female,1,1979, +0.897,0.89977778,1.46283333,0.868375,1676,10/25/2019 12:26,female,1,1999, +1.09611111,1.2985,1.437,1.4256,1679,10/25/2019 16:01,female,1,1981, +3.726,1.54666667,1.4285,2.624,1680,10/25/2019 20:45,male,1,1976, +1.3974,1.828,1.504,1.45866667,1680,10/26/2019 11:15,male,1,1976, +0.8149,1.14228571,0.89414286,0.941875,1680,10/26/2019 11:17,male,1,1976, +0.48633333,0.55142857,0.63185714,0.49023529,1681,10/25/2019 17:19,male,1,1985, +1.2514,1.106,1.2525,1.24714286,1682,10/25/2019 17:35,male,1,1958, +1.17375,1.2255,1.01833333,0.86688889,1682,10/25/2019 17:49,male,1,1958, +1.86833333,1.678,1.555,2.538,1684,10/25/2019 21:46,male,1,1954, +0.853,0.55753846,0.707375,0.67036364,1685,10/25/2019 22:04,male,1,1987, +0.698875,0.67857143,0.679,0.84718182,1686,10/25/2019 22:23,male,1,1976, +0.616125,1.18144444,0.94616667,0.69183333,1687,10/26/2019 11:57,female,1,1988, +0.80171429,0.6941,0.97742857,0.74692308,1687,10/26/2019 11:58,female,1,1988, +1.0282,0.73385714,1.0423,1.17757143,1688,10/26/2019 12:05,male,1,1971, +0.927,0.8598,1.13875,0.83285714,1688,10/26/2019 12:06,male,1,1971, +1.14925,0.8908,2.3005,1.239,1688,10/26/2019 12:03,male,1,1971, +0.68244444,0.6306,0.646,0.657,1689,10/26/2019 12:47,male,1,1997, +2.011,1.99533333,1.69,1.506,1690,10/26/2019 15:20,male,1,1960, +0.869,0.6126,0.7001,0.7091,1691,10/26/2019 15:26,male,1,1965, +1.333,1.8995,1.40883333,1.67433333,1692,10/26/2019 15:36,male,1,1952, +1.14433333,1.143,1.187,1.095125,1693,10/26/2019 19:33,male,1,1968, +1.1978,1.25666667,1.40728571,1.278875,1694,10/26/2019 18:51,female,1,1978, +1.3398,1.20771429,0.999,1.08475,1695,10/26/2019 19:03,male,1,1988, +1.2904,1.0184,1.02509091,0.99471429,1695,10/26/2019 19:03,male,1,1988, +0.679,0.9056,1.54533333,0.82066667,1696,10/26/2019 20:08,male,1,1983, +1.124375,1.35666667,1.52466667,1.2185,1697,10/26/2019 19:44,female,1,1987, +2.6726,1.5525,2.678,1.668,1698,10/26/2019 21:45,female,1,1980, +0.8932,1.41,1.14575,1.06855556,1698,10/26/2019 21:48,female,1,1980, +2.6726,1.5525,2.678,1.668,1698,10/26/2019 21:45,female,1,1980, +2.0346,1.6405,2.24116667,1.105,1698,10/26/2019 21:46,female,1,1980, +1.95225,1.966,1.618,1.2994,1698,10/26/2019 21:47,female,1,1980, +2.67425,2.49,1.8715,1.8582,1699,10/27/2019 10:28,female,1,1980, +0.75309091,0.72871429,0.7276,0.816875,1700,10/27/2019 11:21,male,1,1975, +1.14525,1.2985,1.184,1.3395,1701,10/27/2019 11:41,female,1,1982, +0.91766667,0.66088889,0.9986,0.93133333,1703,10/27/2019 12:55,female,1,2000, +3.115,3.25766667,2.8645,4.1,1704,10/27/2019 13:05,female,0,1963, +1.08711111,0.84983333,1.03771429,0.7074,1705,10/27/2019 13:08,female,1,1974, +0.50558824,0.51666667,0.64633333,0.6470625,1706,10/27/2019 13:23,male,1,2012, +2.512,2.88616667,1.936,1.592,1707,10/27/2019 13:51,male,1,1950, +1.21533333,0.87,1.40128571,1.1132,1708,10/27/2019 14:34,female,1,1948, +1.01044444,1.24375,1.01075,1.13433333,1709,10/27/2019 16:18,female,1,1975, +0.851,1.038875,1.238375,0.9698,1711,10/27/2019 17:28,female,1,1981, +0.847625,1.032875,0.873,0.8767,1712,10/27/2019 17:35,female,1,1987, +0.54275,0.58969231,0.74233333,0.68133333,1713,10/27/2019 17:51,male,1,1983, +0.68575,0.81666667,0.95666667,0.69442857,1714,10/27/2019 17:57,male,1,1984, +1.398,1.33125,1.145,1.42633333,1715,10/27/2019 18:02,male,1,1969, +2.76325,3.615,3.7565,3.5155,1716,10/27/2019 18:21,female,1,1948, +0.75892308,0.790625,0.811,0.60055556,1717,10/27/2019 18:24,male,1,1976, +0.7051,0.9834,0.82925,0.86766667,1718,10/27/2019 18:52,female,1,1958, +1.15171429,1.11766667,0.8895,1.00742857,1720,10/27/2019 19:20,female,1,1964, +1.17775,1.4427,1.2192,1.31166667,1721,10/27/2019 20:50,male,1,1974, +2.0115,1.2855,1.775,1.508,1721,10/27/2019 20:51,male,1,1974, +1.96233333,2.39733333,2.3375,2.255,1723,10/29/2019 15:56,male,1,1968, +1.967,1.9112,1.352,2.015,1724,10/27/2019 20:22,male,1,1980, +1.18457143,1.77,1.42533333,1.01671429,1725,10/27/2019 21:07,female,1,1987, +0.6826,0.593,0.82377778,0.63033333,1726,11/6/2019 8:44,female,1,2000,3 +1.0505,0.507875,0.553,0.68066667,1726,11/10/2019 16:32,female,1,2000,3 +1.557,0.935,1.57325,1.4694,1726,10/27/2019 20:53,female,1,2000,3 +0.72625,0.51525,0.63266667,0.5204,1726,11/7/2019 8:39,female,1,2000,3 +0.608875,0.6575,0.7685,0.56206667,1726,11/10/2019 20:37,female,1,2000,3 +1.20183333,0.967,0.9907,1.49725,1726,10/27/2019 20:54,female,1,2000,3 +0.744,0.616375,0.5485,0.59845455,1726,11/8/2019 8:10,female,1,2000,3 +0.68,0.561,0.9478,0.626875,1726,12/16/2019 21:53,female,1,2000,3 +0.76772727,0.607,0.67081818,0.77354545,1726,11/6/2019 8:35,female,1,2000,3 +0.55454545,0.65985714,0.63625,0.5542,1726,11/10/2019 16:04,female,1,2000,3 +1.36457143,1.45975,1.517,1.0904,1727,10/29/2019 14:44,male,1,1998, +1.38985714,1.0275,1.33071429,0.98233333,1727,10/29/2019 14:45,male,1,1998, +1.143125,1.26566667,1.709,1.099,1727,10/29/2019 14:46,male,1,1998, +1.71633333,0.74285714,1.40733333,1.34633333,1727,10/29/2019 14:43,male,1,1998, +1.42088889,1.03375,1.5922,0.9706,1727,10/29/2019 14:47,male,1,1998, +0.87514286,1.07133333,0.9562,1.85625,1728,10/28/2019 16:10,male,1,2000, +1.25916667,1.72166667,1.6898,1.518,1729,10/28/2019 16:37,female,1,1982, +1.1734,1.2884,1.06857143,1.24525,1730,10/28/2019 17:24,male,1,1973, +1.54414286,2.47466667,0.628,1.643,1731,10/28/2019 20:22,male,1,2002, +1.119,2.1655,0.898,1.22025,1732,10/28/2019 18:36,male,1,1968, +1.25171429,1.0245,0.82657143,0.873,1733,10/28/2019 19:50,male,1,2005, +0.83127273,0.9545,0.93925,0.79981818,1734,10/28/2019 20:01,female,1,1974, +0.7235,1.004,0.92814286,1.10442857,1736,10/28/2019 20:24,female,1,1986, +1.2436,1.3964,1.329,1.223625,1737,10/28/2019 22:00,female,1,1970, +1.47425,2.258,1.6006,2.55733333,1737,10/28/2019 20:53,female,1,1970, +1.3615,1.04166667,0.945,1.3425,1738,10/28/2019 20:34,male,1,1967, +1.1072,1.088,0.82155556,0.84777778,1739,10/28/2019 20:47,female,1,1984, +1.8922,1.0794,1.404,1.846,1740,10/28/2019 21:19,male,1,1988, +0.940625,1.37928571,1.04985714,1.2355,1741,10/28/2019 21:21,male,1,1988, +0.95788889,1.03383333,0.99316667,1.120375,1742,10/28/2019 21:47,female,0,1986, +1.37166667,1.71571429,1.9165,1.97,1743,10/28/2019 22:19,male,1,1965, +2.0052,2.489,1.93716667,2.898,1745,10/28/2019 22:38,female,1,1955, +0.8124,1.139,1.26233333,0.9545,1748,10/29/2019 18:21,male,1,1982, +0.85036364,0.66414286,0.79616667,0.625,1748,10/29/2019 18:22,male,1,1982, +0.49825,0.58766667,0.5444,0.704,1749,10/29/2019 18:46,male,1,1983, +0.57372727,0.52746154,0.51235294,0.5166,1750,10/29/2019 18:55,male,1,1985, +0.55536842,0.66241667,0.78628571,0.792,1751,10/29/2019 19:04,female,1,1974, +0.66125,0.65588889,0.73035714,0.71518182,1752,10/29/2019 19:14,female,1,1980, +0.84166667,0.63315385,0.90257143,0.58564706,1752,10/29/2019 19:08,female,1,1980, +0.716625,0.5888,0.81742857,0.67214286,1752,10/29/2019 19:09,female,1,1980, +0.7815,0.6824,0.8716,0.672,1752,10/29/2019 19:13,female,1,1980, +0.59585714,0.595875,0.6731875,0.5803,1753,10/29/2019 19:34,male,1,1980, +0.85033333,0.81316667,1.13916667,0.80869231,1754,10/29/2019 19:43,male,1,1973, +0.944,0.993,0.930125,1.04990909,1755,10/29/2019 19:47,male,1,1982, +1.23325,1.3814,1.25825,1.22916667,1756,10/29/2019 20:01,male,1,1961, +0.913,1.142,1.5422,1.37277778,1757,10/29/2019 20:13,female,1,1974, +2.2118,2.119,2.808,2.48,1758,10/29/2019 20:14,male,1,1955, +1.61755556,2.637,1.32825,1.4624,1759,10/29/2019 21:20,male,1,1967, +2.91733333,2.03733333,2.77166667,2.24066667,1760,10/29/2019 21:41,female,1,1951, +0.83875,1.12066667,0.7592,1.1465,1761,10/29/2019 22:01,male,1,1989, +1.85925,1.5205,1.42033333,1.859,1762,10/29/2019 22:21,female,1,1975, +2.0475,1.9905,1.4626,1.668,1763,10/29/2019 22:37,male,1,1971, +0.995,1.25616667,1.41914286,1.356,1764,10/29/2019 22:57,male,1,1949, +0.83041667,0.836,0.72775,0.61123077,1766,10/30/2019 18:30,male,1,1982, +1.31033333,1.6465,1.85683333,1.8955,1767,10/30/2019 19:21,female,1,1967, +0.9235,1.277,0.96171429,1.272,1768,10/30/2019 19:36,female,1,1985, +0.887,0.81533333,0.56533333,1.679,1769,10/30/2019 19:55,male,1,1975, +0.84085714,0.83533333,0.78685714,0.895,1769,10/30/2019 19:56,male,1,1975, +1.7155,1.4795,1.344,1.335,1771,10/30/2019 22:11,male,1,1967, +0.92,1.20175,1.286,0.943,1772,10/30/2019 22:32,female,1,1971, +0.77963636,0.93875,0.66133333,0.97,1774,10/31/2019 15:46,female,1,2000, +1.32116667,1.2582,1.5635,1.47916667,1775,10/31/2019 17:34,male,1,1965, +0.7146,0.6538,0.818,0.61025,1776,10/31/2019 17:59,female,1,1980, +0.5042,0.6506875,0.47863636,0.56745455,1777,10/31/2019 18:02,female,0,1985, +0.50415,0.60253846,0.56045455,0.5732,1778,10/31/2019 18:23,male,1,1975, +2.49775,1.6815,2.429,2.4115,1779,10/31/2019 18:37,male,1,1948, +0.87754545,0.80625,0.7683,0.8833,1780,10/31/2019 18:41,male,1,1989, +1.08828571,1.14014286,1.25766667,1.6465,1782,10/31/2019 19:25,male,1,1960, +0.889,0.8136,1.2412,1.160125,1783,10/31/2019 19:40,female,1,1969, +1.66366667,1.87683333,1.33333333,1.52216667,1784,10/31/2019 22:04,male,1,1944, +0.7116,0.85418182,0.94814286,1.01166667,1786,11/1/2019 3:24,female,1,1992, +1.83,0.80233333,0.686,0.91711111,1789,11/1/2019 21:12,male,1,1982, +1.772625,0.81225,0.95416667,0.80775,1790,11/2/2019 12:15,male,1,2002, +0.60461538,0.58957143,0.745375,0.57184615,1792,11/7/2019 7:38,male,1,2000,2 +1.12714286,1.013375,1.053,1.18057143,1792,12/16/2019 17:50,male,1,2000,2 +1.1405,1.26,0.957625,0.8278,1792,11/4/2019 7:26,male,1,2000,2 +0.75045455,0.78433333,0.85736364,0.74442857,1792,11/7/2019 16:31,male,1,2000,2 +0.9598,0.74944444,0.71644444,1.14516667,1792,11/5/2019 5:26,male,1,2000,2 +0.9474,1.1534,0.77866667,0.83466667,1792,11/7/2019 16:57,male,1,2000,2 +0.920375,0.740125,0.80961538,0.78628571,1792,11/6/2019 7:30,male,1,2000,2 +1.43728571,1.195,1.07033333,1.33066667,1792,11/7/2019 17:11,male,1,2000,2 +0.61415385,0.581,0.63955556,0.65569231,1793,11/3/2019 13:13,male,1,2000, +1.37333333,1.47775,1.68842857,1.5612,1794,11/3/2019 14:57,male,1,1981, +1.1412,1.02185714,1.2068,1.19722222,1795,11/3/2019 15:39,male,1,1970, +1.84533333,1.5116,2.20075,2.258,1796,11/3/2019 15:57,male,1,1954, +0.8222,0.74811111,0.60388235,1.139,1797,11/3/2019 16:04,male,1,1975, +0.68966667,0.49457143,0.5585,0.9215,1798,11/8/2019 7:39,male,1,2000,3 +0.571,0.78933333,0.687,0.837,1798,11/9/2019 7:08,male,1,2000,3 +0.753,0.581,0.6925,0.927,1798,11/6/2019 7:28,male,1,2000,3 +0.59358824,0.76716667,0.67033333,0.76677778,1798,11/10/2019 10:55,male,1,2000,3 +0.72690909,0.76855556,0.7255,0.778625,1798,11/7/2019 7:32,male,1,2000,3 +0.6675,0.60933333,0.568,0.8445,1798,12/16/2019 19:39,male,1,2000,3 +0.49235,0.51525,0.553125,0.56375,1799,11/3/2019 23:15,male,1,2000, +0.59726667,0.687,0.77666667,0.7783,1799,11/10/2019 12:32,male,1,2000, +0.71106667,0.57876923,0.72275,0.76990909,1800,11/6/2019 13:29,male,1,1995, +0.57927273,0.50635714,0.52705882,0.54238462,1800,11/10/2019 16:07,male,1,1995, +0.65355556,0.56745455,0.6575,0.78311111,1800,11/7/2019 14:19,male,1,1995, +0.9155,1.3585,0.764,1.27155556,1800,11/4/2019 13:41,male,1,1995, +0.6637,0.56133333,0.69338462,0.61122222,1800,11/8/2019 10:36,male,1,1995, +0.69675,0.65716667,0.7235,0.78,1800,11/5/2019 15:00,male,1,1995, +0.5561875,0.514625,0.62836364,0.63853846,1800,11/9/2019 15:46,male,1,1995, +0.61727273,0.65653846,0.71,0.51727273,1801,11/8/2019 8:37,female,1,2000, +0.70254545,0.78425,0.808875,0.731,1801,11/4/2019 8:22,female,1,2000, +0.611625,0.62122222,0.60905556,0.5755,1801,11/9/2019 8:05,female,1,2000, +0.94155556,0.75390909,0.7784,0.58288889,1801,11/6/2019 8:27,female,1,2000, +0.6659,0.56614286,0.576625,0.65533333,1801,11/10/2019 18:53,female,1,2000, +0.88625,0.584,1.009,1.0626,1801,11/7/2019 8:20,female,1,2000, +0.77188889,0.56258333,0.815,0.54916667,1802,11/10/2019 10:40,female,1,2000, +0.64233333,0.621,1.115,0.773,1802,11/5/2019 10:20,female,1,2000, +1.0918,0.62842857,0.69822222,0.726125,1802,11/5/2019 10:24,female,1,2000, +0.721,0.562,0.57475,0.64690909,1802,11/8/2019 11:22,female,1,2000, +0.72942857,0.74866667,0.574,1.05433333,1802,11/6/2019 11:04,female,1,2000, +0.7432,0.7325,0.69033333,0.74754545,1802,11/9/2019 10:30,female,1,2000, +0.68236364,0.59353333,0.67675,0.8374,1802,11/7/2019 15:48,female,1,2000, +0.77071429,0.909,1.05455556,1.09,1802,11/4/2019 7:38,female,1,2000, +0.79177778,0.94633333,0.789,1.01871429,1803,11/7/2019 10:51,male,1,2000, +1.1108,1.0712,1.36655556,1.6695,1803,11/4/2019 7:03,male,1,2000, +1.013125,0.74688889,0.8783,0.969,1803,11/8/2019 7:55,male,1,2000, +0.99255556,0.758,0.77942857,1.1285,1803,11/5/2019 9:59,male,1,2000, +1.11271429,1.039125,1.4904,1.2242,1803,11/9/2019 22:53,male,1,2000, +0.83466667,0.8201,0.902,0.91,1803,11/6/2019 8:31,male,1,2000, +0.890625,1.00671429,1.19433333,1.20828571,1803,11/10/2019 6:45,male,1,2000, +0.97,0.96666667,0.72054545,1.00157143,1804,11/4/2019 7:10,male,1,2000, +0.71555556,0.86166667,0.6315,0.96111111,1804,11/8/2019 17:04,male,1,2000, +0.6124,0.71083333,0.75422222,0.69658333,1804,11/5/2019 7:12,male,1,2000, +0.60485714,0.806375,0.67138462,0.78314286,1804,11/9/2019 7:10,male,1,2000, +0.60708333,0.949,0.68376923,0.72190909,1804,11/6/2019 7:13,male,1,2000, +0.57735714,0.62607692,0.6742,0.60490909,1804,11/10/2019 7:16,male,1,2000, +0.567875,0.67841667,0.6476875,0.6862,1804,11/7/2019 7:10,male,1,2000, +0.7427,0.61577778,0.59207692,0.62378571,1805,11/5/2019 7:57,male,1,2000,3 +0.59528571,0.47417647,0.57221429,0.578,1805,11/9/2019 8:06,male,1,2000,3 +0.554,0.64,0.6935,0.54633333,1805,11/6/2019 8:46,male,1,2000,3 +0.55015385,0.533,0.58481818,0.62615385,1805,11/11/2019 10:25,male,1,2000,3 +0.67288889,0.574,0.62629412,0.69046154,1805,11/7/2019 7:44,male,1,2000,3 +0.71041667,0.62841667,0.6628,0.56141667,1805,11/8/2019 7:59,male,1,2000,3 +0.7208,0.538,0.60733333,0.709,1805,11/4/2019 8:03,male,1,2000,3 +0.5942,0.63023077,0.75166667,0.60373333,1806,11/6/2019 7:33,female,1,2001,4 +0.54592308,0.59342857,0.61157895,0.51938462,1806,11/9/2019 10:54,female,1,2001,4 +0.65890909,0.59723077,0.806875,0.665,1806,11/7/2019 9:28,female,1,2001,4 +0.6703,0.61075,0.6722,0.48054545,1806,11/10/2019 11:15,female,1,2001,4 +0.72458333,0.673125,0.78225,0.6834,1806,11/4/2019 7:51,female,1,2001,4 +0.69025,0.68771429,0.79233333,0.623,1806,11/7/2019 9:29,female,1,2001,4 +0.6508,0.6814,0.793,0.55526667,1806,11/5/2019 9:59,female,1,2001,4 +0.69466667,0.57230769,0.62258333,0.5885,1806,11/8/2019 9:26,female,1,2001,4 +0.52325,0.7674,0.59385714,0.580125,1807,11/6/2019 7:36,male,1,2000, +0.62925,0.68933333,0.6185625,0.60309091,1807,11/10/2019 10:21,male,1,2000, +0.72614286,0.77008333,0.63053846,0.55023077,1807,11/7/2019 8:23,male,1,2000, +0.69209091,0.88325,0.724,0.58045455,1807,11/4/2019 7:55,male,1,2000, +0.50123077,0.63738462,0.7625,0.67281818,1807,11/8/2019 9:59,male,1,2000, +0.57123529,0.71781818,0.57784615,0.62328571,1807,11/5/2019 7:37,male,1,2000, +0.536,0.83933333,0.569875,0.53185714,1807,11/9/2019 11:32,male,1,2000, +0.68075,0.69272727,0.6238,0.65,1808,11/7/2019 7:31,male,1,2000, +1.08183333,0.89454545,0.7947,0.659625,1808,11/4/2019 7:55,male,1,2000, +0.67709091,0.674,0.681,0.615,1808,11/8/2019 10:37,male,1,2000, +0.96633333,0.9112,1.421,0.858375,1808,11/5/2019 7:41,male,1,2000, +1.04416667,0.67145455,0.82536364,0.6641,1808,11/9/2019 18:04,male,1,2000, +0.686,0.873,0.80957143,0.5935,1808,11/6/2019 7:31,male,1,2000, +0.682375,0.7721,0.64266667,0.76881818,1808,11/10/2019 9:24,male,1,2000, +0.92014286,0.792,0.94355556,1.1028,1809,11/4/2019 8:08,female,1,2000, +0.9736,0.73625,0.84433333,0.69816667,1809,11/8/2019 7:45,female,1,2000, +0.96883333,0.78777778,1.209,0.85714286,1809,11/5/2019 10:42,female,1,2000, +0.89954545,0.73118182,0.957,1.117375,1809,11/6/2019 7:24,female,1,2000, +1.18083333,0.82309091,1.029625,0.77214286,1809,11/7/2019 18:28,female,1,2000, +0.9232,0.83116667,0.75709091,0.80935714,1810,11/4/2019 8:16,male,1,2001, +0.99566667,0.683,0.65983333,0.6825,1810,11/5/2019 10:07,male,1,2001, +0.574,0.55006667,0.6976,0.6555,1811,11/5/2019 7:17,male,1,2001, +0.592,0.56453333,0.65185714,0.553,1811,11/9/2019 7:19,male,1,2001, +0.56181818,0.70944444,0.72,0.589,1811,11/6/2019 7:02,male,1,2001, +0.569,0.60026667,0.5958,0.57541667,1811,11/10/2019 11:08,male,1,2001, +0.55566667,0.745,0.69,0.71338462,1811,11/7/2019 7:32,male,1,2001, +0.49886667,0.57723077,0.5684375,0.52836364,1811,12/16/2019 17:54,male,1,2001, +0.72733333,0.73377778,0.66942857,0.7268,1811,11/4/2019 8:27,male,1,2001, +0.6951,0.81263636,0.67744444,0.72527273,1811,11/8/2019 7:19,male,1,2001, +0.5655,0.61215385,0.74442857,0.665,1812,11/5/2019 8:07,female,1,2001, +0.50805882,0.69275,0.64175,0.57022222,1812,11/9/2019 8:55,female,1,2001, +0.62073333,0.62875,0.60527273,0.57636364,1812,11/10/2019 9:56,female,1,2001, +0.61822222,0.5568,0.59666667,0.56553333,1812,11/6/2019 7:37,female,1,2001, +0.67122222,0.6391875,0.50576471,0.62775,1812,11/7/2019 8:25,female,1,2001, +0.57227778,0.65764706,0.6225,0.57683333,1812,11/4/2019 8:39,female,1,2001, +0.60658333,0.6683,0.6147,0.65071429,1812,11/8/2019 8:46,female,1,2001, +0.71166667,0.717,0.81833333,0.63,1813,11/4/2019 9:13,female,1,2000, +0.58721429,0.79344444,0.76366667,0.70181818,1813,11/5/2019 11:40,female,1,2000, +0.6854,0.7564,0.92666667,0.64918182,1814,11/4/2019 9:12,female,1,2000, +0.735,0.71981818,0.6585,0.52623077,1814,11/5/2019 11:07,female,1,2000, +0.88088889,0.5369,0.614,0.61863636,1814,11/5/2019 11:08,female,1,2000, +0.59233333,0.9435,0.71733333,0.746,1816,11/6/2019 8:34,male,1,2000, +0.5755,0.6315,0.635,0.52975,1816,11/7/2019 8:36,male,1,2000, +0.63488889,0.61909091,0.71125,0.566125,1816,11/9/2019 7:49,male,1,2000, +0.573,0.834,0.724,0.91,1816,11/4/2019 10:21,male,1,2000, +0.76238462,0.69590909,0.6865,0.752,1816,11/10/2019 13:49,male,1,2000, +0.7325,0.61411111,0.771,0.523,1817,11/4/2019 10:36,male,1,2000,3 +0.65254545,0.53615,0.688875,0.8,1817,11/8/2019 8:36,male,1,2000,3 +0.66018182,0.92428571,0.60815385,0.91155556,1817,11/5/2019 8:03,male,1,2000,3 +0.57282353,0.6355,0.867875,0.863875,1817,11/9/2019 7:47,male,1,2000,3 +0.667375,0.60983333,0.7701,0.73561538,1817,11/6/2019 8:40,male,1,2000,3 +0.53933333,0.53207692,0.63007692,0.7180625,1817,11/10/2019 21:14,male,1,2000,3 +0.64335714,0.59838462,0.7767,0.59155556,1817,11/7/2019 8:38,male,1,2000,3 +0.5209,0.5223,0.59516667,0.46566667,1818,11/5/2019 8:21,male,1,2000, +0.531,0.524375,0.54594444,0.5304,1818,11/9/2019 8:22,male,1,2000, +0.65561538,0.51221429,0.58675,0.54494118,1818,11/6/2019 10:49,male,1,2000, +0.48742857,0.45492857,0.501,0.555,1818,11/10/2019 17:44,male,1,2000, +0.54526667,0.5807,0.4966875,0.5009375,1818,11/7/2019 10:20,male,1,2000, +0.57505882,0.52466667,0.64108333,0.59211111,1818,11/4/2019 10:50,male,1,2000, +0.50890476,0.52807143,0.60327273,0.602875,1818,11/8/2019 8:55,male,1,2000, +0.98888889,0.77372727,0.97728571,0.891,1819,11/4/2019 12:07,female,1,2001, +0.64133333,0.55327273,0.6763,0.56755556,1820,11/6/2019 12:09,female,1,2000,3 +1.141,0.7835,0.87666667,0.821,1820,11/10/2019 12:48,female,1,2000,3 +0.586,0.676875,0.6045,0.53383333,1820,11/6/2019 12:16,female,1,2000,3 +0.64692857,0.6547,0.623,0.5609,1820,11/7/2019 16:26,female,1,2000,3 +0.61825,0.71666667,0.5488,0.5406,1820,11/6/2019 12:08,female,1,2000,3 +0.71022222,0.7165,0.781625,0.63477778,1820,11/8/2019 14:59,female,1,2000,3 +0.70266667,0.91785714,1.13828571,1.011,1821,11/7/2019 16:51,female,1,2000, +0.65930769,0.78914286,0.65516667,0.81122222,1821,11/10/2019 16:48,female,1,2000, +1.02566667,0.90771429,0.74777778,0.7055,1821,11/4/2019 15:10,female,1,2000, +0.77525,0.92433333,0.6515,0.708,1821,11/8/2019 16:33,female,1,2000, +0.81008333,0.9699,0.953125,0.76766667,1821,11/5/2019 14:41,female,1,2000, +0.77525,0.92433333,0.6515,0.708,1821,11/8/2019 16:33,female,1,2000, +0.75011111,0.85890909,0.79971429,0.8016,1821,11/6/2019 11:21,female,1,2000, +0.70773333,0.9004,0.52091667,0.7592,1821,11/10/2019 15:57,female,1,2000, +0.6444,0.6261875,0.669,0.6787,1822,11/8/2019 16:59,male,1,1999, +0.97555556,0.9698,0.720625,0.75021429,1822,11/4/2019 17:03,male,1,1999, +0.6975,0.5505625,0.919,0.52408333,1822,11/10/2019 14:26,male,1,1999, +0.73615385,0.68236364,0.837375,0.62966667,1822,11/6/2019 16:26,male,1,1999, +0.70071429,0.6607,0.9535,0.63811111,1822,11/10/2019 17:33,male,1,1999, +0.64792308,0.64263636,0.66416667,0.57363636,1822,11/7/2019 16:12,male,1,1999, +1.057,0.892375,1.12972727,0.83733333,1823,11/5/2019 22:20,female,1,2000, +0.7318,0.738875,0.897,1.104,1823,11/10/2019 18:25,female,1,2000, +0.70128571,0.703,0.93433333,0.68009091,1823,11/6/2019 13:41,female,1,2000, +0.7795,1.0472,0.85883333,1.155,1823,11/10/2019 18:58,female,1,2000, +0.883,1.15,0.92711111,0.82754545,1823,11/7/2019 16:35,female,1,2000, +0.78554545,0.6643,0.933,1.005875,1823,11/4/2019 17:35,female,1,2000, +0.73483333,0.68388889,0.98257143,1.16133333,1823,11/8/2019 9:09,female,1,2000, +0.89483333,0.66092857,0.72975,0.66264286,1824,11/4/2019 20:12,male,1,2000, +0.62608333,0.57181818,0.5226875,0.57530769,1824,11/4/2019 20:57,male,1,2000, +0.766,0.54164706,0.68455556,0.839375,1824,11/4/2019 20:22,male,1,2000, +0.7319,0.64471429,0.9675,0.9975,1824,11/4/2019 19:52,male,1,2000, +0.889625,0.56044444,0.735,0.84081818,1824,11/4/2019 20:34,male,1,2000, +0.68207143,0.53691667,0.7754,0.828,1824,11/4/2019 20:03,male,1,2000, +0.6709,0.57586667,0.70342857,0.5889375,1824,11/4/2019 20:45,male,1,2000, +0.63675,0.7686,1.05216667,1.247875,1825,11/4/2019 19:56,male,1,2000, +0.77125,0.76877778,0.953625,0.94011111,1825,11/8/2019 18:44,male,1,2000, +0.65891667,0.63957143,0.50166667,0.59390909,1826,11/5/2019 8:47,male,1,2000, +0.58390909,0.57207692,0.6465,0.50946154,1826,11/12/2019 0:36,male,1,2000, +0.6825,0.59536364,0.87333333,0.54983333,1826,11/7/2019 8:39,male,1,2000, +0.639,0.8345,0.75781818,0.653,1826,11/9/2019 8:27,male,1,2000, +0.55238462,0.6336,0.64166667,0.79436364,1826,11/4/2019 19:50,male,1,2000, +0.598125,0.59958333,0.63635294,0.48242857,1826,11/11/2019 3:02,male,1,2000, +0.509,0.65,0.51971429,0.55371429,1827,11/4/2019 19:51,male,1,2000, +0.563875,0.507,0.5309,0.53028571,1827,11/6/2019 1:08,male,1,2000, +0.704,0.586,0.79375,0.64709091,1827,11/7/2019 0:11,male,1,2000, +0.65557143,0.66472727,0.66436364,0.68875,1829,11/4/2019 20:11,male,1,2000, +0.70525,1.11966667,0.619,0.80884615,1830,11/11/2019 3:31,female,1,2000, +0.56166667,0.65728571,0.92781818,0.6492,1830,11/4/2019 20:44,female,1,2000, +0.78341667,0.788375,0.69854545,0.58745455,1830,11/11/2019 3:36,female,1,2000, +0.92685714,0.799,0.81075,0.55757143,1830,11/11/2019 2:44,female,1,2000, +0.58627273,0.74442857,0.54964286,0.59685714,1830,11/11/2019 3:42,female,1,2000, +0.726,1.066,0.645,0.61,1830,11/11/2019 3:26,female,1,2000, +0.5642,0.814,0.6715,0.47044444,1830,11/11/2019 3:53,female,1,2000, +1.271,0.5906,0.710375,0.608375,1831,11/4/2019 21:17,male,1,2000, +0.59873333,0.62146154,0.589,0.57046154,1832,11/7/2019 7:29,male,1,1997, +0.5488,0.51375,0.5078,0.56266667,1832,11/4/2019 21:33,male,1,1997, +0.70444444,0.5338125,0.6175,0.84061538,1832,11/8/2019 9:12,male,1,1997, +0.64690909,0.663,0.6454,0.7968,1832,11/5/2019 8:15,male,1,1997, +0.753,0.724,0.7588,0.976,1832,11/9/2019 7:25,male,1,1997, +0.6225,0.7195,0.589625,0.64084211,1832,11/6/2019 7:38,male,1,1997, +0.71555556,0.61557143,0.66635714,0.74976923,1832,11/10/2019 23:35,male,1,1997, +0.73928571,0.7678,0.82875,0.77875,1834,11/5/2019 18:53,female,1,2000, +0.588375,0.734,0.68876923,0.73307143,1834,11/5/2019 19:14,female,1,2000, +0.6354,0.76353846,0.719625,0.927,1835,11/7/2019 20:52,male,1,2000, +0.6864,0.67228571,0.76528571,0.881875,1835,11/8/2019 22:02,male,1,2000, +0.59433333,0.67908333,0.66207692,0.83855556,1835,11/4/2019 21:52,male,1,2000, +0.72990909,0.6628,0.853,0.80788889,1835,11/9/2019 18:05,male,1,2000, +0.51164706,0.77428571,0.56944444,0.60818182,1835,11/5/2019 18:12,male,1,2000, +0.671625,0.64241667,0.75272727,0.6965,1835,11/10/2019 19:49,male,1,2000, +0.93557143,1.0075,1.07625,0.96427273,1836,11/4/2019 22:00,female,1,2001, +0.724,0.80677778,0.8911,0.8332,1836,11/4/2019 22:00,female,1,2001, +0.75842857,0.829,0.8715,0.884625,1836,11/5/2019 18:01,female,1,2001, +0.67653846,0.82655556,0.691875,1.06071429,1836,11/6/2019 18:12,female,1,2001, +0.804,0.669,0.549625,0.55742857,1837,11/4/2019 22:08,male,1,2000, +0.54,0.46233333,0.48041176,0.51838889,1837,11/8/2019 19:53,male,1,2000, +0.56946154,0.55654545,0.51942857,0.58833333,1837,11/5/2019 9:01,male,1,2000, +0.54481818,0.57630769,0.49792857,0.46542105,1837,11/9/2019 21:46,male,1,2000, +0.5813,0.6738,0.66371429,0.57621429,1837,11/6/2019 7:09,male,1,2000, +0.57191667,0.51175,0.55442857,0.51276923,1837,11/10/2019 10:27,male,1,2000, +0.60053846,0.56646154,0.5365,0.64136364,1837,11/7/2019 7:40,male,1,2000, +0.53528571,0.50364286,0.53247059,0.88285714,1838,11/4/2019 22:16,male,1,2000, +0.57415385,0.52081818,0.63242857,0.56166667,1838,11/4/2019 22:15,male,1,2000, +0.677,0.68125,0.5996,0.62430769,1839,11/4/2019 22:45,male,1,2000, +0.8218,0.6974,0.7236,0.9795,1840,11/4/2019 22:50,male,1,2000, +0.95171429,0.79142857,0.857,0.97377778,1841,11/5/2019 18:27,female,1,2000, +0.74923077,0.79116667,0.72708333,0.95528571,1841,11/4/2019 23:01,female,1,2000, +0.6265,0.69033333,0.5678,1.3275,1842,11/4/2019 23:05,male,1,2000, +0.82075,0.66083333,0.91325,1.22,1843,11/6/2019 14:22,male,1,2000, +0.756,0.68225,0.78055556,0.92214286,1843,11/10/2019 17:10,male,1,2000, +0.91383333,0.72957143,0.8015,0.92992308,1843,11/8/2019 19:22,male,1,2000, +1.0235,0.76028571,0.85663636,1.1128,1843,11/4/2019 23:22,male,1,2000, +0.7696,0.67090909,0.83457143,0.8216,1843,11/8/2019 19:31,male,1,2000, +0.82111111,0.85955556,0.77715385,0.66585714,1843,11/6/2019 14:09,male,1,2000, +1.002,0.631,0.88716667,1.0403,1843,11/10/2019 17:00,male,1,2000, +0.57322222,0.5292,0.64571429,0.59142857,1844,11/8/2019 18:48,male,0,2001, +0.57266667,0.610125,0.63235714,0.61866667,1844,11/8/2019 23:46,male,0,2001, +0.5455,0.55911111,0.56975,0.7595,1844,11/4/2019 23:45,male,0,2001, +0.654,0.61715385,0.55053846,0.5843125,1844,11/11/2019 2:49,male,0,2001, +0.64811111,0.587625,0.62533333,0.59083333,1844,11/5/2019 23:38,male,0,2001, +0.57641667,0.509,0.5263,0.572,1844,11/11/2019 2:49,male,0,2001, +0.63542857,0.56853846,0.59657143,0.79041667,1844,11/8/2019 0:07,male,0,2001, +0.643,0.77345455,0.59492857,0.60625,1845,11/5/2019 0:16,female,1,2000, +0.52571429,0.59172727,0.51786667,0.64069231,1845,11/9/2019 11:58,female,1,2000, +0.62192857,0.6372,0.65578571,0.51427273,1845,11/6/2019 8:04,female,1,2000, +0.4825,0.5233,0.60271429,0.5934,1845,11/10/2019 12:48,female,1,2000, +0.49176471,0.67166667,0.68257143,0.51853333,1845,11/7/2019 20:05,female,1,2000, +0.5604,0.65806667,0.57176923,0.52130769,1845,11/8/2019 14:20,female,1,2000, +0.54346667,0.95157143,0.60535714,0.50961538,1846,11/6/2019 9:16,male,1,2000, +0.63125,0.645375,0.71928571,0.73669231,1846,11/10/2019 14:40,male,1,2000, +0.69511111,0.86781818,0.676,0.819375,1846,11/5/2019 0:26,male,1,2000, +0.6851,0.8421,0.65118182,0.848,1846,11/5/2019 7:44,male,1,2000, +0.86142857,0.8705,0.78416667,0.88688889,1847,11/6/2019 0:11,male,1,2000, +0.67571429,0.94475,0.6495625,0.71555556,1847,11/7/2019 0:41,male,1,2000, +0.535,0.56235714,0.60746667,0.68254545,1848,11/6/2019 10:53,male,1,2000, +0.54627273,0.70316667,0.6845,0.65633333,1849,11/8/2019 22:33,female,1,2000,2 +0.71211111,0.8035,0.497,0.8545,1849,11/5/2019 9:22,female,1,2000,2 +0.59422222,0.79854545,0.7825,0.6117,1849,11/9/2019 14:53,female,1,2000,2 +0.57653846,0.62314286,0.74966667,0.536375,1849,11/6/2019 8:21,female,1,2000,2 +0.7645,0.86218182,0.9946,0.8548,1849,11/10/2019 12:30,female,1,2000,2 +0.4742,0.65883333,0.666875,0.62877778,1849,11/7/2019 15:38,female,1,2000,2 +1.3945,0.94275,1.277,1.1838,1851,11/5/2019 10:36,female,1,2000, +1.04133333,0.74511111,0.8255,0.86666667,1851,11/10/2019 13:20,female,1,2000, +1.0312,0.88155556,0.97455556,1.379,1851,11/6/2019 21:52,female,1,2000, +0.817,0.74490909,0.5984,0.9107,1851,11/8/2019 10:24,female,1,2000, +0.94022222,0.7978,0.96857143,0.90471429,1851,11/5/2019 10:16,female,1,2000, +1.2325,1.0415,0.717625,1.16775,1851,11/9/2019 11:56,female,1,2000, +0.67022222,0.705,0.72116667,0.7515,1852,11/10/2019 12:33,female,1,2000, +0.795,0.81607692,0.686125,0.87658333,1852,11/5/2019 11:12,female,1,2000, +0.7291,0.80433333,0.71016667,0.892625,1852,11/10/2019 12:46,female,1,2000, +0.68325,0.7408,0.84455556,0.70976923,1852,11/5/2019 11:26,female,1,2000, +0.7735,0.75746154,0.813,0.72333333,1852,11/10/2019 12:56,female,1,2000, +0.76072727,0.86125,0.67955556,0.94166667,1852,11/10/2019 12:19,female,1,2000, +0.6099,0.79416667,0.75781818,0.77442857,1852,11/10/2019 13:16,female,1,2000, +1.112375,0.693625,0.81444444,1.01625,1853,11/5/2019 18:04,female,1,2000, +0.76218182,0.70542857,0.756625,0.69114286,1853,11/11/2019 11:31,female,1,2000, +0.715875,0.71778571,0.83275,0.7389,1853,11/8/2019 9:32,female,1,2000, +0.8592,0.77866667,0.83833333,0.67177778,1853,11/11/2019 11:48,female,1,2000, +1.2522,0.92733333,1.16166667,1.27042857,1853,11/8/2019 9:32,female,1,2000, +1.8375,1.05416667,1.22,0.816,1853,11/8/2019 9:33,female,1,2000, +1.34685714,0.73711111,0.68133333,0.686375,1854,11/7/2019 14:56,male,1,2000, +0.82666667,0.73757143,0.6346,0.75554545,1854,11/8/2019 17:46,male,1,2000, +0.88077778,0.74366667,0.93785714,0.71111111,1854,11/9/2019 11:55,male,1,2000, +0.87675,0.711,0.77985714,0.703125,1854,11/5/2019 20:05,male,1,2000, +0.74925,0.73033333,0.749,0.78308333,1854,11/6/2019 22:51,male,1,2000, +0.60564286,0.64738462,0.60690909,0.91414286,1854,11/10/2019 12:21,male,1,2000, +2.5615,1.47433333,1.239,2.322,1855,11/5/2019 20:21,female,1,2000, +2.01933333,1.8185,1.203,1.3082,1855,11/10/2019 10:52,female,1,2000, +1.377,1.025,1.3418,1.441,1855,11/7/2019 18:20,female,1,2000, +1.07033333,1.19666667,1.283875,1.02533333,1855,11/10/2019 10:53,female,1,2000, +1.37966667,0.94975,0.9545,1.13725,1855,11/10/2019 10:38,female,1,2000, +1.1995,1.15,1.01928571,1.2124,1855,11/10/2019 10:55,female,1,2000, +1.051,1.24025,1.21,1.3295,1855,11/10/2019 10:50,female,1,2000, +0.96125,0.644,0.764,0.808125,1856,11/6/2019 10:23,male,1,2000, +0.7179,1.49475,0.65116667,0.8785,1856,11/10/2019 13:52,male,1,2000, +0.835625,0.76892857,0.79514286,0.935,1856,11/7/2019 8:28,male,1,2000, +0.93,1.27088889,1.03366667,0.88645455,1856,11/10/2019 13:54,male,1,2000, +0.79263636,0.85366667,0.7237,0.88342857,1856,11/10/2019 12:34,male,1,2000, +0.92466667,1.0081,0.80075,1.12533333,1856,11/10/2019 13:56,male,1,2000, +1.24216667,0.8516,0.7812,2.08575,1856,11/5/2019 22:22,male,1,2000, +0.76871429,0.75725,0.80054545,1.06644444,1856,11/10/2019 12:55,male,1,2000, +2.392,1.4165,3.212,1.1105,1857,11/5/2019 23:13,male,1,1998, +0.567,0.54685714,0.53176923,0.57263636,1859,11/6/2019 8:20,male,1,2000, +0.622625,0.68733333,0.73342857,0.75016667,1859,11/10/2019 13:28,male,1,2000, +0.56285714,0.60569231,0.93672727,0.7136,1860,11/6/2019 13:28,male,0,2000, +0.74016667,0.55333333,0.986,0.72375,1860,11/6/2019 9:07,male,0,2000, +1.01533333,0.5435,1.605,0.573,1860,11/6/2019 13:27,male,0,2000, +0.63255556,0.73016667,0.60430769,0.65372727,1861,11/10/2019 13:37,male,1,2000, +0.56246154,0.6623,0.62407692,0.64916667,1861,11/6/2019 10:20,male,1,2000, +0.5759,0.725,0.60316667,0.655375,1861,11/10/2019 13:38,male,1,2000, +0.5964,0.636,0.825,0.596,1861,11/7/2019 8:34,male,1,2000, +0.59858333,0.6602,0.55605882,0.538,1861,11/8/2019 12:48,male,1,2000, +0.58475,0.5565,0.55733333,0.586,1863,11/6/2019 13:53,male,1,1995, +0.677,0.686,0.85057143,0.61,1863,11/10/2019 16:40,male,1,1995, +0.79341667,0.76875,0.80476923,0.82625,1863,11/10/2019 16:05,male,1,1995, +1.20383333,1.332,0.8721,1.03457143,1863,11/6/2019 12:44,male,1,1995, +0.7085,0.6455,0.80176923,1.009625,1863,11/10/2019 16:17,male,1,1995, +0.72592308,0.7236,1.0345,0.94477778,1863,11/6/2019 13:03,male,1,1995, +0.74708333,0.6858,0.8365,0.7615,1863,11/10/2019 16:28,male,1,1995, +0.60881818,0.579,0.77645455,0.87471429,1865,11/9/2019 10:44,male,1,2000, +0.80690909,0.95266667,0.86114286,0.96116667,1865,11/6/2019 17:06,male,1,2000, +0.97325,0.64614286,0.68625,0.822,1865,11/9/2019 10:57,male,1,2000, +0.8742,0.6305,0.89266667,0.93111111,1865,11/7/2019 15:45,male,1,2000, +0.887625,0.57486667,0.7258,0.76288889,1865,11/11/2019 17:26,male,1,2000, +0.72655556,0.66673333,0.6125,0.70941667,1865,11/7/2019 23:08,male,1,2000, +0.64413333,0.6083,0.69657143,0.596,1865,11/11/2019 17:41,male,1,2000, +0.69791667,0.65130769,0.90044444,0.8315,1866,11/10/2019 22:59,female,1,2000, +0.77425,0.908,0.612,0.83366667,1866,11/6/2019 18:11,female,1,2000, +0.7315,0.63357143,0.75577778,0.82209091,1866,11/10/2019 23:00,female,1,2000, +0.87825,0.94442857,0.74314286,0.657,1866,11/10/2019 22:55,female,1,2000, +0.65933333,0.9414,0.88825,0.7434,1866,11/10/2019 23:01,female,1,2000, +0.7642,0.98942857,0.86271429,0.77327273,1866,11/10/2019 22:58,female,1,2000, +0.92785714,0.9017,1.105875,1.0252,1866,11/10/2019 22:59,female,1,2000, +0.49085714,0.46011765,0.49475,0.4504,1870,11/7/2019 8:19,male,1,2000, +0.9288,0.87571429,1.19766667,0.86457143,1887,11/9/2019 17:32,male,1,2001, +0.74475,0.55166667,0.6765,0.6255,1887,11/9/2019 17:36,male,1,2001, +0.67177778,0.6798,0.913625,0.65507143,1887,11/9/2019 17:33,male,1,2001, +0.5454,0.60966667,0.59306667,0.74771429,1887,11/9/2019 17:38,male,1,2001, +0.65733333,0.56427273,0.62272222,0.848,1887,11/9/2019 17:34,male,1,2001, +0.59085714,0.616125,0.60082353,0.625,1887,11/9/2019 17:40,male,1,2001, +0.66954545,0.61033333,0.6725,0.75627273,1887,11/9/2019 17:35,male,1,2001, +0.7075,0.65071429,0.61663636,0.64246667,1887,11/9/2019 17:47,male,1,2001, +1.51785714,1.207,1.37566667,1.13371429,1888,11/7/2019 17:35,female,1,1999, +0.65207143,0.79671429,0.6893,0.62425,1888,11/10/2019 15:14,female,1,1999, +0.96833333,1.451875,1.375,1.07088889,1888,11/7/2019 18:43,female,1,1999, +0.67688889,0.62385714,0.58083333,0.66071429,1888,11/10/2019 15:15,female,1,1999, +0.83392308,0.92,1.1614,0.8788,1888,11/7/2019 18:45,female,1,1999, +0.67181818,0.62,0.65486667,0.54292308,1888,11/10/2019 15:16,female,1,1999, +0.76257143,0.929,0.84177778,0.75744444,1888,11/10/2019 15:12,female,1,1999, +0.727,0.851,0.861,0.8246,1889,11/7/2019 15:25,female,1,2001, +0.6914,0.871,0.69592308,0.708,1889,11/10/2019 15:05,female,1,2001, +0.75118182,0.8762,0.81311111,0.847,1889,11/7/2019 15:38,female,1,2001, +0.77342857,0.7973,0.86911111,0.78845455,1889,11/10/2019 15:22,female,1,2001, +0.631375,0.82488889,0.7358,0.8275,1889,11/8/2019 22:10,female,1,2001, +0.72085714,0.74825,0.75858333,0.85175,1889,11/10/2019 21:04,female,1,2001, +0.8019,0.7831,0.78233333,0.9063,1889,11/7/2019 15:14,female,1,2001, +0.733,0.73544444,0.88228571,0.8313,1889,11/10/2019 14:56,female,1,2001, +0.53269231,0.504,0.51184615,0.50570588,1890,11/8/2019 7:47,male,1,2000, +0.7469,0.91855556,0.6776,0.66763636,1891,11/8/2019 11:14,female,1,2000, +0.6775,0.73108333,0.89136364,0.6922,1891,11/8/2019 13:00,female,1,2000, +0.67384615,0.86933333,0.648,0.49035714,1891,11/8/2019 11:29,female,1,2000, +0.60976923,1.07744444,0.726375,0.61266667,1891,11/8/2019 11:44,female,1,2000, +0.97183333,0.81735714,0.87328571,0.6027,1891,11/8/2019 12:58,female,1,2000, +0.909875,0.832,0.79792857,1.11085714,1892,11/9/2019 15:28,female,1,2000, +0.89091667,0.871,0.78633333,0.9061,1892,11/8/2019 16:03,female,1,2000, +1.01785714,0.92733333,0.95125,0.749,1892,11/10/2019 19:14,female,1,2000, +0.979,0.76246154,0.75511111,1.07,1892,11/8/2019 16:20,female,1,2000, +0.72571429,0.88345455,1.02225,0.95636364,1892,11/10/2019 19:38,female,1,2000, +0.956375,0.7473,0.8555,0.79022222,1892,11/8/2019 16:28,female,1,2000, +0.88888889,1.26428571,0.733625,1.3136,1892,11/10/2019 19:38,female,1,2000, +0.8536,0.84933333,0.75071429,0.918,1893,11/8/2019 16:58,male,1,2000, +0.886,0.8225,0.6839375,1.01616667,1894,11/8/2019 23:18,male,1,2000, +0.6368,0.84475,0.68966667,0.82657143,1895,11/9/2019 0:07,male,1,2000, +0.57244444,0.62638462,0.56942857,0.6696,1896,11/9/2019 14:25,female,1,1999, +0.68433333,0.79025,0.706,0.883,1896,11/9/2019 14:34,female,1,1999, +0.75833333,0.756875,0.7407,0.84575,1896,11/9/2019 14:27,female,1,1999, +0.54163158,0.53941667,0.4962,0.54566667,1896,11/9/2019 14:35,female,1,1999, +0.73416667,0.6005,0.68975,0.7394,1896,11/9/2019 14:28,female,1,1999, +0.96742857,0.77025,0.7676,0.9233,1896,11/9/2019 14:22,female,1,1999, +0.7702,0.68733333,0.86988889,0.619375,1896,11/9/2019 14:30,female,1,1999, +0.59333333,0.589,0.6088,0.636,1897,11/9/2019 15:37,male,1,2000, +0.651,0.65755556,0.59030769,0.64292857,1897,11/9/2019 16:33,male,1,2000, +0.6896,0.539375,0.61325,0.6689,1897,11/9/2019 16:28,male,1,2000, +0.5171,0.6042,0.70566667,0.84136364,1897,11/9/2019 16:34,male,1,2000, +0.6605,0.69715385,0.8045,0.69728571,1897,11/9/2019 15:29,male,1,2000, +0.70163636,0.6965,0.56458333,0.75214286,1897,11/9/2019 16:30,male,1,2000, +0.6272,0.656,0.70746667,0.56146154,1897,11/9/2019 15:35,male,1,2000, +0.70736364,0.57630769,0.565375,0.60755556,1897,11/9/2019 16:32,male,1,2000, +0.547125,0.50335714,0.57305882,0.5474375,1898,11/9/2019 21:11,male,1,2000, +0.56606667,0.52282353,0.56155556,0.52621429,1898,11/9/2019 21:53,male,1,2000, +0.51721429,0.53738462,0.58276923,0.52686667,1898,11/9/2019 21:12,male,1,2000, +0.64866667,0.61233333,0.545,0.572125,1898,11/9/2019 20:48,male,1,2000, +0.5465,0.48009091,0.51963158,0.59213333,1898,11/9/2019 21:14,male,1,2000, +0.556,0.58138462,0.5125,0.54966667,1898,11/9/2019 20:58,male,1,2000, +0.50145455,0.497375,0.554625,0.55753846,1898,11/9/2019 21:52,male,1,2000, +0.4555,0.54745455,0.5286,0.6439375,1899,11/9/2019 23:59,male,1,2000, +0.79633333,0.98711111,0.68525,0.876,1901,11/10/2019 11:02,male,1,2001, +0.24096552,0.34416667,0.21386364,0.15095238,1901,11/10/2019 11:09,male,1,2001, +0.34211111,0.607,0.33542105,0.24009091,1901,11/10/2019 11:04,male,1,2001, +0.64107692,0.795625,0.752,0.72658333,1901,11/10/2019 10:56,male,1,2001, +0.25727586,0.33509091,0.26878571,0.12971429,1901,11/10/2019 11:06,male,1,2001, +0.48909091,0.60929412,0.85766667,0.74233333,1901,11/10/2019 11:01,male,1,2001, +0.34415,0.40025,0.2686,0.159,1901,11/10/2019 11:07,male,1,2001, +0.6133,0.52841667,0.5928,0.64269231,1902,11/10/2019 11:14,male,1,2000, +0.52878571,0.62038462,0.695,0.64966667,1904,11/10/2019 15:24,male,1,2000, +0.76133333,1.00466667,0.99533333,0.58185714,1905,11/11/2019 0:25,female,1,2000, +0.479,1.03114286,0.45473684,0.4589375,1905,11/11/2019 0:31,female,1,2000, +0.65433333,0.9055,0.89333333,0.68691667,1905,11/11/2019 0:26,female,1,2000, +0.49461111,0.45395,0.23476471,0.40488889,1905,11/11/2019 0:32,female,1,2000, +0.738,0.7874,0.89914286,0.56958333,1905,11/11/2019 0:28,female,1,2000, +0.65991667,1.0728,0.684,0.49283333,1905,11/11/2019 0:29,female,1,2000, +0.908125,0.87933333,1.6698,1.2194,1905,11/11/2019 0:23,female,1,2000, +0.84933333,0.73655556,0.7865,0.8526,1906,11/10/2019 17:22,male,1,2000, +0.69707692,0.60146154,0.72725,0.6646,1906,11/10/2019 17:33,male,1,2000, +0.72255556,0.657625,0.59875,0.5645,1906,11/10/2019 17:25,male,1,2000, +0.73728571,0.811875,0.94925,0.668625,1906,11/10/2019 17:11,male,1,2000, +0.9348,1.0382,0.60692308,0.746,1906,11/10/2019 17:26,male,1,2000, +0.81569231,0.73685714,0.67125,0.721375,1906,11/10/2019 17:20,male,1,2000, +0.81814286,0.736,0.606,0.75985714,1906,11/10/2019 17:31,male,1,2000, +0.8155,0.74041667,0.7934,0.68523077,1908,11/10/2019 17:16,male,1,2000, +0.83311111,0.53155556,0.84933333,0.6018,1908,11/10/2019 17:36,male,1,2000, +0.6863,0.83966667,0.93875,0.51527273,1908,11/10/2019 17:49,male,1,2000, +0.66045455,0.8255,0.66627273,0.58766667,1909,11/10/2019 18:50,male,1,2000, +0.5748,0.58357143,0.67157143,0.83138462,1909,11/10/2019 18:55,male,1,2000, +0.5889,0.53221429,0.60658333,0.5594375,1909,11/10/2019 18:57,male,1,2000, +0.55877778,0.50353333,0.7618,0.68771429,1909,11/10/2019 18:59,male,1,2000, +0.59544444,0.63757143,0.8478,0.83078571,1909,11/10/2019 18:43,male,1,2000, +0.636625,0.60888235,0.76155556,0.68972727,1909,11/10/2019 18:47,male,1,2000, +0.66045455,0.8255,0.66627273,0.58766667,1909,11/10/2019 18:50,male,1,2000, +0.5748,0.58357143,0.67157143,0.83138462,1909,11/10/2019 18:55,male,1,2000, +0.5889,0.53221429,0.60658333,0.5594375,1909,11/10/2019 18:57,male,1,2000, +0.55877778,0.50353333,0.7618,0.68771429,1909,11/10/2019 18:59,male,1,2000, +0.636625,0.60888235,0.76155556,0.68972727,1909,11/10/2019 18:47,male,1,2000, +0.66045455,0.8255,0.66627273,0.58766667,1909,11/10/2019 18:50,male,1,2000, +0.57192857,0.54736364,0.74388889,0.78228571,1909,11/10/2019 18:53,male,1,2000, +0.5748,0.58357143,0.67157143,0.83138462,1909,11/10/2019 18:55,male,1,2000, +0.5889,0.53221429,0.60658333,0.5594375,1909,11/10/2019 18:57,male,1,2000, +0.636625,0.60888235,0.76155556,0.68972727,1909,11/10/2019 18:47,male,1,2000, +0.57192857,0.54736364,0.74388889,0.78228571,1909,11/10/2019 18:53,male,1,2000, +0.5889,0.53221429,0.60658333,0.5594375,1909,11/10/2019 18:57,male,1,2000, +0.5889,0.53221429,0.60658333,0.5594375,1909,11/10/2019 18:57,male,1,2000, +0.636625,0.60888235,0.76155556,0.68972727,1909,11/10/2019 18:47,male,1,2000, +0.751,0.5488,0.853,0.636,1913,11/10/2019 19:32,male,1,2000, +0.56835714,0.49807143,0.63122222,0.9321,1913,11/10/2019 19:39,male,1,2000, +0.66644444,0.57666667,0.764,0.78354545,1913,11/10/2019 19:34,male,1,2000, +0.729375,0.61545455,0.827,0.9844,1913,11/10/2019 19:27,male,1,2000, +0.67307692,0.51238889,0.63488889,0.67577778,1913,11/10/2019 19:36,male,1,2000, +0.63030769,0.5573,0.81766667,0.73325,1913,11/10/2019 19:31,male,1,2000, +0.54833333,0.5055,0.67007692,0.58476923,1913,11/10/2019 19:38,male,1,2000, +0.48430769,0.52076923,0.53676471,0.54935714,1921,11/10/2019 19:39,male,1,2000, +0.987,1.14185714,0.890125,0.88863636,1922,11/10/2019 20:30,male,1,2000, +0.60342857,0.70066667,0.5888,0.87376923,1923,11/10/2019 20:43,male,1,2000, +0.645875,0.62625,0.63021429,0.961625,1924,11/10/2019 20:50,male,1,2000, +0.52166667,0.47409091,0.909,0.7696,1925,11/10/2019 20:56,male,1,2000, +0.598,0.70222222,0.67555556,0.893,1926,11/10/2019 21:02,male,1,2000, +0.76866667,1.07054545,0.69785714,0.90228571,1927,11/10/2019 22:50,male,1,2000, +0.68641667,0.664,0.6354,0.62146154,1927,11/10/2019 22:54,male,1,2000, +0.80972727,0.6095,0.65846667,0.65211111,1927,11/10/2019 22:51,male,1,2000, +0.55246154,0.63092857,0.5865,0.60053846,1927,11/10/2019 22:56,male,1,2000, +0.77614286,0.80666667,0.70472727,0.75293333,1927,11/10/2019 22:52,male,1,2000, +0.78672727,0.7291,0.66454545,0.90028571,1927,11/10/2019 22:43,male,1,2000, +0.7646,0.73236364,0.8149,0.67077778,1927,11/10/2019 22:53,male,1,2000, +0.89714286,1.237,0.91457143,0.80966667,1929,11/11/2019 0:28,female,1,2000, +0.5792,0.87792857,0.43817647,0.30278571,1929,11/11/2019 0:33,female,1,2000, +0.7894,0.96307692,0.82642857,0.7234,1929,11/11/2019 0:29,female,1,2000, +0.68916667,0.9235,1.07871429,0.63907692,1929,11/10/2019 23:43,female,1,2000, +0.579625,0.79941667,0.48907143,0.65553846,1929,11/11/2019 0:30,female,1,2000, +0.5782,0.83966667,1.01128571,1.385,1929,11/11/2019 0:25,female,1,2000, +0.63309091,1.041,0.56545455,0.4155,1929,11/11/2019 0:32,female,1,2000, +0.54511111,0.8235,0.69376923,0.713,1931,11/11/2019 1:17,female,1,2000, +0.7458,0.7495,0.68525,0.51961538,1931,11/11/2019 0:41,female,1,2000, +0.65363636,0.61021429,0.794,0.6457,1931,11/11/2019 1:32,female,1,2000, +0.61485714,0.50770588,0.597,0.957,1931,11/11/2019 0:57,female,1,2000, +0.989,1.03,0.949,0.8615,1931,11/11/2019 1:34,female,1,2000, +0.61690909,0.7681,1.0466,1.27425,1931,11/11/2019 1:08,female,1,2000, +0.5965,0.70133333,1.048,0.61709091,1931,11/11/2019 1:35,female,1,2000, +0.7643,1.013875,0.66730769,0.608625,1933,11/11/2019 3:49,female,1,2000, +0.4865,0.726,0.68,0.778,1933,11/11/2019 3:43,female,1,2000, +0.704,0.74092308,1.17725,0.6425,1933,11/11/2019 3:46,female,1,2000, +0.34433333,0.583,0.838,0.96271429,1933,11/11/2019 3:50,female,1,2000, +0.752,0.84666667,0.63475,0.74292308,1933,11/11/2019 3:47,female,1,2000, +0.63066667,0.74157143,0.92816667,0.77516667,1933,11/11/2019 3:51,female,1,2000, +0.825,1.05611111,0.857,0.89,1933,11/11/2019 3:48,female,1,2000, +0.66442857,0.49433333,0.50433333,0.6065,1937,11/11/2019 11:16,male,1,1992, +0.73157143,0.86844444,1.06233333,0.88433333,1937,11/11/2019 11:26,male,1,1992, +0.75211111,0.626875,0.74925,0.7039,1937,11/11/2019 11:35,male,1,1992, +0.545,0.60666667,0.51455556,0.73563636,1937,11/11/2019 11:03,male,1,1992, +0.46178947,0.5983,0.56192857,0.66754545,1937,11/11/2019 11:45,male,1,1992, +0.58455556,0.58458824,0.64641667,0.6882,1938,11/11/2019 20:22,male,1,1996, +0.4826875,0.56623529,0.5966,0.602,1938,11/11/2019 21:32,male,1,1996, +0.55521429,0.667,0.5269,0.775125,1939,11/11/2019 23:37,male,1,2000, +0.61214286,0.8222,0.53675,0.791625,1940,11/19/2019 23:07,male,0,1990, +1.64225,1.4632,1.89233333,2.50175,1943,12/10/2019 12:28,male,1,1976,3 +0.87733333,0.80192308,1.1048,1.08875,1951,12/10/2019 13:23,male,1,2001,4 +1.059,0.93628571,0.9017,0.77444444,1955,12/16/2019 19:04,male,1,2000,2 +0.616,0.56188889,0.60335714,0.5638,1957,12/16/2019 23:18,male,1,2000,3 +0.78,0.949125,0.97871429,0.8375,1958,12/17/2019 0:09,female,1,2000,3 +0.628,0.612,0.66075,0.52888889,1959,12/17/2019 0:12,male,1,2000,3 +0.63366667,0.663375,0.6354,0.75016667,1960,12/17/2019 7:36,male,1,1999,3 +0.6762,0.56194444,0.61890909,0.70323077,1961,12/23/2019 8:27,male,1,2000,4 +2.42083333,1.71866667,1.33475,2.068,1966,1/21/2020 12:02,male,1,1980,3 +1.17033333,1.1205,1.23255556,1.1522,1966,1/21/2020 12:03,male,1,1980,3 +0.64416667,0.656,0.62666667,0.75154545,1968,3/1/2020 15:47,female,1,1997,3 +0.6368,0.71209091,0.80391667,0.83685714,1968,3/1/2020 12:46,female,1,1997,3 +0.57284211,0.71454545,0.7185,0.71577778,1968,3/1/2020 13:01,female,1,1997,3 +0.6413,0.69744444,0.6728,0.98214286,1968,3/1/2020 13:03,female,1,1997,3 +0.64771429,0.6797,0.63025,0.74527273,1968,3/1/2020 13:07,female,1,1997,3 +0.625,0.711125,0.6222,0.73371429,1968,3/1/2020 13:11,female,1,1997,3 +0.551,0.6842,0.60994118,0.71242857,1968,3/1/2020 14:08,female,1,1997,3 +1.01714286,0.900875,0.84825,1.25085714,1968,2/21/2020 15:59,female,1,1997,3 +0.63388889,0.65823077,0.6687,0.789,1968,3/1/2020 14:11,female,1,1997,3 +0.69041667,0.69869231,0.7747,0.9562,1968,3/1/2020 11:32,female,1,1997,3 +0.74472727,0.892,0.81990909,1.03828571,1968,3/1/2020 11:10,female,1,1997,3 +0.6246,0.67085714,0.62722222,0.69973684,1968,3/1/2020 14:15,female,1,1997,3 +0.615625,0.65546154,0.7116,1.03522222,1968,3/1/2020 11:34,female,1,1997,3 +0.665375,0.704,0.665,0.96083333,1968,3/1/2020 11:13,female,1,1997,3 +0.64672727,0.65353846,0.87677778,0.78825,1968,3/1/2020 14:18,female,1,1997,3 +0.7443,0.7923,0.6995,0.81925,1968,3/1/2020 11:39,female,1,1997,3 +0.62206667,0.65754545,0.71066667,0.85175,1968,3/1/2020 11:18,female,1,1997,3 +0.629375,0.66591667,0.67692308,0.65025,1968,3/1/2020 15:40,female,1,1997,3 +0.689375,0.708,0.67763636,0.75383333,1968,3/1/2020 12:37,female,1,1997,3 +0.62875,0.615,0.724,0.64027273,1968,3/1/2020 11:29,female,1,1997,3 +0.67007692,0.77533333,0.64484615,0.7867,1968,3/1/2020 15:42,female,1,1997,3 +0.63523077,0.8174,0.74307143,0.76311111,1968,3/1/2020 12:39,female,1,1997,3 +0.67407143,0.75409091,0.73157143,0.836,1968,3/1/2020 15:45,female,1,1997,3 +0.70471429,0.68333333,0.68021429,0.7126,1968,3/1/2020 12:42,female,1,1997,3 +0.5955,0.6765,0.61738462,0.72125,1968,3/1/2020 15:45,female,1,1997,3 +0.69375,0.66433333,0.78166667,0.75563636,1968,3/1/2020 12:42,female,1,1997,3 +0.59854545,0.72855556,0.66921429,0.6905,1968,3/1/2020 15:48,female,1,1997,3 +0.75355556,0.61891667,0.77736364,0.84275,1968,3/1/2020 12:46,female,1,1997,3 +0.53654545,0.839,0.65192308,0.7,1968,3/1/2020 13:02,female,1,1997,3 +0.60209091,0.59738462,0.73125,0.9014,1968,3/1/2020 13:05,female,1,1997,3 +0.676,0.69935714,0.64858333,0.79014286,1968,3/1/2020 13:08,female,1,1997,3 +0.6062,0.76366667,0.59294737,0.79257143,1968,3/1/2020 13:12,female,1,1997,3 +0.56866667,0.68433333,0.60258333,0.74777778,1968,3/1/2020 14:09,female,1,1997,3 +0.68122222,0.7233,0.89428571,0.9973,1968,3/1/2020 11:07,female,1,1997,3 +0.7107,0.7308,0.7725,0.65084615,1968,3/1/2020 14:12,female,1,1997,3 +0.64766667,0.66966667,0.69154545,0.70977778,1968,3/1/2020 11:33,female,1,1997,3 +0.78733333,0.78,0.7523,1.29925,1968,3/1/2020 11:11,female,1,1997,3 +0.67133333,0.6995,0.81477778,0.7462,1968,3/1/2020 14:16,female,1,1997,3 +0.64018182,0.69007692,0.69266667,0.8545,1968,3/1/2020 11:35,female,1,1997,3 +0.61745455,0.786,0.72875,0.9099,1968,3/1/2020 11:14,female,1,1997,3 +0.57527273,0.63463636,0.6157,0.89381818,1968,3/1/2020 14:19,female,1,1997,3 +0.60983333,0.70278571,0.67055556,0.90436364,1968,3/1/2020 11:39,female,1,1997,3 +0.58069231,0.86125,0.77416667,0.80291667,1968,3/1/2020 11:18,female,1,1997,3 +0.64922222,0.69733333,0.61591667,0.72909091,1968,3/1/2020 15:40,female,1,1997,3 +0.5739,0.66138462,0.79911111,0.74345455,1968,3/1/2020 12:37,female,1,1997,3 +0.64992308,0.72822222,0.71009091,0.7145,1968,3/1/2020 11:31,female,1,1997,3 +0.636,0.6869,0.6932,0.65769231,1968,3/1/2020 15:43,female,1,1997,3 +0.62854545,0.69788889,0.641,0.72984615,1968,3/1/2020 12:40,female,1,1997,3 +0.77554545,0.7149,0.7514,0.83233333,1968,3/1/2020 15:46,female,1,1997,3 +0.63121429,0.6926,0.74,0.772375,1968,3/1/2020 12:43,female,1,1997,3 +0.744625,0.72444444,0.832,0.80466667,1968,3/1/2020 15:49,female,1,1997,3 +0.626125,0.678,0.60633333,0.749375,1968,3/1/2020 12:47,female,1,1997,3 +0.68244444,0.71958333,0.64578571,0.67522222,1968,3/1/2020 13:02,female,1,1997,3 +0.65676923,0.7005,0.643,0.8516,1968,3/1/2020 13:05,female,1,1997,3 +0.66490909,0.73385714,0.67984615,0.8353,1968,3/1/2020 13:08,female,1,1997,3 +0.60227273,0.81566667,0.59764286,0.868,1968,3/1/2020 13:12,female,1,1997,3 +0.91977778,0.7955,0.758,1.127,1968,2/21/2020 11:34,female,1,1997,3 +0.62741667,0.69833333,0.73516667,0.71484615,1968,3/1/2020 14:10,female,1,1997,3 +0.8186,0.7776,0.873,0.70866667,1968,3/1/2020 11:09,female,1,1997,3 +0.55,0.7641,0.59355556,0.631,1968,3/1/2020 14:12,female,1,1997,3 +0.504375,0.66275,0.772375,0.89244444,1968,3/1/2020 11:33,female,1,1997,3 +0.754125,0.73828571,0.8158,0.837,1968,3/1/2020 11:12,female,1,1997,3 +0.74975,0.72171429,0.73258333,0.6994,1968,3/1/2020 14:16,female,1,1997,3 +0.59692308,0.68116667,0.82311111,0.82185714,1968,3/1/2020 11:36,female,1,1997,3 +0.61923077,0.65875,0.86433333,0.96088889,1968,3/1/2020 11:16,female,1,1997,3 +0.63145455,0.676875,0.66383333,0.72053846,1968,3/1/2020 14:19,female,1,1997,3 +0.58555556,0.76376923,0.86733333,0.846125,1968,3/1/2020 11:40,female,1,1997,3 +0.6724,0.72785714,0.66873333,0.87411111,1968,3/1/2020 11:19,female,1,1997,3 +0.81333333,0.826125,0.74416667,0.866625,1968,3/1/2020 15:41,female,1,1997,3 +0.737875,0.69572727,0.692,0.65527273,1968,3/1/2020 12:38,female,1,1997,3 +0.60655556,0.69027273,0.5609,0.65464706,1968,3/1/2020 11:31,female,1,1997,3 +0.61916667,0.6452,0.66107692,1.0249,1968,3/1/2020 15:43,female,1,1997,3 +0.58115385,0.6329,0.741,0.81333333,1968,3/1/2020 12:40,female,1,1997,3 +0.7778,0.81307692,0.96528571,0.74545455,1968,3/1/2020 15:47,female,1,1997,3 +0.61863636,0.6605,0.74718182,0.67323077,1968,3/1/2020 12:45,female,1,1997,3 +0.53675,0.7,0.63169231,0.71007692,1968,3/1/2020 13:00,female,1,1997,3 +0.57871429,0.65342857,0.6562,0.68078571,1968,3/1/2020 13:03,female,1,1997,3 +0.59933333,0.69466667,0.67053846,0.887375,1968,3/1/2020 13:07,female,1,1997,3 +0.61378571,0.78928571,0.77077778,0.77772727,1968,3/1/2020 13:09,female,1,1997,3 +0.66263636,0.6998,0.67228571,0.81238462,1968,3/1/2020 14:05,female,1,1997,3 +0.649625,0.80644444,0.94022222,1.055125,1968,2/21/2020 11:35,female,1,1997,3 +0.64075,0.80066667,0.68845455,0.73,1968,3/1/2020 14:10,female,1,1997,3 +0.9196,0.777625,0.94014286,0.93538462,1968,3/1/2020 11:09,female,1,1997,3 +0.56269231,0.6835,0.62225,0.78408333,1968,3/1/2020 14:13,female,1,1997,3 +0.57628571,0.7116,0.6764,0.999125,1968,3/1/2020 11:34,female,1,1997,3 +0.7175,1.035,0.708,0.88842857,1968,3/1/2020 11:13,female,1,1997,3 +0.62858333,0.65222222,0.60038462,0.8122,1968,3/1/2020 14:18,female,1,1997,3 +0.703,0.75111111,0.741,0.74866667,1968,3/1/2020 11:37,female,1,1997,3 +0.7935,0.7629,0.94783333,0.75636364,1968,3/1/2020 11:17,female,1,1997,3 +0.58144444,0.68318182,0.628875,0.6651,1968,3/1/2020 15:39,female,1,1997,3 +0.69522222,0.64746154,0.7762,0.82777778,1968,3/1/2020 11:40,female,1,1997,3 +0.66321429,0.7003,0.799,0.9205,1968,3/1/2020 11:20,female,1,1997,3 +0.55066667,0.70385714,0.763,0.7949,1968,3/1/2020 15:42,female,1,1997,3 +0.61436364,0.72677778,0.77827273,0.7958,1968,3/1/2020 12:39,female,1,1997,3 +0.71811111,0.70508333,0.67272727,0.7163,1968,3/1/2020 15:44,female,1,1997,3 +0.58953333,0.72215385,0.9418,0.73566667,1968,3/1/2020 12:41,female,1,1997,3 +0.50023077,0.56538462,0.68621429,0.49584615,1969,1/28/2020 18:56,male,1,1993,4 +0.50985714,0.60361538,0.47964706,0.4445,1969,1/28/2020 18:58,male,1,1993,4 +0.49984615,0.59446154,0.57075,0.48638889,1969,1/28/2020 18:53,male,1,1993,4 +0.62230769,0.62608333,0.748,0.67290909,1971,2/13/2020 16:38,female,1,1987,3 +0.6422,0.59961538,0.79833333,0.54966667,1971,2/13/2020 16:39,female,1,1987,3 +1.11366667,0.7625,0.9192,1.29583333,1971,2/13/2020 16:36,female,1,1987,3 +0.741,0.72071429,0.98742857,0.799625,1971,2/13/2020 16:37,female,1,1987,3 +0.85125,1.13566667,0.94881818,1.02877778,1975,2/19/2020 14:01,female,1,1968,4 +0.88725,0.89142857,0.75409091,0.7071,1977,2/19/2020 14:32,female,1,1963,3 +0.984,0.90409091,0.885125,0.923875,1978,2/20/2020 7:07,female,1,1975,4 +0.83155556,0.8104,0.98877778,1.173375,1981,2/24/2020 17:20,male,1,1973,4 +0.93545455,1.1494,1.19471429,0.758,1989,4/16/2020 10:14,female,1,1962,3 +1.13516667,1.21,1.5504,0.9742,1989,4/17/2020 3:29,female,1,1962,3 +1.48475,1.8904,1.6048,1.54075,1989,4/15/2020 15:31,female,1,1962,3 +1.20366667,1.42866667,1.14522222,0.88157143,1989,4/19/2020 17:46,female,1,1962,3 +1.07085714,1.11833333,1.24866667,0.780125,1989,4/15/2020 16:01,female,1,1962,3 +1.3422,1.422,1.4042,1.46883333,1994,4/24/2020 22:39,female,1,1998,2 +1.07557143,0.84063636,0.611,0.72622222,1995,4/25/2020 23:16,male,1,1998,3 +1.47,1.167,0.793,8.334,1996,5/14/2020 12:53,male,1,1998,4 +0.95428571,3.5945,1.03733333,1.1655,2000,6/2/2020 18:07,male,1,1998,3 +0.755,0.69553846,0.8713,0.73058333,2001,6/2/2020 18:08,male,1,1997,3 +0.67435714,0.715,0.59081818,0.68918182,2003,6/15/2020 21:09,male,1,1991,4 +1.0605,1.266,1.12354545,1.1668,2004,8/26/2020 11:53,male,1,1979,5 +1.164,1.2795,0.736,0.687,2008,10/14/2020 10:21,female,1,1994,5 +0.8934,0.74271429,0.7306,0.83792308,2008,10/21/2020 18:36,female,1,1994,5 +0.927875,0.79315385,0.72888889,1.0588,2008,10/17/2020 18:45,female,1,1994,5 +0.81145455,0.8965,0.696,0.97709091,2008,4/3/2021 20:45,female,1,1994,5 +0.9386,0.78071429,0.69575,1.015,2008,10/21/2020 14:38,female,1,1994,5 +0.70972727,0.76416667,0.64754545,0.93081818,2008,4/7/2021 10:35,female,1,1994,5 +0.8102,0.7685,0.65157143,0.9399,2008,10/21/2020 16:35,female,1,1994,5 +0.8985,1.876,0.48833333,1.012,2008,4/22/2021 21:39,female,1,1994,5 +1.2505,1.058625,0.848,1.286,2009,10/14/2020 10:19,male,1,1994,4 +0.8762,1.05466667,0.8975,1.68566667,2009,10/20/2020 15:48,male,1,1994,4 +0.7185,0.850625,1.086125,1.06,2010,10/20/2020 17:51,male,1,1995,4 +0.75916667,0.85842857,1.14475,0.978,2010,10/22/2020 14:30,male,1,1995,4 +0.765875,0.76991667,0.823375,1.0035,2010,10/21/2020 14:33,male,1,1995,4 +0.64225,0.81528571,0.71553333,0.80688889,2010,10/22/2020 16:32,male,1,1995,4 +0.754,0.96957143,0.85285714,0.98011111,2010,10/20/2020 13:56,male,1,1995,4 +0.81,0.839,0.96157143,0.80183333,2010,10/21/2020 16:33,male,1,1995,4 +0.76283333,0.85166667,0.9826,1.06271429,2010,10/20/2020 16:03,male,1,1995,4 +0.878,0.83725,1.063,1.414,2010,10/21/2020 18:37,male,1,1995,4 +0.64683333,0.68573333,0.696625,0.85354545,2011,10/20/2020 15:48,male,1,2000,4 +0.60761538,0.58827273,0.99844444,0.6374,2012,10/20/2020 15:49,male,1,2001,2 +0.82125,0.82011111,0.77533333,0.98855556,2013,10/20/2020 15:48,female,1,2002,2 +0.7078,0.734,0.69714286,0.7867,2014,10/20/2020 15:48,male,1,1996,3 +0.68916667,0.61,0.57454545,0.62707143,2015,10/20/2020 15:47,male,1,2001,3 +0.69133333,0.84009091,0.7731,0.93422222,2016,10/20/2020 15:48,male,1,2001,2 +0.68622222,0.940625,0.78561538,0.727875,2017,10/20/2020 15:47,female,0,2001,3 +0.893,0.904,0.970375,0.78783333,2018,10/20/2020 15:48,male,1,2001,4 +0.67688889,0.52958333,0.6621875,0.60581818,2020,10/20/2020 15:48,male,1,2001,3 +1.14566667,0.8251,1.03125,0.89914286,2022,10/20/2020 15:48,male,1,2001,2 +0.7047,0.8233,0.92842857,0.58507692,2023,10/20/2020 15:48,male,1,2002,3 +1.19266667,1.115,1.13585714,0.968,2024,10/20/2020 15:51,male,1,2001,3 +1.109875,0.6484,0.6755,1.11111111,2026,10/20/2020 16:03,male,1,1999,4 +0.50942857,0.5341,0.65218182,0.58753846,2026,10/22/2020 14:24,male,1,1999,4 +0.6092,0.779125,0.68881818,0.74569231,2029,10/22/2020 14:23,male,0,1999,3 +0.86654545,0.77766667,0.71322222,0.77116667,2030,10/20/2020 16:03,male,1,2001,4 +0.91625,0.85866667,0.51025,0.78333333,2030,10/22/2020 14:35,male,1,2001,4 +0.91775,0.825625,0.693,0.84483333,2032,10/22/2020 14:24,female,1,2001,3 +0.80857143,1.221125,0.6815,0.7017,2032,10/22/2020 14:23,female,1,2001,3 +0.69261538,0.73014286,0.66333333,0.9584,2033,10/22/2020 14:24,male,1,2001,4 +0.66933333,0.6346,0.6978,0.93166667,2034,10/22/2020 14:22,male,1,2001,4 +0.86525,0.7769,0.83536364,0.9395,2037,10/20/2020 16:04,male,1,2001,4 +0.87214286,0.91983333,0.82942857,0.87107143,2037,10/22/2020 14:25,male,1,2001,4 +0.996,1.02033333,0.9122,0.91744444,2037,10/20/2020 16:03,male,1,2001,4 +0.68122222,0.62566667,0.57990909,0.721625,2040,10/20/2020 17:54,male,1,2002,4 +0.673,0.6395,0.62963636,0.83584615,2041,10/20/2020 17:55,male,1,1999,4 +0.71611111,1.05663636,0.661,0.96122222,2042,10/20/2020 17:54,male,0,2001,3 +0.6514,0.930875,0.76790909,0.97236364,2043,10/20/2020 17:54,male,1,2000,3 +0.92766667,0.72453846,1.0378,0.81475,2045,10/20/2020 17:54,male,1,2001,3 +0.6274,0.70488889,0.54116667,0.58811111,2046,10/20/2020 17:51,male,1,2001,3 +0.59722222,0.69718182,0.64791667,0.59535714,2047,10/20/2020 17:51,male,1,2001,3 +0.7734,0.78811111,0.91111111,1.2062,2049,10/20/2020 17:54,male,1,2001,3 +0.651,0.6141875,0.70875,0.71441667,2050,10/20/2020 17:51,male,1,2001,4 +0.94285714,0.8027,0.994875,0.898,2054,10/20/2020 17:54,male,1,2001,3 +0.90890909,0.95671429,0.93471429,0.84175,2055,10/20/2020 17:51,male,1,2001,3 +0.871,0.85383333,0.7585,1.004,2056,10/20/2020 18:07,male,1,2001,3 +0.78944444,0.66128571,0.8654,0.86581818,2059,10/20/2020 17:54,male,1,2001,3 +0.65090909,0.56078947,0.60942857,0.841875,2060,10/20/2020 18:06,female,1,2001,3 +0.6129375,0.636,0.62028571,0.72727273,2060,10/22/2020 16:31,female,1,2001,3 +0.7509,0.66316667,0.65376923,0.74015385,2060,10/20/2020 17:51,female,1,2001,3 +0.61869231,0.56291667,0.8833,0.8945,2061,10/20/2020 17:54,male,1,2001,3 +0.65828571,0.76181818,0.63066667,0.71526667,2063,10/20/2020 17:54,male,0,2000,3 +0.98316667,1.07142857,1.15057143,1.26616667,2064,10/20/2020 17:56,male,1,2001,3 +0.689875,0.76692308,0.80814286,0.71,2070,10/20/2020 19:28,male,1,2002,4 +1.3075,0.964,2.123,2.615,2071,10/20/2020 19:35,male,1,2002,2 +0.78383333,1.06314286,0.92009091,0.83066667,2071,10/22/2020 19:24,male,1,2002,2 +0.72209091,0.7816,0.5870625,0.76736364,2072,10/20/2020 19:31,male,1,2002,4 +1.1762,0.87083333,0.71988889,0.7620625,2075,10/20/2020 19:30,male,1,2001,4 +0.831,0.746,0.92233333,1.01309091,2077,10/20/2020 19:39,male,1,2001,3 +0.96885714,0.7317,0.74175,0.85936364,2078,10/20/2020 19:39,male,1,2002,3 +0.927125,0.6795,0.66144444,0.71315385,2079,10/20/2020 19:39,male,1,2001,5 +1.03457143,0.61383333,0.85577778,0.68254545,2080,10/20/2020 19:39,male,1,2001,4 +1.022,0.8768,1.08283333,0.82755556,2082,10/20/2020 19:39,male,1,2001,2 +0.68392308,0.70577778,0.68528571,0.495,2083,10/20/2020 19:39,male,1,2001,4 +0.71225,0.58075,0.58473684,0.5893,2084,10/20/2020 19:39,male,1,2001,3 +0.64145455,0.90171429,0.86,0.924,2085,10/20/2020 19:39,male,1,2002,3 +0.67013333,0.60685714,0.7715,0.676,2086,10/20/2020 19:39,male,1,1989,4 +1.18066667,0.94354545,1.0206,1.3832,2087,10/20/2020 19:39,male,1,2001,3 +0.91842857,1.004,0.92333333,0.87325,2088,10/20/2020 19:46,female,1,2002,3 +0.65807692,0.61692308,0.73416667,0.76216667,2088,10/22/2020 16:32,female,1,2002,3 +3.4408,0.78942857,1.0116,0.8645,2090,10/20/2020 20:01,male,1,1983,3 +1.24628571,1.46716667,1.4204,1.0582,2091,10/20/2020 20:13,female,1,1972,3 +1.00266667,0.964,1.05533333,1.0019,2092,10/20/2020 20:26,male,1,1977,2 +1.2426,0.935,1.12683333,1.56,2093,10/20/2020 20:37,female,1,1997,3 +3.34825,2.12766667,1.772,2.11166667,2094,10/20/2020 20:50,female,0,1975,3 +0.53147619,0.58811111,0.66436364,0.65844444,2095,10/20/2020 22:13,male,1,2002,3 +0.89785714,1.025,1.522,0.85228571,2102,10/21/2020 9:52,male,1,1968,5 +0.772,0.77388889,0.78544444,1.027375,2107,10/21/2020 9:55,female,1,1992,4 +0.7056,0.7583,0.66766667,0.82328571,2107,10/21/2020 9:56,female,1,1992,4 +0.634,0.7848,0.71290909,0.5532,2119,10/21/2020 14:38,male,1,2001,3 +0.83991667,0.95366667,0.95525,0.7175,2120,10/21/2020 14:38,female,1,2002,2 +0.6871,1.61185714,0.73075,1.0936,2120,11/6/2020 14:07,female,1,2002,2 +0.95016667,0.6886,0.8315,1.014,2121,10/21/2020 14:38,male,1,2001,3 +0.66942857,0.53325,1.07575,0.72290909,2124,10/21/2020 14:38,male,1,2001,3 +0.67822222,0.61335294,0.78455556,0.772875,2126,10/21/2020 14:33,male,1,2002,3 +0.65458333,0.63307692,0.584,0.95822222,2129,10/21/2020 14:38,male,1,2001,4 +1.17611111,1.032875,0.987,0.9882,2130,10/21/2020 14:33,male,1,2001,3 +0.63609091,0.65915385,0.577875,0.62153333,2131,10/21/2020 14:33,male,1,2001,3 +0.865,0.706125,0.82718182,1.01022222,2134,10/21/2020 14:41,male,1,2002,2 +0.8355,0.64627273,0.75011111,0.8689,2134,10/22/2020 22:58,male,1,2002,2 +0.81163636,0.73214286,0.96625,0.7445,2134,11/3/2020 14:02,male,1,2002,2 +0.8646,0.82166667,0.93885714,0.747,2135,10/21/2020 14:38,male,1,2001,4 +0.65975,0.752,0.84122222,1.097,2140,10/21/2020 14:38,male,1,2001,3 +1.07828571,1.2166,1.8636,1.16116667,2141,10/21/2020 16:34,female,1,1995,2 +0.65333333,0.961625,1.0702,0.924,2143,10/21/2020 16:34,male,1,2001,3 +1.04771429,1.74,1.361125,1.287,2144,10/21/2020 16:35,male,0,2001,3 +0.7355,0.643125,0.7515,0.8178,2145,10/21/2020 16:35,male,0,2001,3 +0.92336364,0.91385714,0.95275,0.89133333,2146,10/21/2020 16:34,male,1,2001,3 +1.30583333,0.93266667,0.74728571,0.7885,2149,10/21/2020 16:34,female,1,2001,3 +0.53428571,1.15242857,0.67723529,1.59975,2150,10/21/2020 16:35,male,1,2001,3 +0.671375,0.7198,0.573,0.839,2151,10/21/2020 16:35,male,1,2001,3 +0.61366667,0.52983333,0.58141667,0.6812,2152,10/21/2020 16:34,male,1,2001,4 +0.65028571,0.63166667,0.68253846,0.4645,2153,10/21/2020 16:34,male,1,2001,3 +0.5593,0.59,0.59464706,0.56954545,2153,10/21/2020 18:23,male,1,2001,3 +0.644,0.57441667,0.76,0.78361538,2155,10/21/2020 16:35,male,1,2001,3 +1.32085714,1.31416667,1.1272,1.4342,2157,10/21/2020 16:35,female,1,2002,3 +1.012375,0.61785714,1.18657143,1.130625,2159,10/21/2020 16:34,male,1,2001,3 +0.76014286,0.71211111,0.80891667,0.8324,2160,10/21/2020 16:33,male,1,2001,1 +0.5608125,0.721,0.71766667,0.667,2163,10/21/2020 16:50,male,1,2002,2 +1.11471429,1.18783333,1.03566667,0.788,2164,10/21/2020 16:34,female,1,2001,3 +1.731,0.998,1.076,1.094,2164,10/31/2020 12:33,female,1,2001,3 +0.8751,0.7334,0.9572,1.1,2164,10/31/2020 19:42,female,1,2001,3 +0.77,0.789,0.73877778,0.85683333,2167,10/21/2020 16:33,male,1,2002,2 +0.905,0.98,1.193,1,2168,10/21/2020 16:34,male,1,2002,2 +0.96466667,0.7797,0.84,1.303,2170,10/21/2020 16:33,male,0,2002,1 +0.51931579,0.7583,0.71966667,0.80214286,2171,10/21/2020 16:35,male,1,2002,5 +0.73157143,0.862875,0.77583333,0.84914286,2171,10/21/2020 16:34,male,1,2002,5 +1.29116667,1.0058,1.08009091,0.97,2172,10/21/2020 16:34,female,1,1998,3 +0.902125,0.7138,0.808125,0.8624,2173,10/21/2020 18:36,male,1,2001,4 +0.69433333,0.73288889,0.76155556,0.5852,2174,10/31/2020 9:52,male,1,2001,4 +0.68827273,0.68344444,0.78861538,0.685,2174,10/21/2020 18:37,male,1,2001,4 +1.495,0.89314286,0.98371429,1.0816,2175,10/21/2020 18:36,female,1,2001,3 +0.866,0.91771429,0.89225,0.8608,2175,10/21/2020 18:37,female,1,2001,3 +0.864,0.98175,0.762,0.87869231,2176,10/21/2020 18:37,male,1,2001,4 +0.86733333,1.003,0.9393,1.045,2176,10/21/2020 18:36,male,1,2001,4 +0.98942857,0.81257143,0.9955,1.03857143,2178,10/21/2020 18:36,male,1,2001,3 +1.12166667,0.79369231,0.93527273,0.98,2179,10/21/2020 18:37,male,1,2001,3 +0.9914,0.97983333,1.296,1.078125,2180,10/21/2020 18:37,male,0,2001,2 +1.2164,0.94216667,1.14390909,1.0454,2181,10/21/2020 18:37,male,1,2001,2 +1.2936,1.39083333,1.17488889,0.8478,2182,10/21/2020 18:37,male,1,2001,3 +1.225,0.8114,0.85553333,1.0654,2183,10/21/2020 18:37,female,1,2001,3 +1.129,1.00590909,0.821125,1.099,2184,10/21/2020 18:36,male,1,1999,3 +1.07325,0.73927273,1.25344444,1.0235,2187,10/21/2020 18:38,male,1,2001,3 +0.5221,0.57276923,0.46678571,0.48984615,2188,10/21/2020 18:37,male,1,2000,4 +0.53907692,1.09625,0.66936364,0.6284,2189,10/21/2020 18:38,male,1,2001,4 +0.89133333,0.7406,0.6501,0.91711111,2190,10/21/2020 18:37,male,1,2001,3 +0.76322222,0.68881818,0.9336,0.82233333,2191,10/21/2020 18:38,male,1,2001,3 +0.76322222,0.68881818,0.9336,0.82233333,2191,10/21/2020 18:38,male,1,2001,3 +0.64223077,0.65722222,0.661,0.7976,2191,10/26/2020 19:09,male,1,2001,3 +0.599,0.805,0.583,1.199,2191,11/2/2020 18:15,male,1,2001,3 +1.051,1.19725,1.057,1.23877778,2193,10/21/2020 18:35,male,1,2001,2 +0.95275,1.022375,1.0732,1.24042857,2193,10/21/2020 18:47,male,1,2001,2 +0.7837,0.80928571,0.76711111,1.00844444,2195,10/21/2020 18:37,male,1,2002,3 +1.20628571,1.23625,1.5255,1.7642,2198,10/21/2020 18:38,male,1,2002,3 +1.836,0.77133333,1.03066667,1.017,2199,10/21/2020 18:37,male,1,2002,4 +0.72,1.116,1.0325,0.503,2200,10/21/2020 21:01,male,1,1981,5 +0.60845455,0.690625,0.699625,0.73175,2201,10/21/2020 21:03,male,0,1995,3 +0.7765,0.68475,0.75538462,0.71628571,2202,10/22/2020 9:58,male,1,1999,3 +1.1612,0.623,1.17766667,0.684,2203,10/22/2020 11:07,female,1,1965,3 +0.77781818,1.09983333,0.82757143,1.00125,2205,10/22/2020 14:26,male,1,2001,3 +0.761,0.63353846,0.668125,0.688625,2206,10/22/2020 14:39,male,1,2001,4 +0.81822222,1.00477778,0.79233333,0.8755,2207,10/27/2020 10:07,female,1,2001,3 +0.8068,0.92466667,0.82288889,0.97007692,2207,10/27/2020 10:55,female,1,2001,3 +0.97377778,0.99488889,1.06283333,1.26225,2207,10/27/2020 10:17,female,1,2001,3 +2.2216,2.266,2.44033333,2.3145,2207,10/27/2020 10:29,female,1,2001,3 +1.03225,0.8284,1.0105,0.8885,2207,10/22/2020 14:30,female,1,2001,3 +1.5265,1.568,1.94333333,2.167,2207,10/27/2020 10:41,female,1,2001,3 +0.85,2.5996,0.8726,0.932,2208,10/22/2020 14:31,female,1,2002,3 +0.88622222,0.85181818,0.7505,0.94614286,2211,10/22/2020 16:03,male,1,2001,3 +1.263,0.80155556,0.68183333,1.0866,2213,10/22/2020 16:32,male,1,2001,3 +0.64377778,0.71845455,0.88557143,0.68957143,2215,10/22/2020 18:13,male,1,1985,3 +0.60736364,0.61033333,0.719,0.59533333,2216,10/22/2020 18:31,male,1,2001,4 +0.65691667,0.7415,0.68885714,0.67575,2217,10/22/2020 19:21,male,1,2001,4 +1.0267,1.0534,1.41375,0.92388889,2218,10/22/2020 19:22,male,1,2001,2 +1.1145,0.7898,0.931125,0.90833333,2219,10/22/2020 19:22,male,1,2001,3 +0.58927273,0.68092308,0.55038462,0.55938462,2220,10/22/2020 20:02,male,1,2001,4 +0.711,0.6869,0.772,0.71216667,2221,10/22/2020 20:33,male,1,2001,3 +0.72426667,0.62223077,0.82228571,0.67971429,2221,10/22/2020 20:34,male,1,2001,3 +1.01672727,0.67422222,0.796,0.95242857,2226,10/23/2020 14:40,male,1,2002,2 +0.944875,0.98207692,1.295,1.1075,2227,10/23/2020 14:15,male,1,2001,1 +1.611625,1.27425,1.16966667,1.11571429,2229,10/23/2020 14:31,male,1,1999,2 +0.82928571,0.86866667,0.84864286,0.84409091,2231,10/23/2020 14:51,female,1,2000,4 +0.99911111,1.01114286,0.75922222,0.95514286,2232,10/23/2020 14:52,female,1,1982,3 +0.7233,0.701,0.69075,1.2722,2233,10/23/2020 15:01,male,1,1999,4 +0.987,1.256,1.415,1.479,2234,10/23/2020 15:07,male,1,1990,4 +1.036,0.6905,0.95966667,1.18809091,2234,10/31/2020 16:37,male,1,1990,4 +0.70236364,0.6917,0.922875,0.7436,2235,10/23/2020 15:18,female,1,1975,3 +0.86914286,1.247,1.195,0.9012,2236,10/31/2020 16:27,female,1,1985,3 +0.87275,0.6605,1.06871429,0.9795,2236,10/31/2020 16:28,female,1,1985,3 +1.25816667,0.8176,1.22157143,1.13042857,2237,10/31/2020 19:59,male,1,1973,4 +1.319,1.7375,1.125,0.984,2238,10/23/2020 15:39,female,1,1963,2 +1.417,1.4924,0.97275,1.27,2239,10/23/2020 15:47,male,1,1975,1 +1.785,2.8265,1.575,2.373,2240,10/23/2020 15:52,male,1,1958,1 +0.82433333,0.92318182,0.8316,0.934,2242,10/23/2020 16:31,male,1,1980,4 +0.71707692,0.67922222,0.716,0.66744444,2242,10/23/2020 16:40,male,1,1980,4 +0.954,1.15916667,0.80471429,1.0773,2243,10/23/2020 16:38,male,1,1996,4 +0.8325,0.9257,0.86636364,0.81311111,2243,10/27/2020 18:14,male,1,1996,4 +0.7446,0.81066667,0.6793,0.65621429,2244,10/23/2020 17:02,male,1,2001,3 +1.196625,1.0965,1.1395,1.57325,2246,10/23/2020 17:04,male,1,1994,3 +1.22033333,1.11518182,1.32016667,1.2088,2247,10/23/2020 17:18,male,1,1963,2 +1.321,1.7118,2.20625,1.85825,2247,10/23/2020 17:19,male,1,1963,2 +1.70675,1.575,1.17883333,1.2888,2248,10/23/2020 17:20,female,1,1972,2 +0.739,1.171,1.09655556,0.908125,2249,10/23/2020 17:28,male,1,1968,2 +0.71628571,0.73,0.941375,0.55575,2250,10/23/2020 18:41,male,1,2001,3 +0.9392,1.21485714,0.78641667,0.859125,2251,10/23/2020 18:06,male,1,1997,4 +0.723,0.7815,0.666,0.942,2252,10/23/2020 18:20,male,1,2003,3 +0.75171429,0.695,0.64275,0.81616667,2253,10/23/2020 20:26,female,0,2001,3 +0.69975,0.77885714,0.7441,0.68666667,2256,10/24/2020 12:37,male,1,1992,3 +0.510625,0.5195,0.62081818,0.642,2258,10/24/2020 13:38,male,1,2001,3 +0.87722222,1.01983333,0.9215,1.02133333,2260,10/24/2020 15:06,female,1,2001,3 +1.2605,1.2965,2.8395,0.7165,2261,10/24/2020 16:48,male,1,1975,4 +1.34733333,1.216,1.277,1.5858,2262,10/24/2020 17:08,female,0,1975,3 +0.67114286,0.65418182,0.79142857,0.7795625,2263,10/24/2020 17:14,male,1,2001,4 +0.66975,0.54181818,0.64322222,0.9178,2264,10/24/2020 19:30,male,1,1966,2 +0.79375,0.5884,0.48,0.87,2265,10/24/2020 19:37,male,1,1972,2 +0.7994,0.69323077,1.12275,1.36116667,2266,10/24/2020 21:18,female,1,1986,2 +1.37033333,1.485,2.154,1.18,2268,10/27/2020 19:08,male,0,1955,1 +1.917,1.465,1.213,0.962,2269,10/24/2020 23:49,male,1,1986,3 +1.492,1.4858,1.8156,1.134,2272,10/25/2020 0:20,male,1,1968,3 +1.66914286,1.49,1.43633333,1.8052,2273,10/25/2020 12:28,male,1,1966,1 +1.38171429,1.3952,1.42725,1.4368,2275,10/25/2020 13:11,female,1,1963,2 +0.76641667,0.61572727,0.86188889,0.84957143,2277,10/25/2020 21:28,male,1,2001,3 +0.73092308,0.962,0.93183333,0.88728571,2278,10/25/2020 13:40,male,1,2001,2 +1.20433333,1.81475,3.432,1.6738,2279,10/25/2020 14:01,female,1,1969,2 +2.677,2.11033333,1.826,1.742,2281,10/25/2020 14:52,male,1,1954,2 +0.911,0.7895,1.16242857,0.95222222,2282,10/25/2020 20:07,female,1,2000,2 +0.94633333,0.96528571,0.854,0.91357143,2282,10/25/2020 20:16,female,1,2000,2 +1.33516667,1.5106,1.20625,2.03,2283,10/25/2020 16:44,female,1,2003,3 +1.2875,0.80616667,0.93166667,0.62683333,2283,10/31/2020 16:22,female,1,2003,3 +0.89022222,0.73611111,0.59922222,0.81358333,2285,10/25/2020 18:36,male,1,2001,3 +1.4056,1.37533333,2.0395,1.1645,2286,10/25/2020 19:06,male,1,1968,2 +0.977125,0.869375,0.77433333,1,2288,10/25/2020 19:48,male,1,2001,4 +2.691,2.922,2.3975,2.713,2289,10/25/2020 19:23,female,1,1948,1 +1.94133333,1.8845,1.9864,2.09,2290,10/25/2020 19:32,male,1,1978,2 +0.939,1.167,1.1175,1.50566667,2291,10/25/2020 19:39,female,1,1995,2 +1.9046,2.81133333,2.06466667,1.78033333,2292,10/25/2020 19:51,female,1,1962,2 +3.05033333,1.66916667,1.7955,1.585,2293,10/25/2020 20:06,male,1,1955,2 +0.82614286,1.35633333,0.94083333,0.79783333,2294,10/25/2020 20:06,female,1,1995,2 +0.961375,1.5712,0.97357143,0.88875,2295,10/25/2020 21:18,female,1,1981,2 +1.09942857,1.37666667,1.12166667,1.125,2296,10/25/2020 21:04,female,1,1972,3 +1.66916667,1.1475,1.2,1.1094,2297,10/25/2020 21:21,male,0,1990,3 +1.01466667,1.222,1.206,0.89154545,2298,10/25/2020 21:16,male,1,1970,3 +1.009,1.20575,1.1066,1.150875,2299,10/25/2020 21:34,male,1,1942,2 +0.86383333,0.78114286,0.82641667,0.79225,2300,10/25/2020 21:40,female,1,1983,3 +1.15571429,1.08175,1.05971429,1.327,2301,10/25/2020 21:47,female,1,1947,2 +0.81163636,0.954,0.611,0.9128,2302,10/25/2020 22:19,male,1,2001,3 +1.00392308,0.8407,1.20633333,0.95,2303,10/26/2020 10:12,female,1,1999,3 +1.6702,1.709,1.6435,1.378,2304,10/26/2020 9:55,female,1,1978,2 +1.266,1.02675,1.007,1.01922222,2304,11/2/2020 17:45,female,1,1978,2 +1.8635,2.02925,1.88966667,1.87,2305,10/26/2020 10:23,female,1,1968,1 +1.59966667,1.8446,1.6722,1.506,2306,10/26/2020 10:33,male,1,1944,1 +0.6402,0.60609091,0.51068421,0.55,2309,10/26/2020 15:05,male,1,2001,3 +0.80091667,1.16616667,0.901125,1.0754,2310,11/3/2020 15:31,male,1,2001,2 +0.95883333,0.76511111,0.72453846,0.7524,2311,10/27/2020 19:19,female,1,2001,3 +0.87575,0.78769231,0.84555556,0.63375,2312,10/26/2020 18:30,female,0,1975,4 +0.776125,0.91483333,0.764,0.8549,2315,10/28/2020 16:33,male,0,2001,3 +1.10833333,0.9595,1.711,1.43583333,2316,10/26/2020 22:28,female,1,1983,3 +0.79292308,0.794,0.89275,0.8245,2317,10/27/2020 10:36,female,1,2001,3 +2.743,2.01233333,2.888,2.901,2319,10/27/2020 12:06,male,1,1989,2 +1.415,1.7435,2.77366667,1.226,2321,10/27/2020 18:57,female,1,1975,3 +1.1402,1.2414,0.93944444,1.057625,2322,10/27/2020 18:58,female,1,1966,2 +1.211875,0.92827273,1.1404,1.27433333,2323,10/27/2020 19:09,male,1,1971,2 +0.79366667,0.758,0.6924,0.663,2324,10/27/2020 19:31,male,1,1998,3 +0.792,0.80725,0.7584,1.04733333,2327,10/27/2020 21:44,male,1,2001,4 +0.9045,0.66666667,1.004,0.897,2328,10/27/2020 23:07,male,1,1995,3 +0.7765,0.71722222,0.77511111,0.908,2334,10/28/2020 12:03,female,1,1999,3 +2.773,2.07866667,1.4802,1.6378,2335,10/28/2020 13:46,female,1,1955,2 +0.63875,0.59916667,0.7614,0.984,2337,10/28/2020 15:00,female,1,1998,1 +1.1276,1.076,1.1982,1.0792,2338,10/28/2020 15:17,female,1,2004,2 +0.5075,0.55790909,0.5208,0.844,2340,10/28/2020 15:44,male,1,2001,3 +0.7575,0.62533333,0.7698,0.711,2341,10/28/2020 15:45,male,1,2001,4 +0.782,0.69316667,0.75892308,0.6858,2342,10/28/2020 15:45,female,1,2006,2 +1.16471429,1.0065,1.51157143,0.84716667,2346,10/28/2020 19:13,female,1,1975,2 +0.65525,0.5729,0.8472,0.69436364,2347,10/28/2020 19:21,male,1,1969,3 +1.1924,0.55330769,0.677,0.696875,2348,10/28/2020 19:36,female,1,1989,2 +1.90811111,1.5515,1.058,1.2145,2349,10/28/2020 19:30,male,1,1958,2 +1.625,0.959,0.784,0.861,2351,10/28/2020 20:06,male,1,1970,3 +1.2758,1.08014286,1.33888889,1.12766667,2353,10/28/2020 20:17,female,1,1977,2 +1.306,1.0565,1.458,1.162,2356,10/29/2020 2:25,male,1,1968,2 +1.1198,1.37542857,0.944,0.8669,2357,10/29/2020 2:37,female,1,1991,3 +1.1886,1.106,0.94257143,1.40033333,2358,10/29/2020 11:39,male,1,1966,2 +0.9798,0.775625,0.76772727,1.0112,2359,10/29/2020 12:05,male,1,1999,2 +0.58463636,0.70133333,0.69416667,0.9075,2360,10/29/2020 12:13,female,0,1994,3 +1.98166667,1.42757143,1.187,1.643,2361,10/29/2020 12:24,male,1,1973,2 +0.58445455,0.73414286,0.5956,0.63515789,2362,10/29/2020 13:04,female,0,1989,3 +2.20833333,2.085,2.414,3.5955,2363,10/29/2020 13:14,male,0,1967,2 +4.4185,3.965,3.511,4.0765,2364,10/29/2020 13:24,male,1,1956,1 +0.74633333,0.81707692,0.78441667,0.79866667,2365,10/29/2020 15:14,female,1,1995,3 +0.809,1.215,1.29657143,1.01514286,2368,10/30/2020 19:38,male,1,2001,2 +1.03575,1.34616667,1.22985714,1.19275,2368,10/30/2020 19:20,male,1,2001,2 +1.99666667,1.20222222,1.60366667,0.804,2370,10/31/2020 12:54,female,1,1998,4 +1.012,1.2,1.3985,0.90566667,2370,10/31/2020 13:15,female,1,1998,4 +0.76385714,0.74411111,1.07866667,0.99954545,2370,10/31/2020 19:50,female,1,1998,4 +1.7176,1.2395,1.076,1.11158333,2371,10/31/2020 13:28,male,1,1990,4 +1.065625,1.03075,1.09222222,0.96528571,2371,10/31/2020 13:28,male,1,1990,4 +1.44314286,0.73322222,1.03985714,1.1504,2372,10/31/2020 13:51,female,0,1985,3 +1.1067,1.11975,1.158125,1.206,2372,10/31/2020 13:52,female,0,1985,3 +1.18933333,0.89628571,1.11077778,1.156,2373,10/31/2020 14:10,male,1,1975,3 +0.8395,1.16314286,1.12311111,0.739625,2373,10/31/2020 14:11,male,1,1975,3 +1.50683333,0.9806,1.048,1.31675,2374,10/31/2020 14:29,female,1,1969,2 +0.95,0.882,1.2622,1.127875,2374,10/31/2020 14:30,female,1,1969,2 +1.57828571,1.757,2.9095,1.7515,2375,10/31/2020 14:52,male,1,1963,1 +1.2028,1.14225,1.196,1.19085714,2375,10/31/2020 14:53,male,1,1963,1 +1.7635,1.17,2.074,2.2294,2376,10/31/2020 18:29,male,1,1953,2 +0.6006,0.59666667,0.6155,0.871,2377,10/31/2020 19:03,male,1,1972,2 +0.52815,0.666,0.682,0.729375,2378,10/31/2020 19:12,male,1,1970,1 +0.5643125,0.60527273,0.64122222,0.74809091,2379,10/31/2020 19:20,male,1,1964,2 +5.88,2.3145,3.462,3.975,2381,10/31/2020 20:21,male,1,1959,3 +1.877,1.9786,1.88075,2.26666667,2381,10/31/2020 20:40,male,1,1959,3 +0.868,0.973,2.2395,0.952,2383,10/31/2020 21:40,male,1,1995,3 +0.892,1.078875,0.84075,0.8065,2384,11/2/2020 17:34,female,1,1985,2 +1.1305,1.03728571,0.96718182,1.06683333,2386,11/2/2020 17:57,male,1,1944,1 +4.297,4.791,1.779,2.477,2387,11/2/2020 19:22,male,1,1965,3 +0.970625,0.76516667,1.06716667,0.96681818,2391,11/2/2020 20:24,male,1,2001,3 +1.617,1.2974,1.396,1.31811111,2392,11/2/2020 22:03,male,1,1960,4 +1.31577778,1.47425,1.833,1.5272,2393,11/3/2020 9:55,female,1,1991,3 +2.70375,5.4105,1.9675,1.6535,2394,11/3/2020 10:12,male,1,1971,1 +1.4356,1.2895,1.996,3.604,2395,11/3/2020 10:33,female,1,1971,1 +1.3435,2.02766667,1.659,2.1244,2395,11/3/2020 10:36,female,1,1971,1 +0.50418182,0.69958333,1.0378,0.628875,2396,11/3/2020 11:00,male,1,1987,4 +3.0842,3.408,2.023,2.36333333,2397,11/3/2020 11:13,male,1,1952,1 +1.8645,1.73766667,1.79228571,2.942,2398,11/3/2020 12:02,male,1,1949,1 +1.35544444,1.286,1.236,2.12766667,2401,11/3/2020 14:38,male,1,1999,2 +1.2514,1.23275,1.5196,1.8966,2402,11/3/2020 17:05,male,0,1989,3 +2.42933333,2.61525,1.99866667,5.986,2403,11/3/2020 17:15,female,1,1973,1 +1.37233333,1.31025,0.88477778,1.564,2404,11/3/2020 17:28,male,1,1969,2 +1.768,1.58816667,1.37825,1.703,2405,11/3/2020 17:27,male,1,1944,3 +1.04766667,0.97285714,0.79407143,0.9754,2407,11/3/2020 17:28,male,1,2001,4 +1.04391667,1.197,0.9969,1.216,2408,11/3/2020 17:36,female,1,1962,3 +0.5472,0.669,0.582,0.58668421,2409,11/3/2020 20:09,male,1,1993,5 +0.608375,0.82866667,0.5275,0.5676,2410,11/3/2020 21:38,male,1,1995,3 +1.9158,1.432,1.1755,1.32914286,2411,11/3/2020 22:11,female,1,2002,2 +0.705,0.738,0.71175,0.98333333,2411,11/3/2020 23:06,female,1,2002,2 +1.912,1.49666667,1.309,2.3832,2412,11/3/2020 22:25,female,1,1977,2 +1.7784,1.889,1.93425,2.5,2413,11/3/2020 22:53,male,1,1968,2 +1.355,1.5525,1.67542857,1.62083333,2414,11/4/2020 16:56,male,1,1986,3 +0.87466667,0.8705,1.3095,1.32928571,2414,11/4/2020 16:57,male,1,1986,3 +2.64866667,1.8235,1.20411111,1.64675,2415,11/4/2020 17:16,female,1,1974,2 +1.5786,0.53977778,1.229,1.437,2416,11/4/2020 17:40,male,1,1996,2 +1.857,1.42155556,1.4445,2.15175,2418,11/5/2020 19:33,male,1,1965,2 +0.6969,1.06614286,0.59635714,0.97028571,2421,11/4/2020 18:58,male,1,2001,3 +0.66258333,0.839,1.3618,0.79644444,2422,11/5/2020 11:10,male,1,1979,2 +0.88816667,0.72955556,0.752,0.882,2423,11/5/2020 11:33,male,0,1986,5 +1.193,0.829375,0.8638,0.8698,2424,11/8/2020 13:20,male,1,2001,4 +0.65353333,0.5405,0.6746,0.82381818,2425,11/10/2020 18:55,male,1,2001,1 +0.99533333,0.942125,0.8874,1.162,2427,11/11/2020 10:18,male,1,1999,3 +1.411,2.09875,1.399,1.286375,2429,11/14/2020 17:55,male,1,1954,3 +1.37385714,1.001,1.01775,1.1916,2430,11/16/2020 17:04,male,1,2001,2 +0.7085,0.58316667,0.68171429,0.681,2431,11/18/2020 10:48,female,1,1996,4 +0.909125,0.683625,0.83016667,1.16716667,2433,11/18/2020 10:54,male,1,2001,2 +0.56,1.225,0.61,0.635,2438,11/18/2020 11:08,male,1,2001,4 +0.729,0.881,0.7755,0.889875,2440,11/18/2020 11:20,male,1,2001,3 +0.7919,1.20883333,0.76977778,0.842,2441,11/18/2020 11:20,male,1,2001,3 +0.73884615,0.80785714,0.6255,0.90044444,2442,11/18/2020 11:27,male,1,2001,4 +0.974875,1.042125,0.80316667,0.8486,2450,11/18/2020 11:23,female,1,2000,2 +1.3562,1.39357143,1.27828571,1.7105,2453,11/18/2020 18:11,male,1,1967,2 +2.63066667,3.483,2.29833333,3.0575,2454,11/18/2020 18:42,male,1,1955,1 +1.02883333,0.78757143,0.86166667,0.85906667,2455,11/18/2020 18:59,female,1,1989,4 +0.8487,0.7465,1.09925,1.1764,2456,11/18/2020 20:25,female,0,1974,1 +0.85616667,0.658875,1.04222222,1.087,2457,11/19/2020 21:41,male,1,1995,3 +1.475125,1.1556,1.06328571,1.21925,2458,11/20/2020 14:22,female,1,2001,2 +0.67433333,0.7646,0.70416667,0.6035625,2460,11/22/2020 17:20,female,1,1996,4 +0.77771429,0.95055556,0.96781818,0.86733333,2461,11/23/2020 11:52,female,1,1991,4 +0.756,0.66216667,0.6935,0.72,2461,11/23/2020 11:53,female,1,1991,4 +0.77166667,0.645125,0.76076923,0.73085714,2463,11/23/2020 13:47,male,1,2001,3 +0.64664706,0.62745455,0.67,0.809875,2464,11/23/2020 13:30,male,1,1999,3 +0.58461538,0.7239,0.56092857,0.7078,2466,11/23/2020 13:50,male,1,2001,4 +0.60682353,0.54128571,0.58342857,0.67181818,2470,11/26/2020 8:11,male,1,1979,3 +1.15,1.72814286,1.22825,2.2508,2471,11/26/2020 8:30,male,1,1962,2 +0.53523529,0.73688889,0.62192308,0.6133,2472,11/26/2020 8:40,female,1,1993,3 +0.983,0.87733333,1.0184,1.101,2473,11/28/2020 11:03,male,1,2001,2 +1.542,1.5034,1.606,1.4716,2474,11/28/2020 11:13,female,1,2000,1 +0.5769375,0.50615385,0.66521429,0.52188889,2475,11/28/2020 11:22,male,1,2002,3 +0.558,0.47371429,0.53855556,0.475,2476,11/28/2020 11:31,male,1,1991,4 +0.57707143,0.47866667,0.5999,0.46455556,2477,11/28/2020 11:39,male,1,2001,3 +0.52014286,0.66755556,0.52927273,0.71436364,2478,11/29/2020 14:52,male,1,2001,3 +0.58142857,0.686,0.71388889,0.5625,2479,11/29/2020 15:03,male,1,2001,2 +0.6308,0.514,0.66258333,0.6431875,2482,11/28/2020 19:05,male,1,1993,3 +0.8467,1.4625,0.80009091,1.1568,2489,12/5/2020 13:47,male,1,1973,2 +2.89,1.9282,2.0415,1.80833333,2490,12/5/2020 14:01,female,1,1981,2 +0.84988889,0.87188889,0.79242857,0.80663636,2492,1/22/2021 15:42,male,1,2001,3 +2.16075,1.655,2.0345,1.855,2493,1/22/2021 16:07,female,1,1950,1 +1.2586,1.198125,1.4966,1.3178,2494,1/22/2021 16:38,female,1,1977,2 +1.592,1.74825,1.91125,1.80175,2495,1/22/2021 16:59,male,1,1968,2 +0.79071429,1.06975,0.88481818,0.85157143,2496,1/22/2021 17:19,male,1,1986,3 +2.041,2.634,1.81975,2.257,2497,1/22/2021 17:30,male,1,1945,1 +0.978625,0.948,1.16228571,1.09766667,2513,3/9/2021 14:39,female,1,1962,3 +1.50733333,1.5518,1.6852,1.748,2513,3/9/2021 14:02,female,1,1962,3 +1.10757143,0.94388889,1.08366667,1.09377778,2513,3/9/2021 14:30,female,1,1962,3 +0.9614,0.949125,0.88233333,1.00728571,2514,3/13/2021 20:51,male,1,1990,3 +0.6946,0.6655,0.8793,0.74216667,2515,3/13/2021 21:10,female,1,1977,2 +0.96642857,1.0675,1.15814286,1.43933333,2516,3/13/2021 21:22,male,1,1969,2 +1.16975,1.26933333,1.206,1.68883333,2517,3/13/2021 21:39,male,1,1960,1 +0.7972,0.93975,0.83533333,0.689,2530,4/19/2021 19:15,female,1,2000,3 +0.92833333,0.82333333,0.75333333,0.8998,2530,4/19/2021 19:15,female,1,2000,3 +0.79875,0.7436,0.62010526,0.7379,2531,4/12/2021 11:14,female,1,1999,3 +0.8156,0.758875,0.71885714,0.63175,2531,4/7/2021 13:48,female,1,1999,3 +0.692625,0.74930769,0.6694,0.68336364,2533,4/7/2021 10:37,female,1,2001,4 +0.6689,0.63623077,0.5905625,0.61633333,2533,4/8/2021 10:13,female,1,2001,4 +0.93325,0.77333333,0.85325,0.965,2535,4/7/2021 15:27,female,1,2001,3 +0.54525,0.7087,0.63188235,0.68925,2535,4/17/2021 18:26,female,1,2001,3 +0.69475,0.829,0.87033333,0.83033333,2535,4/7/2021 15:21,female,1,2001,3 +0.572,0.49022222,0.5115,0.49775,2536,4/7/2021 10:36,male,1,2001,4 +0.521,0.5086,0.54984615,0.54611111,2536,4/7/2021 10:37,male,1,2001,4 +0.8265,0.74718182,0.77177778,1.25866667,2538,4/7/2021 10:38,female,1,2000,3 +0.782,0.902,1.016625,1.4706,2539,4/7/2021 10:36,male,1,2001,3 +0.78963636,0.5945,0.9385,1.04166667,2539,4/7/2021 10:37,male,1,2001,3 +0.61522222,0.76328571,0.72961538,0.79181818,2540,4/15/2021 22:23,male,1,1999,3 +0.6905,0.66709091,0.8923,0.69777778,2540,4/7/2021 10:35,male,1,1999,3 +0.72428571,0.62845455,0.869,0.6878,2541,4/8/2021 15:20,female,1,2002,3 +0.66416667,0.58742857,0.796,0.7864,2541,4/8/2021 15:36,female,1,2002,3 +0.84092308,0.68827273,0.88783333,0.83785714,2542,4/17/2021 18:16,female,1,2001,4 +0.603,0.851,0.79585714,0.84614286,2542,4/17/2021 18:19,female,1,2001,4 +0.96077778,0.9336,1.6605,1.39966667,2542,4/7/2021 10:35,female,1,2001,4 +2.502,3.073,3.16433333,2.48666667,2544,4/13/2021 21:10,female,1,2001,3 +1.84333333,2.44233333,2.0635,2.3656,2544,4/13/2021 22:21,female,1,2001,3 +2.434,3.546,2.988,2.81033333,2544,4/13/2021 21:10,female,1,2001,3 +1.54925,2.41525,1.71066667,1.89725,2544,4/13/2021 22:22,female,1,2001,3 +0.9495,0.91971429,1.187,0.8866,2544,4/11/2021 16:15,female,1,2001,3 +1.9862,2.64966667,2.956,3.9375,2544,4/13/2021 21:41,female,1,2001,3 +0.750125,0.97722222,0.73966667,0.6815,2544,4/11/2021 16:16,female,1,2001,3 +1.7865,1.89857143,2.27,4.016,2544,4/13/2021 21:42,female,1,2001,3 +0.71836364,0.75855556,0.56341667,0.62676923,2545,4/7/2021 10:35,male,1,2001,5 +0.68166667,0.669,0.5825,0.732875,2545,4/8/2021 12:31,male,1,2001,5 +0.92877778,0.95557143,0.8588,0.82385714,2546,4/7/2021 10:40,female,1,2002,3 +0.66463636,0.919,0.72425,0.68488889,2546,4/7/2021 18:30,female,1,2002,3 +0.62792308,0.861,0.5186,0.7965,2547,4/20/2021 22:07,male,1,2001,1 +0.608875,0.5334,0.58007692,0.7074,2547,4/20/2021 22:07,male,1,2001,1 +1.2665,0.91666667,2.70425,1.1936,2549,4/7/2021 10:35,female,1,2001,3 +0.85642857,1.2882,1.27033333,1.158625,2549,4/17/2021 19:13,female,1,2001,3 +1.0794,0.89144444,1.9086,1.099,2549,4/17/2021 19:13,female,1,2001,3 +0.73892857,0.867875,1.07657143,0.9916,2550,4/20/2021 16:49,female,1,1998,3 +1.44933333,0.68854545,1.151,0.92571429,2550,4/7/2021 11:00,female,1,1998,3 +1.93333333,1.22,1.47985714,0.8738,2551,4/7/2021 10:52,female,0,2001,3 +1.17833333,0.96218182,0.80790909,0.80725,2551,4/7/2021 11:05,female,0,2001,3 +0.73644444,0.62538462,0.77725,0.727875,2552,4/19/2021 14:39,female,1,2001,3 +0.6775,0.618,0.77254545,0.91671429,2552,4/19/2021 14:29,female,1,2001,3 +6.823,6.373,4.993,4.0125,2554,4/7/2021 12:33,male,1,1946,1 +1.212,0.92166667,0.774,1.022,2555,4/7/2021 12:35,female,1,1972,3 +1.1845,0.9674,1.348,0.923,2555,4/7/2021 12:35,female,1,1972,3 +1.06257143,1.09342857,1.0526,1.20685714,2556,4/7/2021 14:20,female,1,2001,3 +0.805125,1.125125,0.821,1.02145455,2556,4/7/2021 14:30,female,1,2001,3 +1.408,1.7584,1.37042857,2.236,2557,4/7/2021 15:00,female,1,1973,2 +2.536,2.3885,1.83071429,1.5875,2557,4/7/2021 14:46,female,1,1973,2 +2.536,2.3885,1.83071429,1.5875,2557,4/7/2021 14:46,female,1,1973,2 +0.81333333,0.75445455,1.0305,0.93081818,2558,4/18/2021 22:57,male,1,2001,3 +0.8701,0.96042857,0.80857143,0.67038462,2558,4/18/2021 22:57,male,1,2001,3 +0.80842857,0.89677778,0.82655556,0.8269,2559,4/7/2021 15:56,female,1,2001,2 +0.935125,0.9785,0.8,0.95866667,2559,4/7/2021 15:39,female,1,2001,2 +0.732,0.75816667,0.71408333,0.46544444,2560,4/7/2021 15:49,male,1,1995,3 +0.7236,0.87,0.8415,0.84055556,2561,4/14/2021 23:25,male,0,2001,3 +0.759,0.9905,0.90741667,1.00966667,2561,4/7/2021 16:09,male,0,2001,3 +0.67357143,0.93485714,0.92444444,0.92672727,2561,4/7/2021 16:10,male,0,2001,3 +0.64671429,0.67975,0.7162,0.594,2562,4/18/2021 22:20,female,1,2001,3 +0.77475,0.63311765,0.78271429,0.61081818,2562,4/18/2021 22:21,female,1,2001,3 +0.77475,0.63311765,0.78271429,0.61081818,2562,4/18/2021 22:21,female,1,2001,3 +1.02225,1.044,0.952375,0.79966667,2564,4/7/2021 16:43,female,1,2001,4 +0.707,0.9186,0.79445455,0.76675,2564,4/7/2021 17:19,female,1,2001,4 +0.71773333,0.753125,0.728,0.6644,2565,4/7/2021 16:49,male,1,2002,4 +1.39966667,1.23228571,0.99466667,1.43025,2566,4/15/2021 10:18,female,1,1980,3 +0.90963636,1.21885714,0.962,1.206,2566,4/15/2021 10:19,female,1,1980,3 +1.39966667,1.23228571,0.99466667,1.43025,2566,4/15/2021 10:18,female,1,1980,3 +0.5825,0.7815,0.67166667,0.77591667,2571,4/7/2021 20:29,male,1,2001,3 +0.73933333,0.67928571,0.89042857,0.83742857,2571,4/7/2021 20:45,male,1,2001,3 +0.95442857,0.79436364,0.6386,0.7174,2573,4/7/2021 20:54,male,1,1968,3 +0.80622222,0.722,0.79755556,0.734,2573,4/7/2021 20:55,male,1,1968,3 +1.1115,1.21477778,1.027,1.0575,2574,4/7/2021 21:00,female,1,1998,3 +1.6016,1.08171429,1.051,1.12333333,2574,4/20/2021 21:05,female,1,1998,3 +3.981,2.0125,2.05666667,2.19566667,2575,4/7/2021 21:13,female,1,1968,2 +1.579,2.4104,1.28833333,1.49825,2575,4/7/2021 21:13,female,1,1968,2 +0.5681875,0.62178571,0.69277778,0.64455556,2576,4/7/2021 21:19,male,1,2000,3 +0.51673333,0.50871429,0.60957143,0.61377778,2576,4/7/2021 21:20,male,1,2000,3 +1.984,1.7918,1.60966667,1.674,2577,4/7/2021 21:34,male,0,1970,1 +1.16016667,1.1289,1.3385,1.22766667,2577,4/7/2021 21:34,male,0,1970,1 +0.66177778,0.5865,0.79969231,0.9504,2579,4/7/2021 21:48,male,1,1972,3 +0.6325,0.641,0.687875,0.88075,2579,4/7/2021 21:48,male,1,1972,3 +2.148,1.7765,1.7968,2.65933333,2580,4/8/2021 12:53,female,1,1954,2 +1.319,1.592,1.52685714,1.9132,2580,4/8/2021 12:54,female,1,1954,2 +1.555,1.01,1.18857143,1.00733333,2581,4/8/2021 13:36,female,1,1976,4 +1.4426,1.3695,2.01466667,1.376,2581,4/8/2021 13:34,female,1,1976,4 +1.133,1.962,1.018,0.893,2583,4/8/2021 14:43,female,1,1951,2 +0.6852,0.7754,0.8055,0.8295,2584,4/8/2021 15:16,female,0,1965,3 +0.503,0.753,0.811,0.61733333,2584,4/8/2021 15:16,female,0,1965,3 +0.605,0.7122,0.6582,0.70355556,2586,4/8/2021 15:30,male,0,1970,4 +0.62585714,0.6865,0.69238462,0.59663636,2586,4/8/2021 15:30,male,0,1970,4 +0.969,0.981,1.009,1.618,2587,4/8/2021 15:40,male,1,1970,3 +3.668,3.812,5.99,1.506,2588,4/8/2021 15:57,female,1,1950,1 +6.115,6.1735,2.624,2.6095,2588,4/8/2021 15:56,female,1,1950,1 +1.10125,1.09366667,1.34228571,1.538625,2589,4/8/2021 17:10,male,1,2001,4 +0.88792308,0.68533333,0.85133333,0.8448,2589,4/8/2021 17:27,male,1,2001,4 +0.70155556,0.821625,0.80428571,0.84392308,2590,4/8/2021 21:04,male,1,2001,1 +1.2615,1.0275,0.89188889,1.05411111,2590,4/8/2021 21:03,male,1,2001,1 +1.7975,1.52425,1.28155556,2.59,2591,4/8/2021 21:24,female,1,1976,1 +1.606,2.4162,0.8205,1.818,2591,4/8/2021 21:25,female,1,1976,1 +1.65025,1.6218,1.7214,1.38125,2592,4/8/2021 21:52,female,1,1958,1 +1.3812,1.5625,1.107,1.3779,2592,4/8/2021 21:51,female,1,1958,1 +1.0009,0.87585714,1.007,1.31225,2594,4/8/2021 22:36,male,1,1977,1 +0.996,0.7994,0.939375,1.1221,2594,4/8/2021 22:37,male,1,1977,1 +1.5775,1.5625,1.528,1.5245,2595,4/8/2021 23:04,female,1,1952,1 +1.63225,1.68816667,1.44725,2.17533333,2595,4/8/2021 23:03,female,1,1952,1 +0.85357143,1.1298,1.1438,1.0438,2597,4/8/2021 23:40,female,1,1980,4 +0.999125,0.8435,0.952,1.1265,2597,4/8/2021 23:40,female,1,1980,4 +0.7709,0.7825,0.842,0.63223077,2598,4/9/2021 14:26,female,1,2001,3 +0.95254545,0.69563636,0.8512,0.689375,2598,4/9/2021 13:46,female,1,2001,3 +1.04266667,1.357125,1.3754,1.3115,2599,4/17/2021 18:15,male,1,1977,2 +1.21116667,1.1524,1.3026,1.283,2599,4/21/2021 9:58,male,1,1977,2 +1.1372,1.442625,0.976375,1.11075,2600,4/9/2021 19:13,male,1,1970,3 +0.985,0.94633333,1.1535,1.03654545,2600,4/9/2021 19:15,male,1,1970,3 +1.1372,1.442625,0.976375,1.11075,2600,4/9/2021 19:13,male,1,1970,3 +0.6155,0.66466667,0.83833333,0.64233333,2601,4/18/2021 0:42,male,1,2001,3 +0.6155,0.66466667,0.83833333,0.64233333,2601,4/18/2021 0:42,male,1,2001,3 +1.31477778,1.06742857,1.253,0.968375,2601,4/9/2021 22:40,male,1,2001,3 +0.81375,0.886,0.7683,0.62683333,2601,4/13/2021 12:08,male,1,2001,3 +1.1735,1.504,1.13785714,1.788,2602,4/11/2021 10:31,male,1,1976,2 +2.14933333,1.51233333,1.7345,1.48075,2602,4/11/2021 10:32,male,1,1976,2 +3.662,3.3986,1.209,5.937,2603,4/11/2021 11:00,female,1,1977,2 +2.01133333,2.2285,2.566,2.037,2603,4/11/2021 11:00,female,1,1977,2 +1.482,1.534,1.4175,1.4905,2605,4/12/2021 11:19,female,1,1955,1 +1.7135,1.2284,1.05342857,1.2752,2605,4/12/2021 11:20,female,1,1955,1 +1.0368,1.587,1.0717,1.016875,2606,4/12/2021 11:46,male,1,1975,5 +0.80042857,1.191,0.628375,0.71230769,2606,4/12/2021 11:47,male,1,1975,5 +1.8215,1.5868,1.4914,1.605,2608,4/12/2021 14:16,female,1,1958,3 +1.6578,1.7302,1.74475,1.70766667,2608,4/12/2021 14:17,female,1,1958,3 +1.623,1.67375,1.4176,1.34475,2609,4/12/2021 14:33,male,1,1956,3 +1.71566667,1.87,1.47033333,1.7164,2609,4/12/2021 14:34,male,1,1956,3 +0.67990909,0.77728571,0.73922222,0.67073333,2610,4/12/2021 15:06,male,1,1979,2 +0.82411111,0.67890909,0.87616667,0.77408333,2610,4/12/2021 15:06,male,1,1979,2 +0.66433333,0.7336,0.7505,0.94533333,2611,4/12/2021 15:29,male,1,1964,3 +1.47157143,1.54233333,1.39716667,1.538,2612,4/12/2021 15:43,female,1,1956,3 +1.65383333,1.34385714,1.002,1.411,2612,4/12/2021 15:43,female,1,1956,3 +2.15366667,1.39933333,1.272,1.3316,2613,4/12/2021 16:36,female,1,1957,2 +1.41333333,1.34975,1.3755,1.60071429,2613,4/12/2021 16:35,female,1,1957,2 +1.37622222,1.16642857,1.231,1.1416,2614,4/12/2021 18:41,male,1,1973,4 +0.79928571,0.92163636,0.91466667,0.73957143,2614,4/12/2021 20:53,male,1,1973,4 +0.65,0.69933333,0.64316667,0.57014286,2615,4/12/2021 20:50,male,1,2001,4 +0.746,0.709,0.73458333,0.61333333,2615,4/12/2021 20:32,male,1,2001,4 +1.301,1.4565,1.551,1.28225,2616,4/12/2021 21:07,female,1,1981,2 +1.048625,1.24085714,1.2482,1.84633333,2616,4/12/2021 21:08,female,1,1981,2 +3.764,3.386,3.404,3.9925,2617,4/12/2021 21:31,male,1,1942,2 +2.895,2.6765,2.552,2.408,2617,4/12/2021 21:17,male,1,1942,2 +1.554,1.7966,1.475625,1.701,2618,4/12/2021 21:31,male,1,1948,1 +1.417,1.299,1.1795,1.56883333,2618,4/12/2021 21:32,male,1,1948,1 +2.26,1.621,2.25225,1.6154,2620,4/17/2021 23:15,male,1,1976,3 +1.9456,1.842,2.2886,1.628,2620,4/12/2021 21:40,male,1,1976,3 +1.60825,1.8102,1.7405,1.6915,2621,4/12/2021 22:00,male,1,1955,3 +1.4355,1.476375,1.47133333,1.60933333,2621,4/12/2021 22:01,male,1,1955,3 +0.91933333,0.8916,0.8868,1.06466667,2622,4/12/2021 22:59,male,1,2001,3 +0.899875,0.911,0.94858333,1.11166667,2622,4/12/2021 22:58,male,1,2001,3 +2.66175,1.26575,1.777,1.73516667,2623,4/13/2021 12:08,female,1,2001,2 +1.144,1.094,1.30425,0.92833333,2623,4/13/2021 12:20,female,1,2001,2 +2.69,3.22666667,2.9405,2.52575,2625,4/17/2021 23:06,female,1,1965,3 +4.778,6.587,5.9665,6.171,2625,4/13/2021 14:10,female,1,1965,3 +1.26266667,1.30625,1.4245,1.07371429,2626,4/13/2021 16:46,male,1,1996,3 +3.115,2.679,3.23966667,2.30066667,2627,4/13/2021 18:15,female,1,1949,1 +2.64125,2.142,2.2415,1.9284,2627,4/13/2021 18:16,female,1,1949,1 +1.57866667,2.057,1.7026,1.578,2628,4/13/2021 18:29,female,0,1957,2 +1.06728571,1.6205,1.693,1.1604,2628,4/13/2021 18:30,female,0,1957,2 +4.05,2.437,3.71666667,2.205,2629,4/13/2021 18:53,male,1,1941,1 +1.9645,2.1718,2.3542,1.692,2629,4/13/2021 18:54,male,1,1941,1 +1.4804,1.21333333,1.08316667,1.05075,2630,4/13/2021 22:40,female,1,1978,3 +0.894,0.97322222,1.06688889,0.8626,2630,4/13/2021 22:41,female,1,1978,3 +1.24814286,1.5505,1.53983333,1.394,2631,4/13/2021 22:09,male,1,1976,2 +0.93175,1.375375,0.99333333,0.87016667,2631,4/13/2021 22:11,male,1,1976,2 +0.961,1.11214286,1.291,1.01266667,2632,4/14/2021 23:04,male,1,1967,2 +0.799125,1.1615,1.1512,0.84816667,2632,4/14/2021 23:05,male,1,1967,2 +0.98166667,0.94314286,0.98511111,0.8117,2633,4/14/2021 20:52,female,1,1972,3 +0.80657143,0.93222222,0.78409091,0.69544444,2633,4/14/2021 20:52,female,1,1972,3 +0.97925,0.78084615,0.74636364,0.7482,2634,4/14/2021 22:32,male,1,1970,3 +0.70323077,0.65966667,0.76190909,0.834,2634,4/14/2021 22:33,male,1,1970,3 +1.64375,2.2245,1.672,1.527,2635,4/13/2021 20:42,male,1,1973,1 +2.983,3.504,3.81333333,3.513,2635,4/18/2021 17:50,male,1,1973,1 +1.08177778,0.92771429,1.10914286,0.93733333,2636,4/13/2021 21:14,male,1,1979,3 +1.00277778,1.11966667,1.54225,0.951625,2636,4/13/2021 21:14,male,1,1979,3 +1.811,1.747,1.5416,2.1178,2637,4/13/2021 22:04,female,1,1958,5 +1.624375,1.2915,1.05775,1.8045,2637,4/14/2021 12:04,female,1,1958,5 +1.385,1.62733333,1.639,1.98166667,2638,4/19/2021 0:22,male,1,1970,2 +1.65375,1.7152,1.77025,1.4404,2638,4/13/2021 23:27,male,1,1970,2 +1.48933333,1.41242857,1.6238,1.04657143,2639,4/13/2021 23:44,female,0,1971,4 +1.0116,0.98288889,0.99344444,0.868125,2639,4/18/2021 0:26,female,0,1971,4 +0.86275,1.077625,1.3296,0.9055,2640,4/14/2021 11:37,female,1,1974,3 +0.928,1.1946,1.11742857,0.92027273,2640,4/14/2021 11:37,female,1,1974,3 +1.14233333,1.07971429,1.30011111,0.99914286,2641,4/14/2021 11:49,male,1,1966,3 +0.77275,0.65788235,1.0314,1.05085714,2641,4/14/2021 11:49,male,1,1966,3 +1.293,1.15575,1.6225,0.95325,2641,4/14/2021 11:50,male,1,1966,3 +0.80063636,1.10285714,1.322,1.23316667,2643,4/14/2021 12:04,male,1,1964,3 +1.342,1.67975,2.28366667,1.1132,2644,4/14/2021 12:22,female,1,1971,3 +0.95066667,1.065,1.0035,0.9399,2644,4/14/2021 12:24,female,1,1971,3 +0.842875,0.90985714,0.90744444,0.78145455,2646,4/14/2021 12:41,female,1,1969,3 +0.951,0.90475,1.06371429,0.864875,2646,4/14/2021 12:41,female,1,1969,3 +2.113,2.00875,1.4608,1.80883333,2648,4/14/2021 12:59,male,1,1959,3 +1.7534,2.07666667,1.5895,1.779,2650,4/14/2021 13:19,female,1,1975,2 +1.96925,1.224,1.7014,1.50383333,2650,4/14/2021 13:20,female,1,1975,2 +0.83725,0.819625,0.85522222,0.79045455,2651,4/14/2021 14:08,male,1,2001,3 +0.7696,0.8588,1.0168,0.995875,2651,4/14/2021 14:46,male,1,2001,3 +0.7684,0.76288889,0.73922222,0.90185714,2651,4/20/2021 21:17,male,1,2001,3 +2.2945,2.27033333,2.192,2.851,2653,4/14/2021 13:41,female,1,1950,1 +5.265,4.5835,1.577,3.187,2653,4/14/2021 13:41,female,1,1950,1 +8.51,3.091,4.65,4.782,2654,4/14/2021 13:59,male,1,1951,1 +4.4715,4.497,5.8385,3.729,2654,4/14/2021 14:00,male,1,1951,1 +2.951,4.199,2.854,2.62,2655,4/14/2021 14:12,female,1,1960,1 +1.1225,1.06842857,1.5032,1.3265,2656,4/14/2021 15:01,female,1,1969,2 +0.8845,0.772875,0.9705,1.14444444,2656,4/14/2021 15:02,female,1,1969,2 +2.434,3.79733333,2.1815,1.8586,2657,4/14/2021 15:34,male,1,1973,3 +1.64025,1.70725,1.07888889,1.1715,2657,4/14/2021 15:36,male,1,1973,3 +1.61475,1.847,1.5205,1.4908,2658,4/20/2021 22:02,male,1,1970,3 +3.12433333,4.932,1.16233333,1.452,2658,4/20/2021 22:03,male,1,1970,3 +1.00142857,0.95333333,1.1675,1.00585714,2659,4/14/2021 16:02,male,1,1970,3 +0.91377778,0.7822,0.7161,0.827625,2659,4/14/2021 16:04,male,1,1970,3 +1.1925,1.484,1.642,1.4014,2660,4/14/2021 16:11,female,1,1978,3 +1.126,1.469,1.46185714,1.46566667,2660,4/14/2021 16:12,female,1,1978,3 +3.024,3.60333333,3.2565,4.2205,2662,4/14/2021 16:57,male,1,1946,1 +2.24633333,2.89833333,2.22375,2.2155,2662,4/14/2021 16:59,male,1,1946,1 +0.77683333,0.8775,0.769875,0.76454545,2663,4/18/2021 3:20,female,1,1970,2 +0.83669231,0.80322222,0.69742857,0.714,2663,4/18/2021 3:21,female,1,1970,2 +0.6845,0.6056,0.67445455,0.68,2665,4/14/2021 17:20,male,1,2001,4 +0.54745,0.548125,0.8522,0.66788889,2665,4/14/2021 17:21,male,1,2001,4 +0.7635,1.00641667,0.72109091,0.82983333,2666,4/18/2021 21:57,male,1,1960,2 +0.83983333,0.77536364,0.907,0.6023,2666,4/18/2021 21:58,male,1,1960,2 +0.65822222,1.041,1.28766667,1.18166667,2667,4/18/2021 2:50,male,1,1973,3 +1.17575,1.00875,0.619875,1.3578,2668,4/18/2021 21:46,female,1,1978,3 +0.9193,0.76964286,0.71233333,0.54416667,2668,4/18/2021 21:45,female,1,1978,3 +11.071,1.5505,1.19166667,1.2815,2669,4/17/2021 19:45,female,1,2001,3 +1.063875,1.32575,2.409,1.155,2669,4/17/2021 19:46,female,1,2001,3 +0.75744444,0.93957143,0.89781818,2.18333333,2670,4/14/2021 17:39,male,1,1968,3 +0.68688889,0.7554,0.7647,0.74972727,2670,4/14/2021 17:38,male,1,1968,3 +0.63878571,0.85754545,0.6805,0.682,2671,4/18/2021 21:16,female,1,1965,3 +0.801,0.67413333,1.058125,0.6513,2671,4/18/2021 21:16,female,1,1965,3 +0.70344444,0.69490909,0.874875,1.105875,2673,4/18/2021 22:09,female,1,1968,3 +0.65566667,0.90425,0.973,0.67236364,2673,4/18/2021 22:08,female,1,1968,3 +0.93858333,0.90571429,0.70307692,0.6314,2674,4/18/2021 3:06,male,1,1972,2 +0.72577778,1.15588889,0.9048,0.91244444,2674,4/18/2021 3:07,male,1,1972,2 +1.07185714,1.0002,0.85357143,1.1399,2675,4/14/2021 17:53,female,0,1975,3 +1.03666667,0.98375,1.2162,0.97557143,2675,4/14/2021 17:53,female,0,1975,3 +0.888,1.46283333,0.9355,0.8444,2676,4/17/2021 21:06,male,1,2003,3 +0.728875,0.9298,0.78418182,0.79428571,2676,4/17/2021 21:06,male,1,2003,3 +3.262,5.459,2.384,3.111,2677,4/14/2021 18:13,female,1,1943,1 +2.445,2.52766667,4.244,5.776,2677,4/14/2021 18:16,female,1,1943,1 +1.68,5.931,4.277,1.728,2677,4/14/2021 18:17,female,1,1943,1 +3.087,5.407,3.83166667,3.1355,2677,4/14/2021 18:12,female,1,1943,1 +1.11628571,1.3172,1.49733333,1.08166667,2678,4/14/2021 18:37,female,0,1981,2 +1.418,1.4915,1.43114286,1.21216667,2678,4/14/2021 18:36,female,0,1981,2 +1.328,1.397,1.60314286,1.6382,2679,4/14/2021 18:47,male,1,1976,3 +1.228,0.82975,1.3425,1.202,2679,4/14/2021 18:47,male,1,1976,3 +1.2325,1.57342857,1.80225,1.28975,2680,4/14/2021 19:06,female,1,1959,2 +1.42525,1.8855,2.447,2.1385,2680,4/14/2021 19:04,female,1,1959,2 +2.30875,2.375,2.251,2.461,2681,4/14/2021 19:01,male,1,1974,2 +1.66625,1.8435,2.6362,1.87466667,2681,4/14/2021 19:02,male,1,1974,2 +1.0855,0.93054545,1.1954,1.428,2682,4/14/2021 19:30,female,1,1980,2 +1.34683333,1.081,1.62175,1.5585,2682,4/14/2021 19:29,female,1,1980,2 +3.393,2.61725,2.54875,1.38266667,2683,4/14/2021 19:42,male,1,1976,2 +4.486,3.4395,2.061,4.88533333,2683,4/21/2021 10:34,male,1,1976,2 +3.273,2.81333333,1.965,1.51933333,2684,4/21/2021 10:49,female,1,1976,2 +1.625,1.643,1.38375,1.341,2684,4/14/2021 19:57,female,1,1976,2 +3.981,1.95233333,1.2365,1.119,2685,4/14/2021 20:02,female,1,1951,2 +1.61533333,2.12566667,1.81533333,1.045,2685,4/14/2021 20:03,female,1,1951,2 +2.883,3.19566667,2.9865,2.8085,2686,4/14/2021 20:08,female,1,1959,1 +2.804,4.036,3.965,3.4215,2686,4/14/2021 20:08,female,1,1959,1 +4.454,1.214,8.924,2.165,2688,4/21/2021 10:42,male,1,1979,2 +3.757,3.0395,3.08966667,2.392,2689,4/14/2021 20:28,male,1,1949,1 +5.472,3.806,5.449,2.93666667,2689,4/21/2021 17:23,male,1,1949,1 +1.5948,1.52525,1.56025,1.25166667,2690,4/20/2021 21:16,female,1,1977,5 +2.77925,1.08233333,2.12275,1.1565,2691,4/14/2021 20:39,female,1,1989,4 +1.8345,1.1408,2.188,1.9078,2691,4/14/2021 20:50,female,1,1989,4 +3.85,3.465,2.543,4.147,2692,4/22/2021 15:36,female,0,1971,2 +1.9085,2.3115,2.99525,1.43966667,2692,4/21/2021 17:08,female,0,1971,2 +1.43133333,1.353,3.54466667,2.49666667,2693,4/21/2021 17:20,male,1,1971,2 +2.97433333,2.5425,2.286,3.7985,2693,4/22/2021 19:07,male,1,1971,2 +2.60233333,2.324,2.89766667,6.213,2694,4/14/2021 21:04,female,1,1963,2 +6.455,6.886,6.183,7.553,2694,4/21/2021 17:32,female,1,1963,2 +8.826,4.134,4.038,5.21,2695,4/22/2021 18:56,male,1,1939,1 +1.71633333,2.5505,2.0895,1.134,2696,4/14/2021 21:41,male,1,1974,2 +1.114,1.92914286,1.94366667,1.0144,2696,4/14/2021 21:42,male,1,1974,2 +1.049125,1.17242857,1.1364,1.268,2697,4/15/2021 17:56,female,1,1949,1 +0.7535,1.08988889,0.95625,0.94878571,2697,4/15/2021 17:55,female,1,1949,1 +0.88822222,2.92,1.1278,1.3428,2698,4/16/2021 12:05,male,1,1948,1 +0.8243,0.9565,1.04011111,0.9995,2698,4/15/2021 18:04,male,1,1948,1 +0.89357143,0.941,1.4145,1.2785,2698,4/15/2021 18:05,male,1,1948,1 +0.82833333,1.19377778,1.01625,1.4015,2698,4/16/2021 12:04,male,1,1948,1 +1.3934,1.17183333,1.0275,1.621625,2699,4/15/2021 11:19,female,1,1955,1 +1.01311111,1.52533333,1.0345,1.235,2699,4/15/2021 17:47,female,1,1955,1 +2.1705,2.98225,2.029,1.74433333,2700,4/15/2021 11:38,female,1,1954,1 +2.848,2.696,4.413,2.543,2700,4/15/2021 11:37,female,1,1954,1 +2.627,1.644,4.1315,4.51,2701,4/15/2021 12:59,female,1,1961,1 +11.852,2.123,2.845,3.709,2701,4/15/2021 13:00,female,1,1961,1 +2.666,2.237,2.575,7.631,2703,4/15/2021 13:20,female,1,1959,1 +6.919,7.217,7.042,3.666,2703,4/15/2021 13:18,female,1,1959,1 +3.8505,1.866,1.13525,2.0558,2704,4/15/2021 13:29,male,1,1945,2 +2.169,4.607,2.644,1.6794,2704,4/15/2021 13:30,male,1,1945,2 +1.604,1.50628571,2.2,1.71125,2705,4/15/2021 14:19,male,1,1951,2 +1.3425,1.7685,1.4465,1.50133333,2705,4/15/2021 14:18,male,1,1951,2 +1.9105,1.61116667,1.338,1.82883333,2706,4/15/2021 14:31,female,1,1948,3 +1.21457143,1.6156,1.278,2.15,2706,4/15/2021 14:48,female,1,1948,3 +1.734,1.98475,1.911,1.874,2707,4/15/2021 15:11,male,1,1948,2 +2.17733333,1.74016667,2.00175,2.0875,2707,4/15/2021 15:10,male,1,1948,2 +0.98057143,0.9176,0.81488889,0.839,2708,4/15/2021 15:32,male,1,1970,5 +0.94171429,0.65407692,0.93775,0.7349,2708,4/15/2021 15:32,male,1,1970,5 +0.886,0.8992,1.176,1.3392,2709,4/15/2021 15:48,male,1,1962,2 +2.781,1.133,2.611,2.584,2709,4/15/2021 15:47,male,1,1962,2 +2.18925,2.356,1.17966667,1.27766667,2712,4/15/2021 16:04,female,1,1972,3 +0.9355,1.077,0.76615385,1.0528,2713,4/15/2021 16:03,female,1,1981,4 +0.92133333,0.70227273,0.72241667,1.11857143,2713,4/15/2021 16:04,female,1,1981,4 +7.15,3.3075,2.692,2.4535,2714,4/17/2021 20:08,female,1,1947,3 +2.291,2.64,3.34133333,2.628,2714,4/17/2021 20:08,female,1,1947,3 +1.48716667,1.90233333,1.99925,1.70525,2715,4/15/2021 16:18,female,1,1947,3 +2.611,1.5042,1.7215,1.82425,2715,4/15/2021 16:18,female,1,1947,3 +1.29416667,1.3815,1.1705,1.43771429,2717,4/15/2021 17:21,male,1,1971,2 +1.181,1.68533333,1.0624,2.4288,2717,4/15/2021 17:22,male,1,1971,2 +1.558,2.01633333,1.50566667,1.70683333,2718,4/15/2021 18:42,male,1,1972,3 +1.33628571,1.273,1.42275,1.305,2718,4/15/2021 18:42,male,1,1972,3 +1.25566667,1.175,1.1376,1.22966667,2719,4/15/2021 19:15,male,1,1970,2 +1.42028571,1.16671429,1.40075,1.119,2719,4/15/2021 19:15,male,1,1970,2 +1.3524,1.3165,1.33,1.19477778,2721,4/15/2021 19:37,male,1,1971,2 +1.30828571,1.57066667,1.22325,1.0366,2721,4/15/2021 19:37,male,1,1971,2 +3.004,2.7385,2.4374,1.4985,2722,4/15/2021 20:15,female,1,1956,2 +1.83866667,2.362,2.29166667,1.87725,2722,4/15/2021 20:16,female,1,1956,2 +1.49025,1.24771429,1.69633333,1.55033333,2723,4/15/2021 20:33,male,1,1959,2 +0.9972,1.2095,1.35814286,1.396,2723,4/15/2021 20:34,male,1,1959,2 +0.959,0.854125,1.32244444,0.9644,2724,4/15/2021 21:22,male,1,1971,4 +0.9965,0.7164,1.04433333,0.8282,2724,4/15/2021 21:22,male,1,1971,4 +2.894,3.259,1.11528571,2.7525,2725,4/15/2021 22:43,male,1,1952,2 +2.63966667,2.21,2.664,2.83766667,2725,4/15/2021 22:46,male,1,1952,2 +2.5915,2.994,4.385,3.355,2726,4/15/2021 23:14,female,0,1963,3 +1.9696,2.25033333,2.513,3.769,2726,4/15/2021 23:16,female,0,1963,3 +0.55836364,0.53661538,0.72123077,0.51757143,2727,4/16/2021 0:09,female,1,2002,3 +0.6135,0.603,1.055,0.5168,2727,4/16/2021 0:10,female,1,2002,3 +2.93,4.6145,3.6315,4.347,2729,4/16/2021 10:21,male,1,1955,1 +2.93,4.6145,3.6315,4.347,2729,4/16/2021 10:21,male,1,1955,1 +0.895,0.70481818,0.75192308,0.64908333,2730,4/20/2021 18:54,female,1,2001,3 +0.87028571,1.18642857,1.17242857,1.012,2730,4/16/2021 10:24,female,1,2001,3 +1.06375,0.95514286,1.15171429,0.86942857,2730,4/16/2021 10:37,female,1,2001,3 +1.8198,1.6282,1.7195,1.4562,2731,4/16/2021 10:48,male,1,1974,3 +1.925,1.8934,1.3805,1.09533333,2731,4/16/2021 11:05,male,1,1974,3 +1.85233333,1.34457143,1.92683333,1.5215,2732,4/16/2021 11:04,male,1,1959,3 +2.14233333,1.646,2.08,1.7282,2732,4/16/2021 11:03,male,1,1959,3 +6.087,2.838,1.96675,2.90833333,2734,4/16/2021 11:28,female,1,1959,2 +6.087,2.838,1.96675,2.90833333,2734,4/16/2021 11:28,female,1,1959,2 +2.234,2.684,2.5155,2.0876,2734,4/16/2021 11:29,female,1,1959,2 +1.4908,0.87383333,0.97116667,1.373125,2735,4/16/2021 11:41,male,1,1996,4 +0.692,0.55392308,0.75784615,0.61721429,2735,4/16/2021 11:49,male,1,1996,4 +0.96366667,0.8305,1.09383333,1.2385,2736,4/16/2021 12:15,male,1,1976,3 +0.833,1.0725,1.1636,1.2325,2736,4/16/2021 12:16,male,1,1976,3 +2.35,6.296,4.789,5.746,2737,4/16/2021 12:08,female,1,1954,1 +2.284,5.44,4.034,3.976,2737,4/16/2021 12:09,female,1,1954,1 +2.63,2.249,3.01,2.34675,2738,4/16/2021 17:20,female,1,1972,3 +2.075,1.81666667,1.87,1.76357143,2738,4/20/2021 18:23,female,1,1972,3 +0.697,0.81475,1.07028571,0.86363636,2740,4/16/2021 17:45,male,1,1967,3 +0.9312,1.118125,1.37528571,1.184,2740,4/20/2021 17:56,male,1,1967,3 +0.9405,1.718,1.8275,1.3036,2740,4/20/2021 17:57,male,1,1967,3 +0.9864,1.454,1.57488889,1.03633333,2742,4/16/2021 17:55,female,1,1966,2 +2.26,1.8336,1.58,1.18514286,2742,4/16/2021 17:53,female,1,1966,2 +2.05033333,1.834,2.15125,1.35475,2743,4/16/2021 19:23,male,1,1972,4 +1.12275,1.17,1.66633333,1.41,2743,4/16/2021 19:23,male,1,1972,4 +1.325,1.3534,1.30233333,1.38833333,2744,4/16/2021 19:33,male,1,1970,2 +3.04925,2.138,1.507,2.18216667,2744,4/16/2021 19:32,male,1,1970,2 +1.29671429,2.09825,1.4854,2.0195,2745,4/16/2021 19:41,female,1,1979,3 +1.05166667,1.179,1.4466,1.233125,2745,4/16/2021 19:42,female,1,1979,3 +1.1356,1.6176,1.66,1.919,2746,4/16/2021 20:06,female,1,1970,1 +3.58666667,1.715,2.1585,2.158,2746,4/16/2021 20:05,female,1,1970,1 +2.0805,1.853,1.593,1.65033333,2747,4/16/2021 20:26,male,1,1965,2 +0.9755,1.36333333,1.787,1.729,2747,4/20/2021 18:01,male,1,1965,2 +0.827,1.0235,0.79569231,0.8425,2748,4/20/2021 17:31,male,1,1997,4 +1.10942857,1.47383333,1.31025,1.25116667,2749,4/18/2021 14:18,female,1,1955,2 +0.929,1.17583333,1.17842857,0.89383333,2749,4/18/2021 14:19,female,1,1955,2 +1.37757143,1.24914286,1.0825,1.8052,2750,4/16/2021 21:01,female,1,1964,2 +1.0145,1.73,1.163,1.3424,2750,4/20/2021 18:12,female,1,1964,2 +0.900375,1.161875,0.9675,1.02816667,2751,4/16/2021 21:28,female,1,1968,2 +1.29433333,1.9975,2.54625,1.114,2751,4/20/2021 17:46,female,1,1968,2 +2.3198,2.39933333,2.8175,1.73733333,2753,4/17/2021 11:56,male,1,1970,3 +1.91075,2.786,1.9054,1.321,2753,4/20/2021 17:26,male,1,1970,3 +4.873,4.211,2.229,2.431,2754,4/17/2021 13:07,female,1,1952,2 +7.407,4.784,7.307,7.427,2754,4/17/2021 22:19,female,1,1952,2 +1.1394,1.20114286,0.87191667,1.24533333,2756,4/17/2021 13:10,female,1,1957,2 +1.1096,1.11188889,1.27716667,1.11966667,2756,4/17/2021 13:11,female,1,1957,2 +2.1605,4.643,3.72433333,2.099,2758,4/17/2021 13:27,female,1,1971,2 +2.0772,1.7975,2.34133333,2.46033333,2758,4/17/2021 22:11,female,1,1971,2 +2.1075,2.60333333,1.999,2.51233333,2759,4/17/2021 14:47,male,1,1968,2 +2.17275,2.2064,1.5685,1.977,2759,4/17/2021 14:48,male,1,1968,2 +0.72166667,0.70823077,0.74825,0.82111111,2760,4/17/2021 15:00,female,1,1945,1 +0.7519,0.65441667,0.7338,0.7046,2760,4/17/2021 15:00,female,1,1945,1 +2.08075,2.40866667,2.557,1.671,2761,4/20/2021 20:02,female,1,1951,1 +2.142,2.54233333,4.3875,2.92666667,2761,4/20/2021 20:03,female,1,1951,1 +1.28655556,0.98390909,1.2245,0.753,2763,4/17/2021 15:26,female,1,1979,4 +1.6254,0.54025,0.91254545,0.7754,2763,4/17/2021 15:27,female,1,1979,4 +1.559,1.37333333,1.3288,2.9365,2764,4/17/2021 15:30,female,1,1973,3 +1.2135,1.991,1.7935,2.317,2764,4/17/2021 15:30,female,1,1973,3 +0.91614286,0.73563636,0.8895,0.795,2765,4/17/2021 15:41,male,1,1968,3 +0.7672,0.7842,0.882875,1.13866667,2765,4/17/2021 15:42,male,1,1968,3 +1.65766667,1.67383333,1.62375,2.0355,2766,4/17/2021 15:48,male,1,1966,3 +1.362,1.199,1.89866667,1.990625,2766,4/17/2021 15:49,male,1,1966,3 +1.02328571,0.965,1.12975,1.078,2768,4/17/2021 16:03,male,1,1955,2 +0.963625,0.91814286,0.9725,1.09042857,2768,4/17/2021 16:04,male,1,1955,2 +0.91985714,0.71663636,0.704625,1.325,2769,4/17/2021 16:05,male,1,1998,2 +0.8388,0.58166667,0.75776923,0.983875,2769,4/17/2021 16:06,male,1,1998,2 +1.29842857,1.24814286,1.91525,1.33266667,2770,4/17/2021 17:17,male,1,1981,3 +1.00166667,1.15566667,1.82616667,1.171,2770,4/17/2021 17:18,male,1,1981,3 +1.74033333,1.536625,1.64875,1.15875,2771,4/17/2021 17:45,male,1,1964,3 +1.17775,1.849,1.40142857,0.95,2771,4/17/2021 17:46,male,1,1964,3 +1.3,1.65833333,1.4105,2,2772,4/17/2021 17:50,male,1,1950,2 +0.81066667,1.668,1.4684,1.59966667,2772,4/17/2021 17:51,male,1,1950,2 +1.2678,1.2155,1.41775,1.304,2773,4/17/2021 18:06,male,1,1970,2 +1.1415,1.00283333,1.03685714,0.78906667,2773,4/17/2021 18:07,male,1,1970,2 +0.87771429,1.0329,0.9281,0.9285,2774,4/17/2021 18:12,male,1,1959,3 +0.85166667,0.89175,0.76472727,0.9629,2774,4/17/2021 18:13,male,1,1959,3 +0.75966667,0.886,0.97175,0.90353846,2776,4/17/2021 18:20,male,1,1994,5 +0.76127273,0.776,0.81188889,0.71385714,2776,4/17/2021 18:21,male,1,1994,5 +2.2195,2.56775,2.46133333,2.542,2777,4/17/2021 18:28,female,1,1953,2 +1.39575,1.3525,1.932,2.4064,2777,4/17/2021 18:29,female,1,1953,2 +0.9098,1.03375,0.95055556,1.10057143,2778,4/17/2021 18:27,female,1,1968,2 +0.9562,0.6985,1.19025,1.2545,2778,4/17/2021 18:28,female,1,1968,2 +4.678,5.399,3.837,2.046,2779,4/17/2021 18:29,male,1,1951,2 +2.267,5.0535,5.3635,5.248,2779,4/21/2021 10:58,male,1,1951,2 +1.43466667,1.5015,1.21375,1.09711111,2780,4/17/2021 21:40,female,1,1982,2 +1.4276,1.506125,1.09566667,1.09766667,2780,4/17/2021 21:41,female,1,1982,2 +1.141125,1.23828571,1.025,1.221625,2781,4/17/2021 18:40,male,1,1978,3 +1.069625,1.06644444,0.9445,1.1286,2781,4/17/2021 18:40,male,1,1978,3 +4.534,3.05,4.488,3.317,2782,4/17/2021 18:43,female,1,1954,1 +3.5075,5.0265,3.955,2.925,2782,4/22/2021 16:21,female,1,1954,1 +2.28,2.503,1.9342,1.836,2783,4/17/2021 18:45,female,1,1955,2 +1.8405,1.6736,2.00766667,2.155,2783,4/17/2021 18:46,female,1,1955,2 +0.751,1.286,1.36166667,1.536,2784,4/17/2021 18:47,male,1,1973,2 +0.691,1.2925,0.9895,1.421,2784,4/17/2021 18:47,male,1,1973,2 +2.338,2.2775,2.61633333,1.9972,2785,4/17/2021 18:48,female,1,1976,2 +1.3562,3.3715,1.289,1.088625,2785,4/17/2021 18:48,female,1,1976,2 +3.98366667,3.112,3.834,3.21966667,2786,4/17/2021 19:27,male,1,1949,1 +3.094,2.732,3.175,1.84875,2786,4/17/2021 19:28,male,1,1949,1 +1.1256,1.07033333,0.6802,0.706,2788,4/17/2021 19:04,female,0,1980,4 +0.985,0.52516667,0.82333333,0.50571429,2788,4/17/2021 19:05,female,0,1980,4 +1.277,1.8,1.199,0.89,2789,4/17/2021 19:10,female,1,1979,3 +0.652875,0.73063636,0.743625,0.85066667,2791,4/17/2021 19:47,female,1,1998,3 +0.728875,0.561875,0.80008333,0.62533333,2791,4/17/2021 19:59,female,1,1998,3 +1.36633333,1.0995,1.16783333,1.18525,2791,4/17/2021 19:31,female,1,1998,3 +2.64025,2.07925,2.61966667,1.844,2792,4/17/2021 19:41,male,1,1956,3 +1.7756,1.7655,2.09025,2.07925,2792,4/17/2021 19:42,male,1,1956,3 +0.81483333,0.99083333,0.973125,0.9418,2793,4/17/2021 19:41,female,1,2001,3 +0.747,0.99385714,0.68108333,0.90075,2793,4/17/2021 20:12,female,1,2001,3 +1.21442857,1.49066667,1.42325,1.39875,2794,4/17/2021 19:31,female,1,1971,2 +1.262625,1.124,1.36742857,1.10625,2794,4/17/2021 19:32,female,1,1971,2 +0.6721,0.683375,0.834,0.982,2795,4/17/2021 19:40,male,1,1974,4 +0.65018182,0.75376923,0.736,1.04,2795,4/17/2021 19:41,male,1,1974,4 +1.0646,1.0548,1.06833333,0.85342857,2796,4/17/2021 19:43,female,1,1985,2 +0.4754,1.04255556,1.16966667,0.73366667,2796,4/21/2021 11:06,female,1,1985,2 +0.93333333,1.12833333,1.01685714,1.04025,2797,4/17/2021 19:50,male,1,1982,2 +0.6435,0.79272727,0.86169231,0.7975,2797,4/21/2021 11:11,male,1,1982,2 +2.946,1.7278,2.256,3.272,2798,4/17/2021 19:55,male,1,1960,2 +3.456,3.73866667,1.727,5.384,2798,4/17/2021 19:55,male,1,1960,2 +1.5085,2.7308,2.3415,2.1905,2799,4/17/2021 19:58,female,1,1950,2 +2.148,2.528,2.1525,3.4665,2799,4/21/2021 10:32,female,1,1950,2 +1.54666667,1.44857143,5.0335,1.12875,2800,4/17/2021 20:01,female,1,1978,1 +1.555,1.2606,1.48177778,1.17175,2800,4/17/2021 20:01,female,1,1978,1 +0.74683333,0.636625,1.065625,0.908375,2801,4/17/2021 20:07,female,1,1970,3 +0.605,0.96942857,0.74709091,1.014375,2801,4/21/2021 11:32,female,1,1970,3 +0.6383,0.569875,0.57545455,0.568,2802,4/20/2021 17:22,male,1,1999,4 +0.63257143,0.59933333,0.68575,0.59523529,2802,4/17/2021 20:16,male,1,1999,4 +0.662,0.58669231,0.59577778,0.62521429,2802,4/20/2021 17:20,male,1,1999,4 +4.518,1.399,1.45933333,1.7992,2803,4/17/2021 20:16,female,1,1974,3 +0.971,1.244,1.08,1.292,2803,4/17/2021 20:30,female,1,1974,3 +1.25,1.057,1.09414286,1.01055556,2805,4/17/2021 20:24,male,1,1975,2 +1.144,1.07775,1.43225,0.98214286,2805,4/17/2021 20:24,male,1,1975,2 +0.73085714,1.61666667,1.49766667,1.80133333,2806,4/17/2021 20:26,female,0,2003,3 +0.73922222,0.81,0.92835714,1.0134,2806,4/20/2021 20:07,female,0,2003,3 +1.2295,1.2395,1.21833333,1.229,2808,4/18/2021 10:06,male,1,1969,1 +1.075,1.26225,1.137,1.102375,2808,4/18/2021 10:07,male,1,1969,1 +1.10166667,1.19766667,1.42477778,1.2235,2809,4/17/2021 20:41,male,1,1968,3 +1.09685714,1.308,1.2964,0.97016667,2809,4/17/2021 20:42,male,1,1968,3 +1.10271429,1.17466667,1.30925,1.09777778,2810,4/17/2021 20:45,male,1,1970,3 +1.00091667,1.1245,0.93128571,1.31233333,2810,4/17/2021 21:00,male,1,1970,3 +1.51666667,1.29375,1.052,1.26842857,2811,4/17/2021 20:49,male,1,1965,3 +0.95428571,1.202,1.18116667,1.1904,2811,4/17/2021 20:57,male,1,1965,3 +1.3885,1.32466667,1.44925,1.87483333,2812,4/17/2021 21:32,female,1,1961,5 +1.0054,1.02633333,1.62428571,0.91375,2812,4/17/2021 21:33,female,1,1961,5 +2.11566667,2.6875,3.44666667,3.5585,2813,4/17/2021 21:50,male,1,1993,3 +1.3152,2.36775,1.66825,1.2824,2813,4/20/2021 17:41,male,1,1993,3 +0.96044444,1.15166667,1.05666667,1.442,2814,4/17/2021 22:03,male,1,1957,5 +1.17628571,1.1895,1.132,1.0298,2814,4/17/2021 22:04,male,1,1957,5 +1.8395,1.632,1.20244444,2.1726,2815,4/17/2021 22:08,female,1,1960,2 +1.20325,5.693,1.23775,1.1355,2815,4/17/2021 22:08,female,1,1960,2 +0.996,1.13057143,1.00325,1.43033333,2816,4/17/2021 22:55,female,1,1975,3 +0.915125,1.17516667,1.01733333,1.502,2816,4/17/2021 22:56,female,1,1975,3 +0.91325,1.08044444,1.09785714,0.91944444,2817,4/17/2021 22:55,female,1,1961,2 +0.8597,1.06357143,1.066375,0.90316667,2817,4/17/2021 22:56,female,1,1961,2 +1.4925,1.28516667,2.2505,2.17066667,2818,4/17/2021 23:28,male,1,1960,2 +3.341,3.738,2.077,2.853,2818,4/18/2021 3:15,male,1,1960,2 +1.0196,0.9673,1.19316667,0.997125,2819,4/19/2021 13:58,male,1,1980,3 +0.98175,1.14766667,1.082125,0.939,2819,4/19/2021 13:59,male,1,1980,3 +0.73975,0.70885714,0.808,0.916,2821,4/18/2021 10:43,male,1,2006,2 +1.008,0.66281818,0.75333333,0.7703,2821,4/18/2021 10:44,male,1,2006,2 +0.81222222,0.70858333,0.838375,0.82455556,2822,4/18/2021 11:05,female,1,1997,3 +0.66241176,0.61944444,0.958625,0.66325,2822,4/18/2021 11:13,female,1,1997,3 +0.84483333,0.96033333,1.13144444,1.032875,2823,4/18/2021 11:25,male,1,2002,2 +0.66911111,0.6245,0.95885714,0.948,2823,4/18/2021 11:25,male,1,2002,2 +0.83342857,1.00257143,0.87716667,1.08475,2824,4/21/2021 0:45,female,1,2001,3 +0.89225,1.3832,0.74713333,0.932,2824,4/21/2021 1:09,female,1,2001,3 +2.5655,2.1965,1.73625,2.547,2824,4/21/2021 11:57,female,1,2001,3 +1.5148,1.503375,1.26033333,1.61175,2824,4/21/2021 12:29,female,1,2001,3 +1.6364,1.44,1.34933333,1.41071429,2824,4/21/2021 12:59,female,1,2001,3 +0.87442857,0.69815385,0.72716667,0.9775,2824,4/18/2021 11:36,female,1,2001,3 +0.8017,0.805875,0.75244444,0.78345455,2824,4/21/2021 0:46,female,1,2001,3 +0.798,0.813875,1.7558,1.11833333,2824,4/21/2021 1:10,female,1,2001,3 +1.82266667,1.8995,1.64233333,2.2162,2824,4/21/2021 11:58,female,1,2001,3 +1.57625,1.32866667,1.53975,1.8604,2824,4/21/2021 12:30,female,1,2001,3 +1.36,1.216,1.42416667,1.225375,2824,4/21/2021 12:59,female,1,2001,3 +0.74928571,0.6776,0.64933333,0.68244444,2824,4/18/2021 11:37,female,1,2001,3 +0.764875,1.0299,0.69481818,0.80642857,2824,4/21/2021 1:01,female,1,2001,3 +1.20333333,1.2255,1.07022222,1.090375,2824,4/21/2021 11:32,female,1,2001,3 +1.544,1.6976,1.5022,1.556,2824,4/21/2021 12:16,female,1,2001,3 +1.513,1.56175,1.86566667,2.058,2824,4/21/2021 12:44,female,1,2001,3 +0.9954,0.79466667,1.0386,0.81881818,2824,4/18/2021 13:48,female,1,2001,3 +0.74341667,0.66288889,0.68481818,0.64281818,2824,4/21/2021 1:01,female,1,2001,3 +1.40483333,1.47857143,1.07725,1.10483333,2824,4/21/2021 11:33,female,1,2001,3 +1.333,1.388,1.42275,1.3054,2824,4/21/2021 12:17,female,1,2001,3 +2.085,1.72328571,1.662,1.30125,2824,4/21/2021 12:45,female,1,2001,3 +0.64155556,0.65122222,0.7835,0.99008333,2824,4/18/2021 13:49,female,1,2001,3 +0.67411111,1.06777778,0.6711,0.99257143,2825,4/18/2021 12:17,female,1,2001,3 +0.62488889,0.7786,0.7662,1.061,2825,4/18/2021 12:18,female,1,2001,3 +1.58425,1.389,1.5544,1.7076,2826,4/18/2021 13:18,male,1,1972,2 +1.093,1.36225,2.4962,1.513,2826,4/18/2021 13:29,male,1,1972,2 +0.82266667,0.62738462,0.91,0.57507143,2828,4/18/2021 13:32,male,1,2001,4 +0.855,0.54307692,0.80921429,0.52990909,2828,4/18/2021 13:50,male,1,2001,4 +0.69977778,0.69975,0.94263636,0.8828,2829,4/18/2021 13:39,male,1,2001,3 +0.72855556,0.74788889,0.89585714,0.82925,2829,4/21/2021 11:37,male,1,2001,3 +1.186625,1.3444,1.2005,1.2648,2830,4/18/2021 13:45,female,1,1976,2 +1.33128571,1.297,1.32071429,1.2005,2830,4/18/2021 13:56,female,1,1976,2 +2.29325,4.3135,3.553,2.60066667,2831,4/18/2021 13:47,female,1,1962,3 +1.18611111,1.824,1.3195,1.3464,2831,4/18/2021 13:48,female,1,1962,3 +0.625,0.57285714,0.77375,0.85766667,2832,4/18/2021 13:47,male,1,2000,3 +0.628,0.63246667,0.8785,0.82214286,2832,4/21/2021 11:43,male,1,2000,3 +0.778875,0.79153333,0.68671429,0.76544444,2833,4/18/2021 14:05,female,1,1964,3 +0.90661538,0.76914286,0.868,0.7354,2833,4/18/2021 14:16,female,1,1964,3 +1.32825,1.37233333,1.292,1.314,2835,4/18/2021 14:15,female,1,1964,2 +1.4858,1.54933333,1.45257143,1.28983333,2835,4/18/2021 14:16,female,1,1964,2 +1.252,2.3655,1.50133333,1.716875,2836,4/18/2021 14:25,male,1,1960,2 +2.467,1.20571429,2.2838,1.17633333,2837,4/18/2021 14:29,female,1,1975,3 +1.184125,1.04971429,1.187,0.923,2837,4/18/2021 14:30,female,1,1975,3 +0.79428571,0.8137,0.7412,0.90525,2838,4/18/2021 14:47,male,1,1969,3 +0.81016667,0.7330625,0.99366667,0.921,2838,4/18/2021 14:37,male,1,1969,3 +1.15875,1.20266667,1.2857,1.221,2840,4/18/2021 14:49,female,1,1945,2 +1.1766,2.07775,1.12325,1.294375,2840,4/18/2021 14:50,female,1,1945,2 +1.46025,1.9372,1.4995,0.96683333,2841,4/18/2021 14:59,male,1,1970,3 +1.766,1.51133333,1.84125,1.3732,2841,4/18/2021 14:58,male,1,1970,3 +3.3808,0.844,2.358,4.519,2842,4/18/2021 14:50,female,1,1956,1 +2.4768,3.3555,2.20166667,1.552,2842,4/18/2021 14:50,female,1,1956,1 +1.50266667,1.727,1.33866667,1.7414,2843,4/18/2021 15:07,male,1,1968,2 +1.73166667,2.13675,1.98825,2.34,2843,4/18/2021 15:06,male,1,1968,2 +0.93,0.62315385,0.73091667,0.9285,2844,4/18/2021 14:58,female,1,1969,3 +0.59773333,0.7775,0.99033333,0.78166667,2844,4/18/2021 14:58,female,1,1969,3 +1.48825,1.83133333,1.6478,1.62133333,2845,4/18/2021 15:15,male,1,1968,2 +1.768,1.645,1.4725,1.738,2845,4/18/2021 15:15,male,1,1968,2 +1.142125,1.17322222,1.157,1.0358,2846,4/18/2021 15:19,male,1,1968,1 +1.06945455,1.047,1.26366667,1.10533333,2846,4/18/2021 15:20,male,1,1968,1 +1.00833333,0.84377778,1.084,0.79236364,2847,4/18/2021 15:48,female,1,2001,3 +0.79661538,0.62122222,1.02557143,0.771,2847,4/18/2021 15:49,female,1,2001,3 +1.153,1.024,1.0466,1.15871429,2847,4/18/2021 15:50,female,1,2001,3 +0.62772727,0.60808333,0.71833333,0.55083333,2848,4/18/2021 16:30,male,1,1977,5 +0.75725,0.60077778,0.66985714,0.5234,2848,4/18/2021 16:31,male,1,1977,5 +1.22171429,1.11757143,1.37825,1.04328571,2849,4/18/2021 16:32,female,1,1976,2 +1.12266667,1.4662,1.8048,1.231,2849,4/18/2021 16:35,female,1,1976,2 +0.59516667,0.58744444,0.698,0.6457,2851,4/18/2021 16:58,male,1,1979,5 +0.6195,0.62077778,0.80214286,0.62715385,2851,4/18/2021 21:20,male,1,1979,5 +1.8725,1.8725,1.6555,1.41183333,2853,4/18/2021 17:10,male,1,1975,2 +1.305,1.6505,1.616,2.03233333,2853,4/18/2021 17:11,male,1,1975,2 +0.92733333,1.2437,0.92542857,1.22675,2854,4/18/2021 17:21,female,1,2001,3 +0.6995,0.98225,1.10042857,0.77236364,2854,4/18/2021 17:35,female,1,2001,3 +1.7126,2.858,1.716125,1.516,2855,4/18/2021 17:23,male,1,1958,2 +1.5948,2.20466667,2.16925,2.00266667,2855,4/18/2021 17:23,male,1,1958,2 +0.93133333,1.0245,0.69992857,0.8351,2856,4/18/2021 17:18,female,1,1998,3 +0.813,0.9535,0.84566667,0.837,2856,4/18/2021 17:19,female,1,1998,3 +0.7995,1.0318,0.88444444,2.04775,2857,4/18/2021 17:21,female,1,2001,3 +0.7854,1.029125,0.85275,0.86075,2857,4/18/2021 17:35,female,1,2001,3 +0.6937,0.6835,0.60955556,0.90088889,2858,4/18/2021 17:30,male,1,1980,5 +0.9635,0.814875,1.12657143,0.76485714,2858,4/18/2021 21:18,male,1,1980,5 +1.7805,1.719,1.876,2.115,2859,4/18/2021 17:34,female,1,1973,3 +0.88966667,1.04914286,0.88,1.2495,2859,4/18/2021 17:35,female,1,1973,3 +5.195,4.0465,3.577,4.0905,2860,4/18/2021 17:37,male,1,1954,1 +2.984,2.59625,2.657,2.21266667,2860,4/18/2021 17:38,male,1,1954,1 +3.19233333,2.6445,2.632,3.086,2861,4/18/2021 18:00,female,1,1958,2 +2.708,2.704,3.341,3.5725,2861,4/18/2021 20:33,female,1,1958,2 +1.22671429,1.26416667,1.16516667,0.90571429,2862,4/18/2021 18:17,male,1,1966,2 +0.847625,1.01575,0.92657143,1.050625,2862,4/18/2021 18:18,male,1,1966,2 +1.2,1.4265,1.317,2.1235,2863,4/18/2021 18:17,female,1,1974,2 +1.42675,1.17214286,1.02085714,1.6902,2863,4/18/2021 18:18,female,1,1974,2 +0.82111111,0.90927273,0.8388,0.96525,2865,4/18/2021 18:20,female,1,2000,4 +0.58092857,0.625,0.60915385,0.51616667,2865,4/18/2021 18:30,female,1,2000,4 +0.60845455,0.67809091,0.7065,0.62485714,2865,4/18/2021 18:31,female,1,2000,4 +0.60845455,0.67809091,0.7065,0.62485714,2865,4/18/2021 18:31,female,1,2000,4 +0.980375,0.83011111,0.8835,0.99655556,2866,4/18/2021 18:29,female,1,1974,5 +0.7789,0.88458333,0.780125,0.87233333,2866,4/18/2021 18:29,female,1,1974,5 +0.8274,1.31866667,0.91511111,0.97355556,2867,4/18/2021 18:34,female,1,1976,2 +0.83028571,0.96566667,0.7951,0.77161538,2867,4/18/2021 18:34,female,1,1976,2 +1.26483333,1.0735,0.96066667,1.48866667,2868,4/18/2021 18:34,male,1,1966,2 +1.00225,1.204,1.145,1.252,2868,4/18/2021 18:34,male,1,1966,2 +2.657,2.165,2.1234,2.0615,2869,4/18/2021 18:50,male,1,1953,1 +2.18933333,1.646,2.77425,1.1645,2869,4/18/2021 18:51,male,1,1953,1 +0.78444444,0.95555556,0.8811,0.8085,2870,4/18/2021 18:52,female,1,1990,4 +0.7897,0.69775,0.71788889,0.7207,2870,4/18/2021 18:52,female,1,1990,4 +1.51383333,1.6744,0.7778,1.70025,2871,4/18/2021 18:52,female,1,1939,1 +1.17633333,1.472,1.19325,1.241,2871,4/18/2021 18:52,female,1,1939,1 +2.842,2.81633333,2.69266667,2.9095,2872,4/18/2021 18:52,female,1,1949,1 +1.98566667,2.45333333,2.739,1.8695,2872,4/18/2021 18:53,female,1,1949,1 +0.9336,0.90022222,0.9158,0.7678,2873,4/18/2021 19:09,male,1,1987,3 +1.5058,0.54336364,1.085,0.81457143,2873,4/18/2021 19:09,male,1,1987,3 +1.5966,1.824,1.62325,1.0855,2874,4/18/2021 19:42,male,1,1969,3 +1.6478,1.5288,1.189,1.1008,2874,4/18/2021 19:43,male,1,1969,3 +2.687,2.3535,1.89525,3.156,2875,4/18/2021 19:46,female,1,1954,2 +2.3155,2.58,1.9248,2.376,2875,4/18/2021 19:47,female,1,1954,2 +2.3996,3.40633333,2.082,2.647,2876,4/18/2021 20:00,female,1,1953,1 +5.713,4.122,1.456,2.129,2876,4/18/2021 20:00,female,1,1953,1 +1.399,2.388,1.778,2.282,2877,4/18/2021 20:00,female,1,1977,3 +2.953,1.08225,1.55533333,2.00966667,2877,4/18/2021 20:16,female,1,1977,3 +3.518,4.534,2.832,3.99866667,2878,4/18/2021 20:17,female,1,1953,1 +3.199,2.8106,2.812,2.446,2878,4/18/2021 20:18,female,1,1953,1 +1.42966667,1.35366667,1.51066667,1.8035,2881,4/18/2021 20:25,female,1,1958,1 +2.484,1.4535,1.707,2.45966667,2882,4/18/2021 20:32,female,1,1972,2 +1.87,1.289,1.58733333,1.24866667,2882,4/18/2021 20:32,female,1,1972,2 +1.278,2.395,1.70825,1.76275,2883,4/18/2021 20:36,male,1,1951,2 +2.0625,3.25175,3.607,2.44366667,2883,4/21/2021 10:39,male,1,1951,2 +2.19066667,2.85366667,2.016,2.102,2884,4/18/2021 20:44,male,1,1957,2 +2.5565,1.57516667,1.8925,1.54733333,2884,4/18/2021 20:43,male,1,1957,2 +0.65807143,0.56888889,0.8758,0.70266667,2885,4/18/2021 20:38,male,1,1979,4 +0.57325,0.7306,0.5975,0.5562,2885,4/18/2021 20:39,male,1,1979,4 +1.69025,3.392,3.0355,2.6864,2886,4/21/2021 10:45,male,1,1954,2 +2.443,2.431,1.7985,1.74033333,2886,4/18/2021 20:44,male,1,1954,2 +1.1695,1.29266667,1.33475,1.11014286,2887,4/18/2021 20:50,male,1,1959,2 +1.06333333,1.14325,1.10566667,1.1006,2887,4/18/2021 20:51,male,1,1959,2 +4.638,3.08533333,2.0245,2.74075,2888,4/21/2021 10:52,male,1,1957,2 +1.956,3.526,2.19,1.64933333,2888,4/18/2021 20:51,male,1,1957,2 +2.31866667,2.293,2.3835,2.08966667,2889,4/18/2021 20:59,female,1,1958,2 +1.46528571,1.38833333,1.675,1.64,2889,4/21/2021 10:59,female,1,1958,2 +0.974,1.234,0.964,0.838,2890,4/18/2021 21:12,male,1,1973,3 +1.71133333,1.956,1.137,1.49233333,2890,4/18/2021 21:11,male,1,1973,3 +1.60633333,1.7384,1.4015,1.474,2892,4/18/2021 21:34,female,1,1975,2 +2.0425,1.452,1.6905,1.588,2892,4/18/2021 21:35,female,1,1975,2 +0.76676923,0.80433333,0.88428571,0.8108,2893,4/21/2021 10:50,male,1,1976,4 +0.8248,0.8901,1.929,0.913625,2893,4/18/2021 22:13,male,1,1976,4 +4.009,1.10533333,1.189,1.657,2894,4/18/2021 22:07,male,1,1970,3 +1.293,0.758,0.867,1.048,2894,4/18/2021 22:07,male,1,1970,3 +0.96588889,0.931375,0.84475,1.04483333,2895,4/18/2021 22:08,male,1,2000,3 +0.98825,1.0586,0.88527273,1.26125,2895,4/18/2021 22:07,male,1,2000,3 +2.0634,1.60433333,1.421,1.509,2896,4/18/2021 22:33,female,1,1970,2 +1.42566667,1.35616667,1.5092,1.26357143,2896,4/18/2021 22:34,female,1,1970,2 +1.17588889,1.577,1.2255,1.6412,2897,4/18/2021 23:08,male,1,1945,2 +1.22016667,1.168125,1.3594,1.376,2897,4/18/2021 23:07,male,1,1945,2 +1.09842857,1.1574,1.8175,0.95655556,2898,4/18/2021 23:16,female,1,1985,3 +0.9034,1.1715,1.56883333,1.245375,2898,4/18/2021 23:18,female,1,1985,3 +0.8095,1.02557143,0.86116667,0.8549,2899,4/21/2021 11:16,male,1,1996,5 +0.99766667,2.57675,0.95883333,1.2985,2899,4/19/2021 15:01,male,1,1996,5 +0.749,0.607,0.56964706,0.58475,2900,4/19/2021 0:27,male,1,1977,3 +0.673125,0.8562,1.16516667,0.70257143,2900,4/19/2021 0:21,male,1,1977,3 +2.3885,2.108,3.386,2.6894,2901,4/19/2021 0:43,male,1,1958,2 +0.8425,0.78842857,1.203,1.53766667,2901,4/19/2021 0:57,male,1,1958,2 +0.6815,0.913875,0.6764,0.787125,2902,4/19/2021 0:43,female,1,1999,4 +0.924,1.02725,0.875,0.80728571,2902,4/19/2021 0:42,female,1,1999,4 +1.28171429,1.01425,1.4205,1.099,2903,4/19/2021 14:24,male,1,1962,2 +0.99118182,1.0862,1.01814286,0.93783333,2905,4/19/2021 9:30,female,1,1980,3 +0.96742857,1.04145455,1.014,0.976,2905,4/19/2021 9:30,female,1,1980,3 +2.2028,2.008,2.08033333,1.8145,2906,4/19/2021 9:52,female,1,1953,1 +2.27266667,2.41033333,2.09666667,2.0435,2906,4/19/2021 9:53,female,1,1953,1 +2.3535,1.573,2.02125,2.122,2907,4/19/2021 10:44,male,1,1953,2 +1.90333333,2.43633333,1.90266667,2.241,2907,4/19/2021 10:45,male,1,1953,2 +1.1044,1.40166667,1.0015,1.32444444,2908,4/19/2021 11:28,female,1,2001,3 +1.01642857,0.90883333,0.879625,1.08766667,2908,4/19/2021 11:29,female,1,2001,3 +1.42666667,1.2916,1.3282,1.36125,2909,4/19/2021 11:30,female,1,1960,2 +1.3402,1.283,1.5188,1.23725,2909,4/19/2021 11:30,female,1,1960,2 +2.1995,3.063,3.43466667,2.515,2910,4/19/2021 11:50,male,1,1948,2 +2.288,2.323,2.70825,2.33575,2910,4/19/2021 11:51,male,1,1948,2 +0.942,0.9985,0.870625,1.11922222,2911,4/19/2021 11:53,male,1,1975,3 +1.59966667,1.43425,1.992,1.6536,2912,4/19/2021 12:13,male,1,1957,3 +1.014,1.15625,1.8654,1.1586,2912,4/19/2021 12:10,male,1,1957,3 +3.577,1.9168,1.49316667,1.678,2913,4/19/2021 12:14,female,1,1977,1 +1.363,1.185,1.224125,1.306,2913,4/19/2021 12:15,female,1,1977,1 +4.88,4.64,4.0715,4.344,2914,4/19/2021 12:37,female,1,1948,2 +7.466,6.432,2.963,8.745,2914,4/19/2021 12:36,female,1,1948,2 +0.8144,0.9915,0.81666667,0.83622222,2915,4/19/2021 12:45,male,1,1960,5 +0.886875,1.01233333,1.121375,0.89636364,2915,4/19/2021 12:50,male,1,1960,5 +0.64242857,0.59858333,0.980625,0.643,2916,4/19/2021 12:55,female,0,1950,1 +0.65091667,0.6642,0.90811111,0.81575,2916,4/19/2021 12:55,female,0,1950,1 +8.573,2.688,4.005,2.131,2917,4/19/2021 13:04,female,1,1951,1 +3.08766667,1.7945,2.66433333,2.286,2917,4/19/2021 13:05,female,1,1951,1 +1.1145,1.161,1.20475,1.46325,2919,4/19/2021 13:15,female,1,1971,3 +1.9544,1.85216667,1.951,2.391,2919,4/19/2021 13:13,female,1,1971,3 +0.7543,0.569,0.93733333,0.78176923,2920,4/19/2021 13:20,female,1,1999,2 +0.6913,0.53685714,0.81925,0.5834,2920,4/19/2021 13:21,female,1,1999,2 +4.33066667,1.3255,3.4215,3.1195,2921,4/19/2021 13:25,male,1,1950,1 +4.522,3.40433333,3.86,2.889,2921,4/19/2021 13:25,male,1,1950,1 +1.813,1.96233333,2.657,2.1615,2922,4/19/2021 13:20,female,1,1959,3 +2.14225,2.457,2.246,3.436,2922,4/19/2021 13:21,female,1,1959,3 +1.436,1.4365,1.45266667,1.776,2923,4/19/2021 13:34,female,1,1971,3 +1.619,2.02033333,2.0474,2.02033333,2923,4/19/2021 13:33,female,1,1971,3 +0.69283333,0.65015385,0.6315,0.6747,2924,4/19/2021 13:37,male,1,2002,2 +0.64925,0.64625,0.6785,0.57728571,2924,4/19/2021 13:38,male,1,2002,2 +1.04833333,0.81227273,1.0186,0.90457143,2925,4/19/2021 13:42,male,1,1960,4 +0.98857143,1.0273,0.95825,0.917,2925,4/19/2021 13:41,male,1,1960,4 +2.266,0.94966667,1.5268,1.0618,2926,4/19/2021 13:42,male,1,1997,5 +0.6215,1.02383333,0.9096,0.68885714,2927,4/19/2021 16:26,male,1,1969,4 +0.67966667,0.62336364,0.6764,0.55392857,2927,4/19/2021 16:27,male,1,1969,4 +1.3608,1.20128571,1.4764,1.81525,2928,4/19/2021 13:56,female,1,1960,2 +1.343,1.5035,1.49183333,1.4475,2928,4/19/2021 13:57,female,1,1960,2 +5.9605,5.927,6.14,3.065,2929,4/19/2021 14:09,male,0,1948,2 +6.1085,4.2815,2.493,5.951,2929,4/19/2021 14:10,male,0,1948,2 +1.31866667,1.51575,1.7402,1.618,2930,4/19/2021 14:16,female,1,1955,2 +1.55033333,1.3616,1.292,1.23366667,2930,4/19/2021 14:17,female,1,1955,2 +1.05583333,0.9906,1.28528571,1.29814286,2931,4/19/2021 14:12,female,1,1959,2 +1.054125,0.9762,1.234,1.116,2931,4/19/2021 14:12,female,1,1959,2 +1.437,0.97357143,0.99622222,0.99,2932,4/19/2021 14:13,female,1,1971,3 +0.87871429,1.03633333,0.93122222,1.26128571,2932,4/19/2021 14:14,female,1,1971,3 +1.09,1.006375,1.173,1.15828571,2934,4/19/2021 14:27,male,1,1956,2 +1.11775,1.064,1.05733333,1.07425,2934,4/19/2021 14:29,male,1,1956,2 +1.564,1.73575,1.56166667,1.62857143,2937,4/19/2021 19:25,female,1,1959,2 +1.21566667,1.867,1.801,1.80983333,2937,4/19/2021 19:26,female,1,1959,2 +2.0835,1.20785714,1.127,0.823,2938,4/19/2021 14:45,female,1,2001,3 +0.97528571,1.05657143,0.89883333,0.81225,2938,4/19/2021 14:46,female,1,2001,3 +3.252,2.6426,1.215,3.933,2939,4/19/2021 14:49,female,1,1949,1 +2.22633333,2.4844,2.11466667,2.2725,2939,4/21/2021 13:38,female,1,1949,1 +1.0935,1.21942857,1.21466667,1.14133333,2940,4/19/2021 14:50,male,1,1958,2 +0.984,0.9905,1.05575,1.04083333,2940,4/19/2021 14:51,male,1,1958,2 +1.058,1.03828571,1.23625,1.1166,2941,4/19/2021 15:06,female,1,1957,2 +0.9965,1.098,1.13642857,1.15871429,2941,4/19/2021 15:07,female,1,1957,2 +1.99025,2.297,2.12533333,2.12875,2942,4/19/2021 15:15,female,1,1949,1 +1.08933333,1.4106,1.3816,1.20985714,2942,4/21/2021 21:35,female,1,1949,1 +1.50133333,1.32628571,2.807,1.4085,2943,4/19/2021 15:18,female,1,1971,2 +2.35025,1.611,1.13066667,1.2882,2943,4/19/2021 15:18,female,1,1971,2 +1.2265,1.38733333,1.1802,1.32116667,2944,4/19/2021 15:30,female,1,1969,3 +0.917,0.9995,0.80663636,1.06428571,2944,4/19/2021 15:31,female,1,1969,3 +0.58045455,0.65414286,0.728375,0.763,2945,4/19/2021 16:56,male,1,1977,5 +0.6235,0.64954545,0.732,0.697125,2945,4/19/2021 16:57,male,1,1977,5 +0.95966667,1.20242857,1.4834,1.318,2946,4/19/2021 15:47,male,1,1971,3 +1.41733333,1.13666667,1.6888,0.9173,2946,4/19/2021 15:47,male,1,1971,3 +1.56825,1.823,1.82433333,1.27128571,2947,4/19/2021 15:48,male,1,1966,2 +1.25825,1.24625,1.36042857,2.441,2947,4/19/2021 15:49,male,1,1966,2 +3.834,3.245,2.9,3.83033333,2949,4/19/2021 16:05,male,1,1945,1 +2.663,3.5295,4.5625,3.791,2949,4/19/2021 16:06,male,1,1945,1 +2.36733333,2.90533333,2.8675,1.95375,2950,4/19/2021 16:04,female,1,1947,1 +2.135,2.703,2.923,3.03633333,2950,4/19/2021 16:05,female,1,1947,1 +1.374125,1.1582,0.8912,1.3024,2951,4/19/2021 16:09,female,0,1975,2 +1.34533333,1.0615,0.851,1.21114286,2951,4/19/2021 16:10,female,0,1975,2 +0.854625,0.64666667,0.63078947,0.72785714,2952,4/20/2021 14:42,female,1,2001,3 +5.103,1.95925,2.704,2.152,2953,4/19/2021 16:42,male,1,1941,1 +1.33183333,1.330875,3.6,1.4516,2953,4/19/2021 16:43,male,1,1941,1 +0.759,0.6929,0.94308333,0.644125,2954,4/19/2021 16:43,female,1,2001,3 +0.93657143,0.66530769,0.92644444,0.85442857,2954,4/19/2021 16:34,female,1,2001,3 +1.6276,1.64933333,1.3735,1.41825,2955,4/19/2021 18:18,female,1,1965,2 +1.52,1.755,1.8735,1.9125,2955,4/19/2021 18:19,female,1,1965,2 +0.64244444,0.6179,0.76890909,0.87027273,2957,4/19/2021 16:53,male,1,1998,4 +0.56133333,0.48290909,0.77358333,0.67491667,2957,4/19/2021 17:00,male,1,1998,4 +1.6976,3.00733333,1.53325,2.1405,2958,4/19/2021 17:14,female,1,1945,2 +1.3392,1.96025,1.976,1.82042857,2958,4/19/2021 17:14,female,1,1945,2 +5.083,3.282,2.4312,4.567,2959,4/19/2021 17:18,male,1,1956,1 +1.6515,2.545,1.6552,2.9455,2959,4/20/2021 21:12,male,1,1956,1 +2.933,3.91875,3.576,3.288,2960,4/19/2021 17:33,female,1,1960,1 +2.795,2.72725,2.7345,2.852,2960,4/20/2021 20:54,female,1,1960,1 +1.6104,1.65575,2.35433333,2.424,2961,4/19/2021 17:31,male,1,1942,2 +1.48725,1.39525,1.497,1.468,2961,4/19/2021 17:31,male,1,1942,2 +0.6248,0.92766667,0.73833333,0.92633333,2963,4/19/2021 17:33,male,1,2001,3 +0.56407143,0.71553333,0.6772,0.85411111,2963,4/19/2021 17:34,male,1,2001,3 +0.9305,1.5485,2.04125,0.988,2964,4/19/2021 17:49,female,1,2001,3 +1.074,1.08455556,2.7315,0.763,2964,4/19/2021 17:50,female,1,2001,3 +3.73833333,2.55066667,1.975,4.04,2965,4/19/2021 17:48,female,1,1950,1 +2.5835,2.3335,2.6315,1.61125,2965,4/19/2021 17:49,female,1,1950,1 +1.3652,1.225625,1.2474,1.12333333,2966,4/19/2021 18:56,female,1,1978,2 +0.9629,0.96883333,0.8705,1.26957143,2966,4/21/2021 10:38,female,1,1978,2 +0.9618,0.92225,0.8185,1.05228571,2967,4/19/2021 17:59,female,1,1969,4 +0.691,0.78228571,0.627,0.80175,2967,4/19/2021 18:00,female,1,1969,4 +0.685,0.70352941,0.95766667,0.77366667,2968,4/19/2021 18:05,female,1,2000,3 +0.93827273,0.96666667,0.65677778,0.902625,2968,4/19/2021 18:06,female,1,2000,3 +0.4832,0.607,0.50252941,0.49461111,2969,4/19/2021 18:28,male,1,2000,2 +0.591,0.63230769,0.5298,0.5735625,2969,4/19/2021 18:07,male,1,2000,2 +0.5635,0.61271429,0.61563636,0.4615,2969,4/19/2021 18:25,male,1,2000,2 +0.876375,1.15866667,0.94466667,0.89528571,2970,4/19/2021 18:10,male,1,1974,5 +0.79828571,0.76875,1.58957143,1.761,2970,4/19/2021 18:11,male,1,1974,5 +1.08381818,1.176,1.1936,1.0925,2972,4/19/2021 18:18,male,1,1965,3 +1.1278,1.223,1.183,1.149625,2972,4/19/2021 18:18,male,1,1965,3 +1.46475,1.47083333,1.9042,1.32675,2973,4/19/2021 18:36,female,1,1999,2 +1.1425,1.20525,1.8208,1.455,2973,4/19/2021 18:37,female,1,1999,2 +0.65177778,0.64193333,0.63425,0.68876923,2974,4/19/2021 18:40,male,1,1976,2 +0.5395,0.7351,0.60381818,0.745,2974,4/19/2021 18:35,male,1,1976,2 +0.5906,0.46413333,0.5615,0.600875,2975,4/19/2021 18:39,male,1,1993,5 +0.652,0.47633333,0.74525,0.523,2975,4/19/2021 18:39,male,1,1993,5 +1.066,1.30728571,1.0625,1.2912,2976,4/19/2021 18:44,male,1,1977,3 +0.93083333,1.23433333,1.13642857,1.00566667,2976,4/19/2021 18:44,male,1,1977,3 +0.67525,0.8035,0.9235,0.66471429,2977,4/19/2021 18:48,male,1,1975,2 +1.08522222,1.0134,1.0765,1.0555,2978,4/19/2021 18:53,male,1,1971,3 +1.036,1.07,1.00185714,1.02163636,2978,4/19/2021 18:53,male,1,1971,3 +0.757375,0.73375,0.62736364,0.69909091,2979,4/19/2021 19:04,male,1,1998,5 +0.66073333,0.718,0.7911,0.6227,2979,4/19/2021 19:05,male,1,1998,5 +1.222,0.82766667,1.127,1.2185,2981,4/19/2021 19:27,female,1,1952,1 +2.28466667,1.2805,2.879,1.6465,2981,4/19/2021 19:29,female,1,1952,1 +0.876,0.90377778,0.90944444,0.85685714,2983,4/19/2021 19:31,female,1,1975,3 +0.97111111,0.9705,0.99642857,1.0766,2983,4/19/2021 19:32,female,1,1975,3 +3.3005,3.926,4.4585,4.4575,2984,4/19/2021 19:33,male,1,1957,1 +2.759,3.185,3.413,2.8275,2984,4/19/2021 19:35,male,1,1957,1 +2.15725,1.54333333,2.0125,2.02275,2986,4/19/2021 19:46,male,1,1943,2 +1.807,1.84933333,1.83116667,1.69925,2986,4/19/2021 19:46,male,1,1943,2 +1.807,1.84933333,1.83116667,1.69925,2986,4/19/2021 19:46,male,1,1943,2 +3.059,2.1995,2.2165,1.909,2987,4/19/2021 20:19,male,1,1958,2 +1.59,1.7844,1.938,1.6034,2987,4/19/2021 20:18,male,1,1958,2 +0.857875,0.8472,1.22944444,0.97266667,2988,4/19/2021 20:14,male,1,1999,3 +1.1575,0.97875,1.12057143,1.21344444,2988,4/19/2021 20:15,male,1,1999,3 +1.05771429,2.716,1.1904,1.093,2989,4/19/2021 20:48,male,1,1951,4 +1.3104,1.6456,1.1415,1.24616667,2989,4/19/2021 20:47,male,1,1951,4 +1.83966667,3.357,2.154,2.1384,2990,4/19/2021 21:04,male,1,1959,2 +2.921,2.53433333,2.0725,2.56733333,2990,4/19/2021 21:05,male,1,1959,2 +2.729,2.475,2.532,2.883,2991,4/19/2021 21:39,male,1,1960,2 +1.71,2.066,3.068,2.464,2991,4/19/2021 21:39,male,1,1960,2 +0.74385714,0.793875,1.207125,0.94277778,2992,4/19/2021 21:44,male,1,2002,4 +0.80483333,0.82571429,0.5427,0.81554545,2992,4/19/2021 21:45,male,1,2002,4 +1.414,3.47966667,2.095,1.789,2993,4/20/2021 0:23,female,1,1962,2 +3.022,3.183,1.875,3.07466667,2993,4/20/2021 0:15,female,1,1962,2 +1.58325,1.738,2.1585,1.6956,2994,4/19/2021 22:04,male,1,1930,2 +1.48328571,1.8468,1.672,1.60425,2994,4/19/2021 22:04,male,1,1930,2 +0.76325,1.0785,0.8375,1.2982,2995,4/19/2021 22:38,female,1,1953,2 +0.82341667,1.2072,1.04555556,1.0525,2995,4/19/2021 22:35,female,1,1953,2 +0.705,0.9295,0.81675,1.496,2996,4/19/2021 22:56,female,1,1945,3 +0.777,1.0915,0.96075,1.19025,2997,4/19/2021 23:12,female,1,2001,3 +1.147,1.479,1.121,0.903,2997,4/19/2021 22:59,female,1,2001,3 +1.24,1.07533333,1.51183333,1.318,2997,4/19/2021 23:11,female,1,2001,3 +1.023,0.79622222,0.78366667,2.0114,2998,4/19/2021 23:46,female,0,1955,1 +0.75914286,1.046625,0.82622222,1.19485714,2998,4/19/2021 23:48,female,0,1955,1 +0.96355556,0.80928571,1.36185714,0.933,2999,4/19/2021 23:43,male,1,1973,3 +0.78063636,1.03383333,1.05466667,0.8816,2999,4/19/2021 23:43,male,1,1973,3 +1.54716667,1.12466667,1.09,1.942,3000,4/20/2021 0:34,female,1,2001,3 +0.79553846,1.07711111,1.0558,0.6935,3000,4/20/2021 0:42,female,1,2001,3 +1.2682,1.17666667,1.21854545,1.2964,3001,4/20/2021 0:50,male,0,1958,3 +1.0492,1.08972727,1.26125,1.472,3001,4/20/2021 0:49,male,0,1958,3 +0.76214286,0.5675,0.77288889,0.8392,3002,4/20/2021 0:51,female,1,1975,3 +0.692,0.562,0.788,1.016,3002,4/20/2021 0:52,female,1,1975,3 +1.13214286,1.36,1.36675,0.83066667,3003,4/20/2021 1:00,male,1,1972,2 +1.305,1.31485714,1.324,1.226,3003,4/20/2021 0:52,male,1,1972,2 +2.69533333,2.93,2.968,3.10366667,3004,4/20/2021 1:08,female,1,1958,2 +1.56,1.53075,1.73442857,1.912,3004,4/20/2021 1:09,female,1,1958,2 +1.5564,1.432,1.5828,1.84233333,3005,4/20/2021 1:21,male,1,1965,3 +2.017,1.5225,1.8065,1.8135,3005,4/20/2021 1:19,male,1,1965,3 +0.622,0.6339,0.76741667,0.60933333,3006,4/20/2021 1:11,male,1,1970,4 +0.5466875,0.53927273,0.698,0.5302,3006,4/20/2021 1:12,male,1,1970,4 +1.17911111,1.19342857,1.4095,0.9875,3007,4/20/2021 1:20,female,1,1976,2 +0.77527273,0.87175,0.92688889,0.76357143,3007,4/20/2021 1:12,female,1,1976,2 +3.57633333,3.459,6.516,4.0095,3009,4/20/2021 1:26,male,1,1955,1 +3.05066667,3.6875,3.7665,4.248,3009,4/20/2021 1:27,male,1,1955,1 +0.718,0.7457,1.04477778,0.84742857,3011,4/20/2021 1:33,female,1,1964,2 +1.3457,0.843,0.7666,1.20628571,3011,4/20/2021 1:34,female,1,1964,2 +1.666,1.356,1.52385714,1.36483333,3012,4/20/2021 1:45,male,1,1958,1 +0.98125,1.2055,1.38,1.1456,3012,4/20/2021 1:46,male,1,1958,1 +0.64184615,0.7775,0.7475,0.67761538,3013,4/20/2021 1:35,male,1,1970,3 +0.58442857,0.73057143,0.8898,0.57561538,3013,4/20/2021 1:35,male,1,1970,3 +0.79390909,0.89242857,1.15914286,0.77214286,3015,4/20/2021 1:49,female,1,1968,2 +0.8634,1.239375,1.59016667,1.40975,3015,4/20/2021 1:50,female,1,1968,2 +1.80825,1.783,1.37725,1.36966667,3016,4/20/2021 2:52,female,1,1959,1 +2.188,2.1225,2.0305,2.66633333,3016,4/20/2021 2:50,female,1,1959,1 +1.5272,1.38633333,1.9755,1.37575,3016,4/20/2021 2:51,female,1,1959,1 +1.06014286,0.878375,0.79608333,0.721,3017,4/20/2021 2:09,male,1,1962,3 +0.758,1.037625,1.2121,0.867,3017,4/20/2021 2:10,male,1,1962,3 +1.501,2.93633333,2.123,2.047,3018,4/20/2021 2:46,female,1,1947,1 +1.54525,1.808,1.57166667,1.6774,3019,4/20/2021 3:00,female,1,1945,1 +1.325,2.85266667,1.1665,1.227,3019,4/20/2021 3:00,female,1,1945,1 +4.15,3.9555,3.74466667,2.802,3020,4/20/2021 3:16,male,1,1945,1 +1.282,3.185,5.0105,2.67933333,3020,4/20/2021 3:17,male,1,1945,1 +0.75727273,0.7646,0.69477778,0.6795,3021,4/20/2021 3:29,female,1,1970,2 +0.8344,1.15355556,0.98209091,0.742,3021,4/20/2021 3:30,female,1,1970,2 +0.80590909,0.66426667,0.6993,0.67566667,3022,4/20/2021 3:45,male,1,1999,4 +1.00942857,1.33077778,0.6675,0.63109091,3022,4/20/2021 3:45,male,1,1999,4 +1.073,0.9995,0.96166667,1.006625,3023,4/20/2021 11:19,male,1,1977,3 +0.955625,0.98288889,0.978625,1.0686,3023,4/20/2021 11:20,male,1,1977,3 +0.711,0.892,0.61644444,0.874,3024,4/20/2021 9:29,female,1,1980,4 +0.75933333,0.935,0.61933333,0.648,3024,4/20/2021 9:29,female,1,1980,4 +0.6892,0.8678,0.6284,0.7205,3025,4/20/2021 10:07,male,1,1978,4 +0.80544444,0.7104,0.63590909,0.8912,3025,4/20/2021 10:08,male,1,1978,4 +0.58890909,0.64944444,0.61825,0.69607143,3026,4/20/2021 10:35,female,1,1978,4 +0.70742857,0.6511,0.55769231,0.70035714,3026,4/20/2021 10:40,female,1,1978,4 +0.79753333,0.6779,0.69685714,0.6334,3027,4/20/2021 11:01,male,1,1974,4 +0.572,0.69514286,0.71914286,0.7645,3027,4/20/2021 11:04,male,1,1974,4 +0.77244444,0.73333333,0.77676923,0.9645,3028,4/20/2021 11:50,female,1,1949,3 +0.86233333,0.89011111,0.8324,0.8485,3028,4/20/2021 11:50,female,1,1949,3 +0.95366667,1.07085714,0.79045455,0.951,3029,4/20/2021 12:08,female,1,1946,3 +0.70492308,0.7638,0.75544444,0.86671429,3029,4/20/2021 12:09,female,1,1946,3 +0.84627273,1.2495,0.94157143,0.8988,3030,4/20/2021 12:24,male,1,1952,3 +0.8788,1.46071429,0.851,0.94733333,3030,4/20/2021 12:24,male,1,1952,3 +2.62175,3.167,2.38466667,2.444,3031,4/20/2021 10:06,female,1,1943,1 +3.0178,2.901,2.2105,2.84,3031,4/20/2021 10:08,female,1,1943,1 +0.68122222,0.62566667,0.8767,0.74083333,3032,4/20/2021 10:27,female,1,2002,3 +0.67772727,0.6216,0.576,0.66618182,3032,4/20/2021 10:28,female,1,2002,3 +1.698,2.18033333,1.69716667,2.125,3033,4/20/2021 10:52,male,1,1959,2 +1.6305,2.0982,1.85425,1.90425,3033,4/20/2021 10:52,male,1,1959,2 +1.585,1.4864,1.9674,1.66825,3034,4/20/2021 11:11,female,1,1960,2 +1.658,1.29342857,1.3636,1.32,3034,4/20/2021 11:12,female,1,1960,2 +2.96,3.272,3.233,2.882,3035,4/20/2021 11:14,female,1,1948,2 +2.986,5.661,3.5835,3.748,3035,4/20/2021 11:14,female,1,1948,2 +2.29375,2.714,1.836,1.9545,3036,4/20/2021 11:18,female,1,1964,2 +1.397,1.691,1.63733333,1.61925,3036,4/20/2021 11:32,female,1,1964,2 +0.59333333,0.55582353,0.668,0.72616667,3037,4/20/2021 11:28,male,1,1979,4 +0.78114286,0.945125,0.67771429,0.70354545,3037,4/20/2021 11:28,male,1,1979,4 +0.947,1.068,0.861625,0.85311111,3038,4/20/2021 12:50,female,1,1954,2 +1.12466667,0.971,0.926,0.865,3038,4/20/2021 12:51,female,1,1954,2 +1.18025,1.0214,1.064,1.15671429,3039,4/20/2021 11:27,male,1,1970,2 +1.0795,1.2622,1.19088889,1.3385,3039,4/20/2021 11:27,male,1,1970,2 +0.95211111,0.904875,0.834,1.26528571,3040,4/20/2021 12:39,male,1,1953,2 +1.0608,0.95066667,0.914875,0.86133333,3040,4/20/2021 12:39,male,1,1953,2 +1.4834,1.98333333,1.25428571,1.4866,3041,4/20/2021 11:39,female,1,2002,3 +0.9908,1.29057143,1.069,0.98622222,3041,4/20/2021 11:40,female,1,2002,3 +1.79475,1.8605,1.703,1.92933333,3042,4/20/2021 11:46,male,1,1957,2 +1.641,1.5738,2.14675,1.81166667,3042,4/20/2021 11:47,male,1,1957,2 +1.321,1.31066667,1.11685714,1.387875,3043,4/20/2021 11:51,female,1,1979,5 +1.2865,0.9948,1.08854545,0.90175,3043,4/20/2021 11:52,female,1,1979,5 +0.674375,0.58773333,0.677,0.78071429,3044,4/20/2021 11:51,female,1,1973,2 +0.65666667,0.79575,0.77291667,0.8647,3044,4/20/2021 11:52,female,1,1973,2 +0.83630769,1.009,0.676,0.85242857,3045,4/20/2021 11:50,female,1,1979,3 +0.9875,0.90214286,0.82577778,0.89518182,3045,4/20/2021 12:02,female,1,1979,3 +0.8085,1.07875,1.01385714,1.363,3046,4/20/2021 12:18,female,1,1960,2 +1.1564,1.369,1.33944444,1.359,3046,4/20/2021 12:25,female,1,1960,2 +1.6975,1.7928,1.63225,1.49075,3047,4/20/2021 12:24,male,1,1957,3 +1.5965,1.50966667,1.561,1.53683333,3047,4/20/2021 12:26,male,1,1957,3 +2.052,2.03666667,1.57,1.306,3048,4/20/2021 12:27,female,1,1958,2 +1.14,1.929,3.582,2.0415,3048,4/20/2021 12:28,female,1,1958,2 +0.56876923,0.9672,0.63566667,0.90011111,3049,4/20/2021 12:26,male,1,1990,3 +0.55866667,0.6435,0.82966667,0.776,3049,4/20/2021 12:28,male,1,1990,3 +1.3414,1.5244,1.23063636,0.7055,3050,4/20/2021 12:56,female,1,2001,3 +0.78688889,1.04514286,0.606,1.11088889,3050,4/20/2021 12:57,female,1,2001,3 +4.7385,3.04933333,3.1575,2.214,3051,4/20/2021 12:42,female,1,1969,2 +2.0542,3.027,1.74925,1.7348,3051,4/20/2021 12:51,female,1,1969,2 +0.60246667,0.9438,0.64013333,0.629,3052,4/20/2021 12:50,male,1,1969,3 +0.58927273,0.75575,0.653,0.56894118,3052,4/20/2021 12:50,male,1,1969,3 +0.68657143,0.801,0.80033333,0.73228571,3053,4/20/2021 12:52,female,1,1996,3 +0.59655556,0.83188889,0.8039,1.05925,3054,4/20/2021 13:11,female,1,1989,3 +0.727,0.58691667,0.62936364,0.7164,3054,4/20/2021 13:12,female,1,1989,3 +0.795,1.2218,0.947375,1.392875,3055,4/20/2021 13:13,male,1,1981,2 +1.816,0.99411111,0.95822222,1.2935,3055,4/20/2021 13:12,male,1,1981,2 +4.1605,4.2025,2.047,1.5975,3056,4/20/2021 13:17,male,1,1956,2 +0.55890909,0.67083333,0.537625,0.548,3057,4/20/2021 14:01,male,1,1972,2 +0.71544444,0.6259,0.48714286,0.55694444,3057,4/20/2021 14:02,male,1,1972,2 +2.21333333,1.60733333,1.40971429,1.5872,3058,4/20/2021 13:27,male,1,1977,3 +1.448,1.66525,1.1998,1.88566667,3058,4/20/2021 13:26,male,1,1977,3 +2.21333333,1.60733333,1.40971429,1.5872,3058,4/20/2021 13:27,male,1,1977,3 +2.21333333,1.60733333,1.40971429,1.5872,3058,4/20/2021 13:27,male,1,1977,3 +1.62283333,2.00975,1.44766667,1.6895,3059,4/20/2021 13:41,male,1,1950,2 +2.15783333,1.82125,1.9245,1.84866667,3059,4/20/2021 14:03,male,1,1950,2 +3.997,3.163,3.069,3.7915,3060,4/20/2021 14:03,female,1,1959,1 +5.31633333,4.831,3.86,4.247,3060,4/20/2021 13:53,female,1,1959,1 +0.81863636,1.0782,0.79361538,0.81233333,3062,4/20/2021 14:30,female,1,1971,2 +0.7746,0.5388,0.64772727,0.9293,3063,4/20/2021 14:14,male,1,1999,3 +0.59,0.9025,0.68655556,1.248,3063,4/20/2021 14:15,male,1,1999,3 +1.1168,1.0954,0.9985,1.3008,3064,4/20/2021 14:17,female,1,1965,2 +1.10622222,0.9485,0.77816667,0.76428571,3064,4/20/2021 14:25,female,1,1965,2 +0.5475,0.568,0.67076923,0.60633333,3065,4/20/2021 14:21,female,1,1968,2 +0.6066,0.532,0.68755556,0.62277778,3065,4/20/2021 14:22,female,1,1968,2 +2.723,2.2048,2.765,1.6565,3066,4/20/2021 14:20,female,1,1957,2 +1.68775,2.469,2.31566667,2.50733333,3066,4/20/2021 14:21,female,1,1957,2 +1.1287,1.068,1.2515,1.49233333,3067,4/20/2021 14:26,male,1,1948,1 +1.06933333,1.77575,2.45866667,1.907,3067,4/20/2021 14:42,male,1,1948,1 +2.22225,1.6545,2.373,2.901,3068,4/20/2021 14:31,male,1,1947,1 +2.68525,2.19533333,2.009,2.14233333,3068,4/20/2021 14:34,male,1,1947,1 +2.5475,3.03133333,2.181,2.1464,3069,4/20/2021 14:46,male,1,1940,1 +2.392,2.904,2.2715,2.3115,3069,4/20/2021 14:46,male,1,1940,1 +3.15733333,3.0995,3.0425,2.744,3070,4/20/2021 14:47,female,1,1956,1 +3.632,3.4765,3.072,3.377,3070,4/20/2021 14:48,female,1,1956,1 +1.932,1.9652,1.851,2.171,3071,4/20/2021 14:46,male,1,1980,3 +1.5335,1.94271429,1.286,1.8115,3071,4/20/2021 14:47,male,1,1980,3 +1.142,0.93316667,1.04,0.9856,3072,4/20/2021 14:51,female,1,2001,3 +0.72885714,0.70357143,0.79772727,0.84142857,3072,4/20/2021 14:52,female,1,2001,3 +0.90175,0.63169231,0.84411111,1.0066,3073,4/20/2021 14:50,male,1,1963,3 +0.90854545,0.70883333,0.803125,0.8875,3073,4/20/2021 14:51,male,1,1963,3 +2.97333333,5.176,3.786,2.8455,3074,4/20/2021 14:55,female,1,1948,1 +2.586,2.36,2.197,1.99266667,3074,4/20/2021 14:56,female,1,1948,1 +0.896625,0.78035714,0.9348,0.897125,3075,4/20/2021 14:54,male,1,1970,2 +0.58709091,0.67609091,0.59606667,0.60090909,3075,4/20/2021 15:06,male,1,1970,2 +3.949,3.49866667,3.1575,2.10575,3076,4/20/2021 14:59,male,1,1943,2 +2.8535,1.749,1.463,2.07975,3076,4/20/2021 14:59,male,1,1943,2 +0.96483333,1.48833333,1.0626,0.9901,3077,4/20/2021 15:00,female,0,1971,2 +0.86828571,0.80673333,1.085,0.9435,3077,4/20/2021 15:01,female,0,1971,2 +2.416,2.4452,1.4565,1.5975,3078,4/20/2021 15:09,female,1,1959,2 +1.2235,1.57025,2.61,2.92075,3078,4/20/2021 15:18,female,1,1959,2 +1.394,1.585,1.45525,1.055,3079,4/20/2021 15:13,male,1,1971,2 +0.7184,0.753,0.859,0.96225,3079,4/20/2021 15:14,male,1,1971,2 +0.57709091,0.6915,0.60775,0.66391667,3080,4/20/2021 15:12,female,1,1971,2 +0.64427273,0.721,0.60558333,0.57321429,3080,4/20/2021 15:18,female,1,1971,2 +1.768,1.8476,1.8735,2.136,3081,4/20/2021 15:16,female,1,1955,2 +1.685,1.5085,1.36257143,2.147,3081,4/20/2021 15:16,female,1,1955,2 +0.80922222,1.01457143,0.9,0.791,3083,4/20/2021 15:37,male,1,2001,3 +8.43,7.015,1.6695,9.743,3084,4/20/2021 15:28,male,1,1942,1 +3.23,4.864,2.275,2.3054,3084,4/20/2021 15:29,male,1,1942,1 +1.09555556,0.9769,1.1505,1.39325,3085,4/20/2021 15:26,male,1,1971,2 +1.23188889,1.1308,1.1628,1.61125,3085,4/20/2021 15:25,male,1,1971,2 +1.1355,1.165,1.00116667,0.86625,3086,4/20/2021 15:26,female,1,1967,3 +1.12066667,0.840625,0.83972727,0.71855556,3086,4/20/2021 15:27,female,1,1967,3 +0.54925,0.5045,0.76966667,0.60123077,3087,4/20/2021 15:35,male,1,1973,2 +0.47138462,0.563,0.69827273,0.5828,3087,4/20/2021 15:27,male,1,1973,2 +1.24683333,1.03325,1.54083333,1.7118,3088,4/20/2021 15:36,female,1,1998,3 +0.76963636,0.7635,1.23257143,0.84622222,3088,4/20/2021 15:37,female,1,1998,3 +0.84058333,0.82842857,0.95214286,0.8665,3089,4/20/2021 15:34,female,1,1978,2 +0.754,0.76922222,0.864,0.9323,3089,4/20/2021 15:33,female,1,1978,2 +1.6155,1.701,1.69875,1.808,3090,4/20/2021 15:35,male,1,1967,2 +1.69666667,2.342,1.5956,1.52025,3090,4/20/2021 15:36,male,1,1967,2 +7.777,2.967,1.397,15.564,3091,4/20/2021 15:40,male,1,1941,1 +0.788,0.8433,0.95925,0.80166667,3092,4/20/2021 15:46,female,1,1959,3 +1.156875,1.063,0.89866667,1.14133333,3093,4/20/2021 15:49,female,1,1972,3 +1.043,10.777,1.47733333,1.745,3093,4/20/2021 15:50,female,1,1972,3 +0.8785,0.762,0.60383333,0.8327,3094,4/20/2021 15:57,female,1,1999,4 +0.742125,0.91314286,0.8593,0.8936,3094,4/20/2021 15:56,female,1,1999,4 +0.734,0.7223,0.729,0.9956,3095,4/20/2021 16:10,female,1,1981,2 +0.64083333,1.2695,0.742375,0.60833333,3095,4/21/2021 1:06,female,1,1981,2 +1.05666667,0.71928571,1.34642857,0.98011111,3097,4/20/2021 15:59,female,1,1953,1 +1.308,1.24633333,1.2015,1.17075,3097,4/20/2021 15:58,female,1,1953,1 +1.902,1.3915,1.36925,1.5046,3098,4/20/2021 15:57,female,1,1945,1 +1.562,1.39633333,1.7134,1.23025,3098,4/20/2021 15:59,female,1,1945,1 +1.672,1.91,2.4406,2.96733333,3099,4/20/2021 16:04,male,1,1945,1 +3.851,5.41,2.76533333,4.06,3099,4/20/2021 16:03,male,1,1945,1 +0.99657143,0.8445,1.3252,1.0955,3100,4/20/2021 16:10,female,1,1969,4 +5.67525,2.174,1.077,0.904,3101,4/20/2021 16:14,female,1,1945,1 +2.13457143,1.32066667,0.9889,1.05,3101,4/20/2021 16:16,female,1,1945,1 +1.08075,0.9745,1.31683333,1.0212,3102,4/20/2021 16:25,female,1,1946,1 +0.80685714,0.75171429,1.09075,0.99366667,3102,4/27/2021 14:18,female,1,1946,1 +1.16933333,0.92591667,1.3376,0.955375,3103,4/20/2021 16:29,female,1,1973,2 +1.201,1.477,1.162375,1.0992,3103,4/20/2021 16:29,female,1,1973,2 +2.78666667,1.6988,1.19666667,1.062125,3104,4/20/2021 16:34,male,1,1956,2 +1.33283333,1.7555,1.77716667,2.40633333,3104,4/20/2021 16:35,male,1,1956,2 +1.13516667,1.23,1.11733333,1.10355556,3105,4/20/2021 16:43,female,1,1979,3 +0.88222222,1.10355556,0.8514,1.07733333,3105,4/20/2021 16:44,female,1,1979,3 +1.42866667,1.267375,0.9485,0.859,3106,4/20/2021 16:59,female,1,2001,2 +2.02625,1.7515,1.877,1.875,3107,4/20/2021 17:15,male,1,1941,1 +2.85566667,2.699,2.3562,2.0875,3107,4/20/2021 17:16,male,1,1941,1 +1.05144444,1.337,1.62116667,0.996,3108,4/20/2021 16:58,male,1,1957,3 +1.14385714,1.14566667,0.96209091,1.07714286,3108,4/20/2021 16:57,male,1,1957,3 +3.9085,2.14966667,3.992,4.0285,3109,4/20/2021 17:05,male,1,1955,1 +2.55266667,2.73766667,2.34025,2.577,3109,4/20/2021 17:06,male,1,1955,1 +2.23066667,3.116,2.43,2.6105,3111,4/20/2021 23:30,female,1,1975,3 +2.175,4.05333333,2.5,2.574,3111,4/20/2021 23:29,female,1,1975,3 +1.23075,1.31033333,1.56366667,1.007,3112,4/20/2021 17:24,female,1,1975,2 +1.9985,1.51166667,2.2795,1.517875,3112,4/20/2021 17:32,female,1,1975,2 +3.77333333,2.41,6.505,3.16533333,3113,4/20/2021 17:33,female,1,1965,1 +1.89075,2.456,2.651,1.779,3113,4/20/2021 17:34,female,1,1965,1 +2.118,4.0675,1.43433333,1.924,3114,4/21/2021 21:48,female,1,1940,1 +1.8776,1.13625,1.912,1.51433333,3115,4/20/2021 17:37,female,1,1961,2 +1.63314286,2.17333333,1.6296,1.7585,3115,4/20/2021 17:38,female,1,1961,2 +2.7545,1.46433333,1.72133333,2.26633333,3116,4/20/2021 17:43,female,1,1956,1 +1.4616,1.44466667,2.19,2.0842,3116,4/20/2021 17:44,female,1,1956,1 +0.7795,0.99266667,0.86042857,0.99977778,3117,4/20/2021 18:07,female,1,1946,1 +0.786,0.95375,0.93625,0.96628571,3117,4/20/2021 18:07,female,1,1946,1 +0.63488889,0.66483333,0.57578571,0.65375,3118,4/20/2021 18:04,male,0,1953,1 +0.61833333,0.70211111,0.7985,0.62871429,3118,4/20/2021 18:05,male,0,1953,1 +1.04842857,1.244,1.212,0.96271429,3120,4/20/2021 18:12,male,1,1976,3 +1.09042857,1.09471429,1.136,1.20683333,3123,4/20/2021 18:10,male,1,1956,2 +0.84090909,0.89816667,1.16066667,1.0905,3123,4/20/2021 18:11,male,1,1956,2 +1.01771429,1.17033333,1.13775,1.22822222,3124,4/20/2021 18:32,male,1,1951,2 +1.31816667,1.4296,1.77025,1.2858,3124,4/20/2021 18:31,male,1,1951,2 +0.74588889,0.99314286,0.939375,1.063125,3125,4/20/2021 18:26,female,1,1980,3 +0.813,0.905,0.791,1.567,3125,4/20/2021 18:27,female,1,1980,3 +0.763,0.57463636,0.66772727,0.87333333,3126,4/20/2021 18:38,female,1,2001,4 +0.7049,0.6627,0.6988,0.74725,3126,4/20/2021 18:37,female,1,2001,4 +1.0105,1.4088,1.31966667,1.312,3127,4/20/2021 18:40,male,1,1976,2 +1.06371429,1.20185714,1.0384,1.30433333,3127,4/20/2021 18:41,male,1,1976,2 +0.62636364,0.63411111,0.5685,0.6460625,3128,4/20/2021 18:50,male,1,1950,2 +0.74009091,0.751,0.53569231,0.52527273,3128,4/20/2021 18:49,male,1,1950,2 +0.6745,1.72522222,0.61485714,0.7715,3129,4/20/2021 18:57,male,1,2000,4 +0.6365,0.538,0.64742857,0.62477778,3129,4/20/2021 18:58,male,1,2000,4 +1.2335,2.88033333,1.44166667,2.057,3130,4/20/2021 19:07,male,1,1941,1 +2.06733333,1.63175,1.69942857,2.3325,3130,4/20/2021 19:06,male,1,1941,1 +0.96471429,1.34675,1.473,1.598,3131,4/20/2021 19:03,female,1,1967,2 +0.92,1.0694,1.65,1.756,3131,4/20/2021 19:04,female,1,1967,2 +4.009,3.8175,1.649,1.5122,3132,4/20/2021 19:21,male,1,1959,2 +2.342,2.16666667,2.32266667,1.758,3132,4/20/2021 19:20,male,1,1959,2 +1.172,1.32628571,1.13414286,1.814,3133,4/20/2021 19:26,male,1,1963,2 +1.07728571,1.11871429,1.15583333,1.501,3133,4/20/2021 19:27,male,1,1963,2 +1.73928571,1.671,1.464,1.467,3134,4/20/2021 19:26,male,1,1960,2 +1.673,1.46683333,1.6235,1.61057143,3134,4/20/2021 19:26,male,1,1960,2 +0.9576,1.1712,1.233,1.04,3135,4/20/2021 19:41,male,1,1975,1 +1.17585714,1.21842857,1.466,1.846,3136,4/20/2021 19:55,female,1,1955,2 +1.0046,1.035,1.844,2.29966667,3136,4/20/2021 19:55,female,1,1955,2 +2.05933333,1.41071429,1.10016667,2.18266667,3137,4/20/2021 19:45,female,1,1960,1 +1.22585714,1.23516667,1.1114,1.39033333,3137,4/20/2021 19:45,female,1,1960,1 +2.181,2.4005,2.146,2.694,3138,4/20/2021 19:50,female,1,1958,1 +2.031,1.73728571,1.7318,1.7055,3138,4/20/2021 19:51,female,1,1958,1 +1.44525,1.86825,1.617,1.4916,3140,4/20/2021 19:55,male,1,1957,2 +1.19175,1.404625,1.3676,1.4094,3140,4/20/2021 19:55,male,1,1957,2 +0.8345,0.57308333,0.66,0.55652941,3141,4/21/2021 20:28,male,1,1978,4 +0.53784615,0.4838,0.84727273,0.46630769,3141,4/21/2021 20:29,male,1,1978,4 +0.91857143,1.10333333,0.97025,1.01955556,3142,4/20/2021 19:58,male,1,1977,3 +0.77036364,0.99283333,0.944,1.26757143,3142,4/20/2021 19:59,male,1,1977,3 +0.95628571,1.01575,0.87225,0.96625,3143,4/20/2021 20:04,male,1,1966,5 +0.86633333,0.9315,0.8822,0.9837,3143,4/20/2021 20:19,male,1,1966,5 +0.82616667,0.9134,0.60392857,0.7221,3144,4/20/2021 20:08,male,1,1972,2 +0.7645,0.60644444,0.60171429,0.6005,3144,4/20/2021 20:09,male,1,1972,2 +1.5004,2.436,2.411,2.423,3145,4/20/2021 20:08,male,1,1955,1 +1.36183333,2.12425,1.3985,1.57766667,3145,4/20/2021 20:09,male,1,1955,1 +4.26,2.859,2.1992,2.2175,3148,4/20/2021 20:09,male,1,1944,1 +1.737,3.39,1.795,3.054,3148,4/20/2021 20:10,male,1,1944,1 +0.888,0.82045455,0.838875,1.426,3149,4/21/2021 20:36,female,1,1974,3 +0.8182,0.755375,0.8946,1.0807,3149,4/21/2021 20:36,female,1,1974,3 +0.8348,0.71133333,0.64016667,0.7042,3150,4/20/2021 20:15,male,1,1971,4 +0.7921,0.66942857,0.87855556,0.63642857,3150,4/20/2021 20:16,male,1,1971,4 +1.3905,1.45066667,1.74533333,10.69,3151,4/20/2021 20:36,female,1,1953,1 +1.3905,1.45066667,1.74533333,10.69,3151,4/20/2021 20:36,female,1,1953,1 +0.98333333,1.41388889,0.8912,1.36714286,3152,4/21/2021 20:40,female,1,1955,2 +0.852,0.87716667,0.81266667,3.3814,3152,4/21/2021 20:40,female,1,1955,2 +3.6755,2.3835,2.282,2.452,3153,4/20/2021 20:30,female,1,1942,1 +6.102,4.004,2.185,4.083,3153,4/20/2021 20:31,female,1,1942,1 +1.43575,2.306,1.8095,1.40742857,3155,4/20/2021 20:32,female,1,1959,2 +1.947,1.84416667,1.296,1.7105,3155,4/20/2021 20:33,female,1,1959,2 +0.893375,0.97371429,0.78318182,0.7269,3156,4/20/2021 21:47,female,1,2001,2 +1.00633333,1.128625,0.97925,0.9425,3156,4/20/2021 21:07,female,1,2001,2 +0.85344444,1.02975,0.83688889,1.04,3156,4/20/2021 21:46,female,1,2001,2 +1.35542857,1.4212,1.17233333,1.40971429,3157,4/20/2021 20:51,male,1,1961,2 +0.99514286,1.0894,1.5844,1.06033333,3157,4/20/2021 20:52,male,1,1961,2 +1.7835,0.948,1.247,1.4635,3158,4/20/2021 20:57,male,1,1953,1 +0.93371429,0.88154545,0.891,0.9535,3159,4/20/2021 21:18,female,1,1967,4 +0.84683333,0.9012,0.8115,0.99722222,3159,4/20/2021 21:19,female,1,1967,4 +1.599,1.282,1.03228571,2.515,3160,4/20/2021 21:39,female,1,1959,1 +1.03883333,1.027,0.98166667,1.185,3160,4/20/2021 21:40,female,1,1959,1 +1.77233333,2.389,2.25066667,2.565,3162,4/20/2021 21:21,female,1,1948,1 +2.052,1.90466667,1.9146,2.2675,3162,4/20/2021 21:22,female,1,1948,1 +0.941625,0.897375,1.151,0.86509091,3163,4/20/2021 21:22,male,1,1956,2 +0.72155556,0.7275,0.78311111,0.622875,3163,4/20/2021 21:23,male,1,1956,2 +0.6775,1.277,0.806,0.901,3164,4/20/2021 21:37,female,1,1955,1 +0.79666667,4.5115,1.215,1.062,3164,4/20/2021 21:40,female,1,1955,1 +2.2055,1.581,2.05866667,2.15,3165,4/20/2021 21:28,female,1,1942,2 +2.0788,1.8426,1.96366667,2.2115,3165,4/20/2021 21:29,female,1,1942,2 +0.91575,0.92214286,1.0166,0.85114286,3166,4/20/2021 21:30,male,1,1976,5 +0.96,0.90963636,0.8638,0.8494,3166,4/20/2021 21:31,male,1,1976,5 +1.37,1.7974,1.4425,1.4226,3167,4/20/2021 21:33,female,1,1973,3 +1.476,1.132625,1.292,1.10575,3167,4/20/2021 21:34,female,1,1973,3 +1.218,1.18225,0.88225,0.9135,3169,4/20/2021 21:44,male,1,1968,3 +0.8433,1.0405,0.85033333,1.06757143,3170,4/20/2021 21:51,male,1,1979,4 +0.70536364,1.05633333,0.85628571,0.9294,3170,4/20/2021 21:52,male,1,1979,4 +2.31966667,2.06566667,2.58666667,2.28266667,3171,4/20/2021 21:56,male,1,1953,2 +1.91575,1.92625,2.1495,1.667,3171,4/20/2021 21:56,male,1,1953,2 +0.86627273,0.90675,0.75557143,1.869,3173,4/20/2021 22:02,female,1,2001,2 +0.791,0.91325,0.637,0.7924,3173,4/20/2021 22:03,female,1,2001,2 +1.2703,1.07766667,1.256,1.0236,3174,4/20/2021 22:05,male,0,1972,3 +1.2703,1.07766667,1.256,1.0236,3174,4/20/2021 22:05,male,0,1972,3 +1.44571429,1.2245,1.01242857,1.1875,3174,4/20/2021 21:58,male,0,1972,3 +0.99866667,1.7506,1.22733333,1.1058,3174,4/20/2021 21:59,male,0,1972,3 +1.407,1.1155,1.420625,0.91866667,3176,4/20/2021 22:13,male,1,1980,3 +1.2615,0.99083333,1.316,1.40075,3176,4/20/2021 22:14,male,1,1980,3 +0.81046154,1.048625,0.99357143,0.66866667,3177,4/20/2021 22:05,female,1,1980,4 +0.96,1.28725,1.46966667,1.016,3177,4/20/2021 22:06,female,1,1980,4 +4.26233333,3.313,1.831,1.649,3178,4/20/2021 22:07,male,1,1941,2 +2.542,1.323,2.1265,2.727,3178,4/20/2021 22:08,male,1,1941,2 +2.36766667,2.27633333,1.70666667,2.1726,3179,4/20/2021 22:09,male,1,1960,2 +2.4775,2.124,3.073,2.05725,3179,4/20/2021 22:10,male,1,1960,2 +3.3748,1.50766667,1.882,2.2035,3180,4/20/2021 22:28,male,1,1965,2 +1.9105,1.24966667,3.0495,2.27275,3180,4/20/2021 22:29,male,1,1965,2 +1.6044,1.582,1.4025,1.382375,3181,4/20/2021 22:16,female,1,1978,1 +1.6498,1.829,1.10542857,1.4416,3181,4/20/2021 22:16,female,1,1978,1 +0.79563636,0.7069,0.76644444,0.6755,3182,4/20/2021 22:17,male,1,2000,4 +0.68669231,0.5183125,0.82583333,0.64881818,3182,4/20/2021 22:18,male,1,2000,4 +2.258,1.4278,1.3475,2.20085714,3183,4/20/2021 22:24,male,1,1967,3 +1.431,1.00975,1.7275,1.01366667,3183,4/20/2021 22:24,male,1,1967,3 +0.99371429,1.1896,0.703625,0.75018182,3184,4/20/2021 22:24,male,1,1971,2 +0.6541,0.81983333,0.835375,0.868,3184,4/20/2021 22:25,male,1,1971,2 +1.959,1.68225,1.7078,1.5866,3186,4/20/2021 22:33,female,1,1959,1 +1.264,1.304,2.92,2.7786,3186,4/22/2021 21:04,female,1,1959,1 +2.044,2.3035,2.15225,2.02883333,3187,4/20/2021 22:31,female,1,1957,1 +1.05266667,1.60366667,1.7465,1.4064,3187,4/20/2021 22:32,female,1,1957,1 +0.499,0.61681818,0.61658333,0.55369231,3189,4/20/2021 22:59,male,1,2001,4 +0.732,0.56066667,0.45675,0.483,3189,4/20/2021 23:02,male,1,2001,4 +1.11933333,0.91925,1.12842857,0.963375,3190,4/20/2021 22:59,female,1,2001,3 +0.876125,0.75881818,0.92528571,0.72763636,3190,4/20/2021 23:01,female,1,2001,3 +1.91328571,1.56333333,1.1215,2.26033333,3192,4/20/2021 22:39,female,1,1940,1 +0.91933333,1.66575,2.30725,1.41928571,3192,4/20/2021 22:39,female,1,1940,1 +1.3214,1.10542857,1.25783333,1.11571429,3193,4/20/2021 22:46,male,0,1956,1 +5.153,1.69,1.7515,2.784,3193,4/22/2021 21:16,male,0,1956,1 +1.597,1.764,1.93033333,1.4965,3194,4/20/2021 22:57,female,1,1969,3 +1.00777778,1.6285,1.2415,0.72875,3194,4/20/2021 22:57,female,1,1969,3 +0.794,0.85666667,0.645,1.1395,3195,4/20/2021 23:01,male,1,1969,4 +1.47375,1.24283333,1.443,1.375,3196,4/20/2021 23:12,male,1,1957,1 +0.55953846,0.71246154,0.43869231,0.69357143,3198,4/20/2021 23:12,male,1,1976,3 +1.4344,0.793125,0.99028571,1.00677778,3199,4/20/2021 23:26,female,1,2001,3 +0.66111111,0.5276,0.863875,0.65375,3199,4/20/2021 23:27,female,1,2001,3 +0.93658333,0.97985714,0.93542857,0.85416667,3200,4/20/2021 23:23,male,1,1960,3 +0.69433333,0.95427273,0.79185714,0.7118,3200,4/20/2021 23:22,male,1,1960,3 +1.40366667,1.262875,1.1135,1.58785714,3201,4/20/2021 23:25,male,1,1961,2 +1.40366667,1.262875,1.1135,1.58785714,3201,4/20/2021 23:25,male,1,1961,2 +1.3921,1.793,1.2964,1.54566667,3201,4/20/2021 23:25,male,1,1961,2 +0.78541667,1.4336,1.102,0.8794,3202,4/20/2021 23:28,female,1,1971,3 +1.37266667,0.88618182,0.91083333,0.831,3202,4/20/2021 23:29,female,1,1971,3 +0.59390909,0.61706667,0.61377778,0.59385714,3203,4/20/2021 23:41,male,1,1978,3 +0.58894118,0.51027273,0.61522222,0.6167,3203,4/20/2021 23:42,male,1,1978,3 +0.81555556,0.915125,0.96066667,0.86963636,3204,4/20/2021 23:46,female,1,1971,1 +1.04933333,1.15633333,1.0005,0.99833333,3204,4/20/2021 23:47,female,1,1971,1 +0.70933333,0.717,0.81390909,0.92614286,3206,4/20/2021 23:46,female,1,1979,3 +0.723,0.61227273,0.85415385,0.7718,3206,4/20/2021 23:46,female,1,1979,3 +2.843,3.852,4.4605,4.307,3207,4/20/2021 23:45,male,1,1977,2 +3.963,3.0265,4.126,2.77466667,3207,4/20/2021 23:46,male,1,1977,2 +1.2256,1.09133333,1.305,1.71,3209,4/20/2021 23:51,female,1,1974,4 +1.017375,1.0166,1.3004,1.42742857,3209,4/20/2021 23:52,female,1,1974,4 +1.2358,0.673,1.33925,1.3034,3211,4/20/2021 23:58,male,1,1960,2 +1.2825,1.5684,1.37925,24.7718,3211,4/20/2021 23:59,male,1,1960,2 +0.75772727,0.632,0.83611111,0.671,3212,4/21/2021 0:06,female,1,1976,3 +0.84275,0.58827273,0.8277,0.8376,3212,4/21/2021 0:08,female,1,1976,3 +0.71242857,0.684,0.88990909,0.6825,3213,4/21/2021 0:08,female,0,1965,4 +0.944,0.799,0.8641,0.88163636,3213,4/21/2021 0:09,female,0,1965,4 +0.77585714,0.71871429,0.68423077,0.86458333,3214,4/21/2021 0:09,male,1,1967,3 +0.68413333,0.61946154,0.61281818,0.8288,3214,4/21/2021 0:10,male,1,1967,3 +3.99966667,7.373,3.506,5.359,3215,4/21/2021 0:09,male,1,1954,1 +5.541,6.544,5.669,7.652,3215,4/21/2021 0:10,male,1,1954,1 +2.647,2.6895,3.578,3.01666667,3216,4/21/2021 0:17,male,1,1952,1 +3.247,2.496,3.42966667,4.399,3216,4/21/2021 0:18,male,1,1952,1 +0.98857143,1.46716667,1.0431,1.12566667,3217,4/21/2021 0:17,male,1,1964,3 +1.43633333,0.88233333,1.051875,0.8578,3217,4/21/2021 0:17,male,1,1964,3 +1.28783333,1.31725,1.28225,1.1998,3218,4/21/2021 0:23,male,1,1973,2 +1.01,1.15733333,1.203,1.21214286,3218,4/21/2021 0:24,male,1,1973,2 +4.826,2.473,3.784,3.71033333,3220,4/21/2021 9:39,male,1,1957,1 +3.19733333,3.94433333,4.485,3.576,3220,4/21/2021 9:40,male,1,1957,1 +0.556,0.59457143,0.61322222,0.629125,3221,4/21/2021 0:33,female,1,1979,3 +0.66227273,0.78309091,0.75711111,0.79711111,3222,4/21/2021 0:37,female,1,1977,3 +0.69757143,0.77475,0.727,0.81341667,3222,4/21/2021 0:36,female,1,1977,3 +1.10383333,1.26066667,1.14442857,0.98836364,3223,4/21/2021 0:40,male,1,1974,4 +0.89190909,1.04175,0.80314286,0.86928571,3223,4/21/2021 0:41,male,1,1974,4 +0.7664,0.7255,0.9153,0.792,3224,4/21/2021 0:40,male,1,1959,4 +0.954,1.077,0.90655556,0.9695,3224,4/21/2021 0:40,male,1,1959,4 +0.72585714,1.036,0.89657143,0.86666667,3225,4/21/2021 0:42,male,1,1967,3 +0.841625,1.05709091,0.8092,0.97385714,3225,4/21/2021 0:43,male,1,1967,3 +0.952,1.17,1.02142857,1.45033333,3226,4/21/2021 0:59,female,1,1952,3 +1.233,0.856,1.6145,0.93958333,3226,4/21/2021 0:58,female,1,1952,3 +1.5656,2.0234,1.623,1.41475,3227,4/21/2021 0:57,male,1,1959,1 +1.7334,1.73925,1.5785,1.3642,3227,4/21/2021 0:57,male,1,1959,1 +1.55,1.652,1.41283333,1.66816667,3228,4/21/2021 0:59,male,1,1954,2 +1.55,1.652,1.41283333,1.66816667,3228,4/21/2021 0:59,male,1,1954,2 +1.6675,2.28233333,1.685,1.606,3228,4/21/2021 0:58,male,1,1954,2 +1.2868,1.421,1.4326,1.38733333,3229,4/21/2021 0:58,male,1,1969,2 +1.42042857,1.62375,2.121,1.563,3229,4/21/2021 0:59,male,1,1969,2 +1.10128571,1.76283333,2.568,1.6194,3230,4/21/2021 1:20,male,1,1970,3 +0.545,1.381,0.778,0.8595,3230,4/21/2021 2:33,male,1,1970,3 +2.012,0.94583333,1.01975,2.01925,3231,4/21/2021 1:53,male,1,2002,4 +1.23416667,1.2,1.6876,1.4655,3231,4/21/2021 2:02,male,1,2002,4 +3.466,2.98975,2.93466667,2.392,3232,4/21/2021 2:22,female,1,1950,2 +1.41133333,1.85125,1.81171429,2.728,3232,4/21/2021 2:23,female,1,1950,2 +0.718,0.80371429,0.73566667,0.74784615,3234,4/21/2021 1:08,female,1,1978,4 +0.73872727,0.80325,0.57706667,0.797875,3234,4/21/2021 1:09,female,1,1978,4 +2.009,1.134,1.16385714,1.80475,3235,4/21/2021 1:17,male,1,1957,1 +1.59342857,1.429,1.6462,1.357,3235,4/21/2021 1:17,male,1,1957,1 +1.2595,1.113,1.116,1.21925,3236,4/21/2021 1:17,male,1,1966,5 +1.381,1.6124,1.10133333,1.54928571,3236,4/21/2021 1:18,male,1,1966,5 +0.9845,1.131125,1.3684,1.096125,3236,4/21/2021 1:19,male,1,1966,5 +0.76375,0.7586,0.71354545,0.74081818,3238,4/21/2021 1:25,male,1,1971,5 +0.927375,0.75266667,1.464,0.86633333,3238,4/21/2021 1:24,male,1,1971,5 +1.097375,0.91766667,1.021,1.131,3239,4/21/2021 1:31,male,1,1959,2 +0.94525,1.047,1.15816667,0.99457143,3239,4/21/2021 1:32,male,1,1959,2 +1.0014,0.80884615,2.131,1.088,3240,4/21/2021 2:06,female,1,1975,3 +1.221,1.15657143,1.43233333,1.16125,3240,4/21/2021 1:53,female,1,1975,3 +0.915,0.89,0.871,0.984,3241,4/21/2021 1:39,female,1,1980,3 +0.6882,1.0495,0.74042857,0.8068,3241,4/21/2021 1:40,female,1,1980,3 +1.4034,1.02216667,0.9055,1.2705,3242,4/21/2021 2:06,female,0,1986,4 +1.29233333,1.364,1.1674,1.61175,3242,4/21/2021 1:53,female,0,1986,4 +2.556,1.52442857,1.33775,1.33525,3244,4/21/2021 2:20,female,1,1958,3 +1.196,0.961375,1.30933333,1.15957143,3244,4/21/2021 2:21,female,1,1958,3 +1.62966667,1.71475,1.018125,4.4195,3245,4/21/2021 2:21,male,1,1960,2 +2.312,3.75,2.4305,2.26266667,3245,4/21/2021 2:20,male,1,1960,2 +0.8302,0.88357143,0.895,0.98490909,3246,4/21/2021 2:36,male,1,1971,4 +1.06244444,0.85827273,0.7915,1.1975,3246,4/21/2021 2:36,male,1,1971,4 +1.10771429,1.33733333,1.00857143,1.02071429,3247,4/21/2021 2:44,male,1,1972,2 +0.78163636,1.94,0.9415,0.7231,3247,4/21/2021 2:44,male,1,1972,2 +0.77864286,0.762625,0.7959,0.65471429,3248,4/21/2021 3:02,female,1,1999,4 +1.35525,1.38857143,1.46375,1.49183333,3249,4/21/2021 6:22,male,1,1960,2 +1.2722,1.6725,1.118,1.2775,3249,4/21/2021 6:23,male,1,1960,2 +1.19025,1.299,1.1764,1.03785714,3250,4/21/2021 6:43,female,1,1956,2 +1.171125,1.16622222,1.23975,1.444,3250,4/21/2021 6:43,female,1,1956,2 +1.21716667,1.33675,1.2128,1.1666,3251,4/21/2021 6:59,male,1,1958,2 +1.39,1.34542857,1.25916667,1.445,3251,4/21/2021 7:00,male,1,1958,2 +1.1,1.13683333,1.075,1.09066667,3252,4/21/2021 9:08,male,1,1976,5 +1.3486,1.13275,1.34128571,1.17066667,3253,4/21/2021 9:36,male,1,1956,2 +1.06157143,1.2215,1.23728571,0.94766667,3253,4/21/2021 9:37,male,1,1956,2 +0.72666667,0.8428,0.70955556,0.66053846,3254,4/22/2021 14:53,male,1,1997,4 +0.96111111,0.98475,1.0474,1.11971429,3254,4/21/2021 9:43,male,1,1997,4 +0.72969231,0.604,0.71277778,0.93866667,3255,4/21/2021 9:59,female,1,1999,4 +0.58652941,0.58575,0.62563636,0.46846154,3255,4/21/2021 10:00,female,1,1999,4 +1.65275,1.50066667,2.15025,1.881,3256,4/21/2021 10:31,female,1,1976,2 +1.156,1.87285714,2.02566667,1.638,3256,4/21/2021 10:30,female,1,1976,2 +2.7495,3.23425,2.555,2.294,3257,4/21/2021 10:38,male,1,1960,2 +2.86,2.91533333,3.381,2.5025,3257,4/21/2021 10:38,male,1,1960,2 +1.3454,1.399,1.32133333,1.27525,3258,4/21/2021 10:39,male,1,1959,4 +0.8268,0.9358,0.85266667,0.91266667,3258,4/21/2021 10:39,male,1,1959,4 +0.8046,1.00728571,0.9845,0.928,3259,4/21/2021 10:49,female,1,1975,3 +0.951,1.36571429,1.0825,0.9384,3259,4/21/2021 10:50,female,1,1975,3 +2.65933333,2.7605,2.7,2.2105,3260,4/21/2021 11:00,female,1,1959,2 +2.9885,1.9696,3.664,2.49125,3260,4/21/2021 10:59,female,1,1959,2 +0.6685,0.901,0.62815385,0.73022222,3261,4/21/2021 11:00,female,1,2002,3 +0.60863636,0.76933333,0.684,0.6755,3261,4/21/2021 11:01,female,1,2002,3 +1.02325,1.025,1.089875,1.09314286,3262,4/21/2021 11:10,male,1,1972,3 +0.955,1.32816667,1.03966667,1.23183333,3262,4/21/2021 11:09,male,1,1972,3 +0.9372,0.95283333,1.18071429,0.9425,3263,4/21/2021 11:10,male,0,1970,3 +0.825,0.792625,0.922,0.757625,3263,4/21/2021 11:25,male,0,1970,3 +1.16411111,1.1832,1.5222,1.033,3264,4/21/2021 12:45,female,1,1986,2 +1.26842857,1.09557143,1.58075,1.00357143,3264,4/21/2021 12:45,female,1,1986,2 +1.29725,1.2075,1.24675,1.27128571,3265,4/21/2021 11:42,male,1,1970,3 +1.19466667,1.23183333,1.0695,1.51933333,3265,4/21/2021 11:43,male,1,1970,3 +1.526875,2.057,1.4285,1.2405,3267,4/21/2021 11:52,female,1,1966,2 +1.724,1.98316667,1.64575,1.52675,3267,4/21/2021 11:51,female,1,1966,2 +1.08816667,1.80933333,2.63733333,1.32466667,3268,4/21/2021 11:52,male,1,1963,2 +1.5555,1.6172,1.4274,1.5768,3268,4/21/2021 11:52,male,1,1963,2 +1.446,1.8454,1.61228571,1.3945,3269,4/21/2021 12:12,male,1,1969,3 +1.151,1.57433333,0.9732,1.1115,3269,4/21/2021 12:10,male,1,1969,3 +0.9735,0.723375,0.996875,0.685125,3270,4/21/2021 12:10,female,1,1963,3 +0.95,0.71675,0.7874,0.93042857,3270,4/21/2021 12:10,female,1,1963,3 +4.046,3.8445,3.932,2.451,3271,4/21/2021 12:23,female,1,1948,1 +2.213,2.71666667,1.902,2.754,3271,4/21/2021 12:22,female,1,1948,1 +2.245,1.107,1.16828571,1.28025,3272,4/21/2021 12:36,female,1,1974,3 +1.0682,1.35633333,1.1246,1.3845,3273,4/21/2021 12:37,male,1,1981,3 +0.91344444,1.45733333,0.988,1.26025,3273,4/21/2021 12:37,male,1,1981,3 +1.225375,1.4412,1.161,0.95133333,3274,4/21/2021 12:48,female,1,1958,2 +1.10344444,1.0174,1.16466667,1.02671429,3274,4/21/2021 12:49,female,1,1958,2 +0.87963636,1.0785,1.1456,1.189625,3275,4/21/2021 12:57,female,1,1954,3 +1.79966667,1.5585,1.41942857,1.52571429,3275,4/21/2021 12:58,female,1,1954,3 +1.05733333,0.97671429,1.21457143,1.31925,3276,4/21/2021 13:02,male,1,1958,3 +0.6765,0.759,1.1341,0.78,3276,4/21/2021 13:03,male,1,1958,3 +1.31033333,0.71771429,0.83430769,0.86828571,3277,4/21/2021 13:11,female,1,1958,3 +1.17842857,0.9494,1.07983333,1.14055556,3277,4/21/2021 13:11,female,1,1958,3 +0.59028571,0.75654545,0.6705,0.64742857,3278,4/21/2021 13:26,male,1,1961,4 +0.86,0.65825,0.6552,0.67309091,3278,4/21/2021 13:26,male,1,1961,4 +2.9705,2.4875,3.796,2.533,3279,4/21/2021 13:45,female,1,1953,2 +1.80775,1.86033333,1.9104,2.459,3279,4/21/2021 13:45,female,1,1953,2 +1.9345,2.1,1.99083333,2.07375,3280,4/21/2021 13:49,male,1,1951,2 +1.763,1.93466667,2.1716,1.918,3280,4/21/2021 13:51,male,1,1951,2 +2.468,3.5665,3.008,3.928,3281,4/21/2021 13:52,female,1,1949,2 +3.44866667,2.6,2.24833333,3.404,3281,4/21/2021 13:52,female,1,1949,2 +1.0247,1.3338,0.97528571,1.0358,3282,4/21/2021 13:54,male,1,1969,3 +1.2215,1.346625,1.171125,1.09566667,3282,4/21/2021 13:53,male,1,1969,3 +1.003625,0.99375,0.9377,0.90088889,3284,4/21/2021 14:09,female,0,1976,3 +1.05875,1.05955556,1.0208,0.92257143,3284,4/21/2021 14:37,female,0,1976,3 +2.46466667,2.785,2.051,2.01933333,3285,4/21/2021 14:13,male,1,1938,1 +2.731,3.01425,2.12933333,3.607,3285,4/21/2021 14:12,male,1,1938,1 +1.47242857,1.86066667,1.52366667,1.7665,3286,4/21/2021 14:16,female,1,1958,2 +1.823,1.71666667,1.81633333,1.85528571,3286,4/21/2021 14:17,female,1,1958,2 +4.17666667,2.031,3.44133333,2.861,3287,4/21/2021 14:20,female,0,1960,3 +2.22033333,2.53633333,3.461,1.851,3287,4/21/2021 14:19,female,0,1960,3 +1.292,1.162,1.14,1.124,3288,4/21/2021 14:23,male,1,1949,2 +1.361,1.065,0.822,1.619,3288,4/21/2021 14:23,male,1,1949,2 +1.614,1.8325,1.6472,1.79675,3289,4/21/2021 14:44,male,1,1960,1 +1.186,1.121,0.994,0.911,3290,4/21/2021 14:42,female,0,1945,1 +1.6842,1.4502,1.931,2.1105,3291,4/21/2021 14:54,male,1,1960,2 +1.82666667,1.917,1.6995,1.99275,3291,4/21/2021 14:54,male,1,1960,2 +1.212,1.3105,1.162,2.77,3292,4/21/2021 17:47,female,1,1956,1 +1.4466,1.6752,1.253,1.2708,3293,4/21/2021 15:56,female,1,1958,3 +1.37775,1.6398,1.2496,1.856,3293,4/21/2021 15:57,female,1,1958,3 +1.56,2.504,2.0425,1.41533333,3294,4/21/2021 16:11,female,1,1969,3 +1.05188889,1.34442857,0.963875,1.4295,3294,4/21/2021 16:11,female,1,1969,3 +2.165,2.5785,2.24525,2.1065,3295,4/21/2021 16:14,male,1,1969,3 +2.347,1.99166667,1.5652,1.7858,3295,4/21/2021 16:15,male,1,1969,3 +1.854,2.17825,2.20975,2.2085,3296,4/21/2021 16:37,male,0,1954,2 +1.57825,1.47466667,1.945,1.62525,3296,4/21/2021 16:37,male,0,1954,2 +0.91477778,1.39642857,0.89325,1.115,3297,4/21/2021 17:50,male,1,1978,3 +0.77016667,0.764,0.80075,0.83783333,3297,4/21/2021 22:24,male,1,1978,3 +1.594,2.756,2.126,1.95933333,3298,4/21/2021 17:49,male,1,1961,2 +1.14211111,1.2698,0.93266667,0.922625,3298,4/21/2021 22:00,male,1,1961,2 +1.336,1.755,1.52925,1.3756,3299,4/21/2021 18:00,male,1,1947,2 +1.336,1.755,1.52925,1.3756,3299,4/21/2021 18:00,male,1,1947,2 +1.3068,0.94083333,2.5555,1.856,3299,4/21/2021 18:01,male,1,1947,2 +0.94933333,1.176,0.92357143,1.3068,3300,4/21/2021 18:20,male,1,1949,1 +1.03527273,1.126,2.1275,1.3186,3301,4/21/2021 20:25,female,1,1957,2 +1.05714286,0.97516667,1.1098,1.13975,3301,4/21/2021 20:26,female,1,1957,2 +0.9332,1.338,1.42177778,1.2512,3302,4/21/2021 20:38,male,1,1970,3 +1.03066667,1.072,2.68366667,0.95725,3302,4/21/2021 20:39,male,1,1970,3 +0.87369231,0.84316667,1.3795,1.22216667,3303,4/21/2021 20:59,female,1,1976,3 +1.271,0.76414286,0.99542857,0.97081818,3303,4/21/2021 21:00,female,1,1976,3 +0.7185,0.65507143,0.9784,0.96963636,3304,4/21/2021 21:11,female,1,1971,3 +1.31475,0.762,0.637,2.03866667,3304,4/21/2021 21:11,female,1,1971,3 +1.006,1.058,0.82133333,0.776,3305,4/21/2021 19:33,male,1,1960,1 +1.2735,1.036,1.07633333,1.4148,3305,4/21/2021 19:34,male,1,1960,1 +1.4455,1.2485,1.470375,1.49,3306,4/21/2021 18:05,male,1,1978,2 +2.299,2.531,2.11833333,2.719,3306,4/21/2021 21:50,male,1,1978,2 +3.31525,2.743,2.5195,2.75766667,3307,4/21/2021 18:33,female,1,1948,3 +3.2676,2.123,2.2885,2.275,3307,4/21/2021 18:34,female,1,1948,3 +1.16857143,1.16033333,0.96427273,1.3236,3308,4/21/2021 18:46,female,1,1974,4 +1.06475,0.9986,0.982,1.271875,3308,4/21/2021 18:47,female,1,1974,4 +1.3225,1.7155,0.935,1.85671429,3309,4/21/2021 20:38,female,1,1955,2 +0.779,1.0605,1.02175,0.753,3309,4/21/2021 20:39,female,1,1955,2 +1.21383333,1.2095,1.4025,1.53983333,3310,4/21/2021 19:01,male,1,1956,3 +1.05557143,1.04716667,1.06244444,1.46875,3310,4/21/2021 19:01,male,1,1956,3 +0.8115,0.545,1.002,1.308,3311,4/21/2021 19:03,male,1,1972,4 +1.2724,1.24225,1.05045455,1.415,3313,4/21/2021 19:15,male,1,1957,3 +0.801,1.02016667,1.2948,1.584,3313,4/21/2021 19:16,male,1,1957,3 +2.98,3.611,2.16,4.162,3314,4/21/2021 21:58,male,1,1972,2 +20.499,4.017,1.678,3.495,3314,4/21/2021 19:28,male,1,1972,2 +1.703,1.55,1.838,1.753,3315,4/21/2021 19:34,male,1,1959,2 +1.65966667,2.0085,1.7866,1.708,3315,4/21/2021 19:34,male,1,1959,2 +2.986,3.579,2.256,4.339,3316,4/21/2021 19:42,male,1,1961,2 +2.21633333,1.7935,2.031,2.365,3317,4/21/2021 19:47,male,1,1953,2 +1.789,1.7995,1.899,2.4535,3317,4/21/2021 19:47,male,1,1953,2 +0.74842857,0.9666,0.99811111,0.98145455,3318,4/21/2021 19:44,male,0,1978,4 +0.97,0.807875,1.179,0.82944444,3318,4/21/2021 21:52,male,0,1978,4 +1.29142857,1.50516667,1.198,1.7495,3319,4/21/2021 19:52,male,1,1960,3 +1.38,1.50983333,1.39825,1.5508,3319,4/21/2021 19:53,male,1,1960,3 +0.77733333,0.903625,0.87755556,0.75592308,3320,4/21/2021 19:55,female,1,1974,4 +0.76318182,0.98516667,0.97016667,1.04955556,3320,4/21/2021 21:43,female,1,1974,4 +1.33116667,1.3765,1.23133333,1.87933333,3321,4/21/2021 20:08,male,1,1960,3 +1.12385714,0.91175,1.3765,2.0328,3321,4/21/2021 20:08,male,1,1960,3 +0.75557143,0.746,0.71464286,0.7795,3322,4/21/2021 20:13,male,1,1968,2 +2.61225,2.9805,2.19266667,3.1635,3323,4/21/2021 22:08,female,1,1956,2 +3.00166667,3.5495,3.955,2.89033333,3323,4/21/2021 21:10,female,1,1956,2 +0.9118,0.862875,0.75545455,0.83391667,3325,4/21/2021 20:24,male,1,1964,2 +0.69072727,0.832,0.7295,0.72473333,3325,4/21/2021 20:25,male,1,1964,2 +0.90863636,0.76555556,0.81057143,1.21066667,3326,4/21/2021 20:30,male,1,2001,3 +1.55775,0.87928571,1.0622,1.67328571,3326,4/21/2021 20:30,male,1,2001,3 +0.6211,0.54123077,0.52929412,0.48753333,3327,4/21/2021 20:37,female,1,1982,5 +0.56257143,0.54733333,0.624,0.80654545,3327,4/21/2021 20:38,female,1,1982,5 +0.704,0.456,0.863,0.912,3328,4/21/2021 20:50,male,1,2002,4 +0.67133333,0.6915,0.75725,0.54085714,3328,4/21/2021 20:50,male,1,2002,4 +0.94928571,1.202,1.03990909,1.1974,3329,4/21/2021 20:52,female,1,1955,3 +2.1295,1.10433333,1.354,1.57857143,3329,4/21/2021 20:53,female,1,1955,3 +0.60771429,0.5136,0.47873333,0.54791667,3330,4/21/2021 20:51,male,1,1992,5 +0.50609091,0.54058333,0.5354,0.51210526,3330,4/21/2021 20:51,male,1,1992,5 +0.69675,0.7333,0.6324,0.61541667,3331,4/21/2021 21:14,female,1,1970,4 +0.632,0.86228571,0.7224,0.8124,3331,4/21/2021 21:15,female,1,1970,4 +1.1375,1.51175,0.965875,2.952,3332,4/21/2021 21:19,male,1,1952,2 +2.0386,1.998,1.96066667,1.5016,3332,4/21/2021 21:18,male,1,1952,2 +0.48135714,0.497,0.5879,0.52210526,3333,4/21/2021 21:29,male,1,1970,4 +0.5302,0.54281818,0.70033333,0.55388235,3333,4/21/2021 21:30,male,1,1970,4 +1.5095,1.23833333,1.38316667,1.201,3334,4/21/2021 21:38,male,1,1975,3 +1.235375,1.15375,1.28133333,1.1342,3334,4/21/2021 21:37,male,1,1975,3 +1.148,1.10266667,1.18414286,1.14616667,3335,4/21/2021 21:42,male,1,1958,1 +1.720125,1.2902,1.30533333,1.1044,3335,4/21/2021 21:42,male,1,1958,1 +0.63325,0.49772727,0.79663636,0.653,3336,4/21/2021 21:46,female,1,1992,3 +0.608,0.51055556,1.17616667,0.74509091,3336,4/21/2021 21:51,female,1,1992,3 +1.0975,1.14314286,0.89177778,0.9286,3337,4/21/2021 21:48,female,1,1974,4 +0.7714,0.91423077,0.80555556,0.88533333,3337,4/21/2021 21:48,female,1,1974,4 +1.5706,1.31775,1.18775,1.603,3338,4/21/2021 21:56,male,1,1957,2 +1.662,1.501,1.67383333,1.5826,3338,4/21/2021 21:56,male,1,1957,2 +1.28016667,1.22133333,1.22244444,1.23766667,3339,4/21/2021 22:01,female,1,1960,2 +1.28333333,1.20066667,1.46163636,1.2248,3339,4/21/2021 22:01,female,1,1960,2 +1.02771429,0.98744444,0.86144444,0.81957143,3340,4/21/2021 22:00,male,1,1973,3 +0.8795,0.7927,0.8975,0.79566667,3340,4/21/2021 22:00,male,1,1973,3 +1.157,1.38611111,1.23814286,1.3055,3341,4/21/2021 22:11,female,1,1941,1 +1.3102,1.24128571,1.24714286,1.102,3341,4/21/2021 22:12,female,1,1941,1 +1.25371429,1.58,1.14725,1.37814286,3342,4/21/2021 22:16,female,1,1959,2 +1.36375,1.37757143,1.27271429,1.41175,3342,4/21/2021 22:17,female,1,1959,2 +3.577,4.688,3.757,3.14533333,3343,4/21/2021 22:19,female,1,1934,1 +5.55,3.9485,5.124,3.9095,3343,4/21/2021 22:19,female,1,1934,1 +2.008,2.677,3.818,2.22366667,3344,4/21/2021 22:36,male,1,1938,1 +2.038,2.2975,2.39325,2.46333333,3344,4/21/2021 22:37,male,1,1938,1 +2.1315,1.9865,2.239,2.075,3345,4/21/2021 22:35,female,1,1960,2 +2.59866667,3.4915,2.579,2.2575,3345,4/21/2021 22:36,female,1,1960,2 +0.87966667,0.96488889,0.97711111,1.12983333,3346,4/21/2021 22:47,female,1,1997,5 +0.7596,1.0532,1.2176,1.18266667,3346,4/21/2021 22:48,female,1,1997,5 +1.6515,1.4888,1.1972,1.30257143,3347,4/21/2021 22:53,female,1,1975,2 +1.614,1.48483333,1.2578,2.01575,3347,4/21/2021 22:54,female,1,1975,2 +2.46033333,1.513,1.8514,1.33525,3348,4/21/2021 23:09,male,0,2000,3 +4.8855,3.871,3.0325,1.89,3350,4/21/2021 23:12,female,1,1970,2 +0.96022222,1.0474,1.00983333,1.07344444,3351,4/21/2021 23:25,male,1,1955,3 +0.82183333,1.0076,0.88828571,1.05916667,3351,4/21/2021 23:26,male,1,1955,3 +1.27616667,1.263,0.9345,1.52033333,3352,4/21/2021 23:27,male,1,1981,2 +1.4256,1.3458,1.072,1.5354,3352,4/21/2021 23:28,male,1,1981,2 +0.77657143,1.53983333,1.0458,1.20175,3354,4/21/2021 23:30,male,1,1953,2 +1.114,0.89154545,1.058,0.954125,3354,4/21/2021 23:31,male,1,1953,2 +1.209,1.1295,2.2145,1.7334,3355,4/21/2021 23:33,female,1,1977,2 +0.71685714,1.0596,1.367,1.24988889,3355,4/21/2021 23:33,female,1,1977,2 +1.3942,2.5725,2.0176,1.6285,3356,4/21/2021 23:42,male,1,1960,3 +1.81771429,1.1705,1.2005,1.399,3357,4/21/2021 23:49,male,1,1985,3 +2.4145,1.387,1.0365,1.4226,3357,4/21/2021 23:49,male,1,1985,3 +1.60625,1.3365,1.13375,1.4398,3359,4/22/2021 0:15,male,1,1976,2 +1.053,1.15714286,1.289,1.41428571,3359,4/22/2021 0:15,male,1,1976,2 +1.31566667,1.7252,2.2416,1.987,3362,4/22/2021 0:30,male,1,1971,2 +2.4435,2.0468,2.421,1.589,3362,4/22/2021 0:29,male,1,1971,2 +3.26,11.473,9.228,3.125,3364,4/22/2021 0:31,female,1,1955,1 +5.116,4.292,4.449,2.947,3364,4/22/2021 0:31,female,1,1955,1 +1.224375,1.11457143,1.2814,1.32875,3365,4/22/2021 0:36,male,1,1999,4 +1.4465,1.0604,1.032,1.0835,3365,4/22/2021 0:36,male,1,1999,4 +3.149,4.703,3.42,3.8375,3367,4/22/2021 0:49,female,1,1952,1 +3.464,3.33133333,6.379,4.635,3367,4/22/2021 0:49,female,1,1952,1 +1.31033333,1.0256,1.49233333,1.13583333,3368,4/22/2021 0:55,female,0,1975,3 +1.24683333,1.002375,1.4055,1.45183333,3368,4/22/2021 0:54,female,0,1975,3 +0.93825,0.71333333,1.258375,1.2044,3369,4/22/2021 0:58,male,0,1977,3 +0.688,0.96155556,1.433125,1.1114,3369,4/22/2021 0:59,male,0,1977,3 +1.0916,1.13571429,1.497,1.90357143,3370,4/22/2021 1:13,male,1,1951,3 +1.194875,1.293,1.2924,1.307,3370,4/22/2021 1:12,male,1,1951,3 +1.3795,1.794,1.5985,1.6425,3371,4/22/2021 1:17,male,1,1955,3 +0.74776923,0.6496,1.236,0.95733333,3371,4/22/2021 1:17,male,1,1955,3 +1.25557143,1.06071429,1.294,1.064125,3372,4/22/2021 1:33,male,1,1957,3 +1.12111111,1.07414286,1.78175,1.22,3372,4/22/2021 1:32,male,1,1957,3 +0.62516667,0.686,0.6875,5.051,3373,4/22/2021 1:45,female,1,1960,3 +1.492,3.71133333,2.6272,2.108,3375,4/22/2021 15:01,female,1,1948,1 +2.054,2.01916667,1.644,1.7165,3375,4/22/2021 15:02,female,1,1948,1 +0.9765,0.9525,0.71766667,1.052,3376,4/22/2021 15:17,male,1,1968,2 +0.6815,0.69063636,0.60542857,0.68841667,3376,4/22/2021 15:18,male,1,1968,2 +0.70983333,0.66266667,0.6238125,0.57633333,3377,4/22/2021 15:40,female,1,1975,3 +0.7233,0.72508333,0.7304,0.55175,3377,4/22/2021 15:40,female,1,1975,3 +1.05333333,1.115,1.142,1.02983333,3378,4/22/2021 16:26,male,1,1966,2 +1.057,1.02325,1.02088889,1.112,3378,4/22/2021 16:26,male,1,1966,2 +1.02988889,0.80775,0.86811111,0.9495,3379,4/22/2021 21:41,male,1,1955,1 +2.6455,1.3275,1.29166667,2.802,3379,4/22/2021 21:40,male,1,1955,1 +1.02988889,0.80775,0.86811111,0.9495,3379,4/22/2021 21:41,male,1,1955,1 +0.58592308,0.61036364,0.608375,0.76557143,3380,4/23/2021 14:08,female,1,1996,4 +0.68384615,0.59141667,0.7295,0.66833333,3380,4/23/2021 14:09,female,1,1996,4 +0.54618182,0.5883125,0.6212,0.69672727,3381,4/23/2021 14:11,male,1,1968,2 +0.686375,0.55854545,0.751,0.65322222,3381,4/23/2021 14:10,male,1,1968,2 +0.6318125,0.71914286,0.43285714,0.47970833,3382,4/23/2021 14:53,male,1,1958,3 +0.837,1.18,0.74,0.851,3382,4/23/2021 14:54,male,1,1958,3 +0.5977,1.0488,0.604,0.58161538,3383,4/23/2021 15:23,male,1,1961,4 +0.5805,0.657,0.5788,0.965,3383,4/23/2021 15:22,male,1,1961,4 +0.72242857,0.862,0.84909091,0.70575,3384,4/23/2021 18:07,female,1,2000,3 +0.8908125,0.659,0.68814286,0.87657143,3384,4/23/2021 18:08,female,1,2000,3 +0.8335,0.7334,0.82676923,0.68185714,3385,4/23/2021 18:22,male,1,2001,3 +0.668,0.8833,0.76553846,0.63944444,3385,4/23/2021 18:21,male,1,2001,3 +0.60514286,0.549125,0.75116667,0.675,3386,4/23/2021 18:26,female,1,2001,3 +0.53318182,0.7979,0.78118182,0.75588889,3386,4/23/2021 18:31,female,1,2001,3 +0.64383333,0.951375,0.71555556,0.89422222,3387,4/23/2021 18:53,male,1,1948,2 +0.64383333,0.951375,0.71555556,0.89422222,3387,4/23/2021 18:53,male,1,1948,2 +0.81025,0.86766667,0.72636364,0.76066667,3387,4/23/2021 18:52,male,1,1948,2 +1.46266667,0.966,1.0322,0.978,3388,4/23/2021 22:45,female,1,1966,3 +1.0068,0.79407692,1.1528,0.76127273,3388,4/23/2021 22:46,female,1,1966,3 +0.83628571,0.95133333,0.99383333,0.988,3389,4/24/2021 12:50,male,1,1971,2 +0.85233333,0.85757143,0.81891667,1.041875,3389,4/24/2021 12:50,male,1,1971,2 +0.66266667,0.73177778,0.79591667,0.7673,3390,4/24/2021 13:51,male,1,1971,3 +0.934,0.70971429,1.06842857,0.7182,3390,4/24/2021 13:52,male,1,1971,3 +1.448,1.76714286,1.38566667,1.67316667,3392,4/25/2021 15:22,female,1,1959,1 +2.1565,1.87766667,1.71025,1.528,3392,4/25/2021 15:22,female,1,1959,1 +2.0962,2.862,1.7818,1.791,3393,4/26/2021 20:03,male,1,1960,1 +1.908,2.0235,1.7796,1.7,3393,4/26/2021 20:04,male,1,1960,1 +1.831,1.76875,2.42025,1.8465,3394,4/26/2021 20:21,female,1,1961,1 +2.17,2.086,1.93533333,8.36,3394,4/26/2021 20:21,female,1,1961,1 +2.3965,3.377,1.636,2.456,3395,4/26/2021 20:49,female,1,1958,1 +1.5026,1.32875,1.711,1.6992,3395,4/26/2021 20:50,female,1,1958,1 +0.54157143,0.54681818,0.83088889,0.65730769,3409,5/7/2021 19:12,male,1,1995,4 +0.53890909,0.52686667,0.59688889,0.6948,3409,5/7/2021 19:16,male,1,1995,4 +0.5444,0.7144,0.6756,0.8158,3409,5/24/2021 10:19,male,1,1995,4 +0.5546,0.582,0.5576,0.5892,3409,6/2/2021 8:46,male,1,1995,4 +0.5286875,0.46216667,0.64957143,0.657,3409,5/7/2021 19:13,male,1,1995,4 +0.5604,0.5294,0.6098,0.6682,3409,5/21/2021 9:49,male,1,1995,4 +0.535,0.5532,0.6052,0.606,3409,5/27/2021 13:07,male,1,1995,4 +0.589,0.5098,0.5838,0.6448,3409,6/6/2021 15:28,male,1,1995,4 +0.55733333,0.515375,0.58425,0.58684211,3409,5/7/2021 19:14,male,1,1995,4 +0.578,0.5382,0.5942,0.708,3409,5/22/2021 10:44,male,1,1995,4 +0.6122,0.4686,0.577,0.5184,3409,5/31/2021 9:44,male,1,1995,4 +0.5664,0.487,0.6618,0.6904,3409,6/7/2021 10:55,male,1,1995,4 +0.56325,0.6175,0.59053846,0.59545455,3409,5/7/2021 19:15,male,1,1995,4 +0.5444,0.7144,0.6756,0.8158,3409,5/24/2021 10:19,male,1,1995,4 +0.5218,0.7054,0.6142,1.0196,3409,6/1/2021 9:15,male,1,1995,4 +0.848,1.492,0.694,1.59733333,3410,5/7/2021 19:30,male,1,1995,4 +1.135,1.452,0.728,2.27733333,3410,5/7/2021 19:31,male,1,1995,4 +0.95666667,2.0395,2.9205,0.92625,3410,5/7/2021 19:31,male,1,1995,4 +1.16533333,1.1805,0.681,0.89266667,3410,5/7/2021 19:29,male,1,1995,4 +0.76,1.904,1.019,1.176,3410,5/7/2021 19:32,male,1,1995,4 +1.1375,1.06542857,1.98025,1.492,3411,5/7/2021 19:27,male,1,1985,3 +0.81416667,0.92541667,1.1915,0.74322222,3411,5/7/2021 19:30,male,1,1985,3 +0.9332,0.95928571,1.71957143,0.789625,3411,5/7/2021 19:33,male,1,1985,3 +0.88611111,0.84442857,1.38375,0.99416667,3411,5/7/2021 19:28,male,1,1985,3 +0.7162,0.7564,1.036,0.90171429,3411,5/7/2021 19:31,male,1,1985,3 +0.85209091,0.897,1.13455556,0.898,3411,5/7/2021 19:29,male,1,1985,3 +0.799,1.10933333,1.1345,0.9,3411,5/7/2021 19:31,male,1,1985,3 +0.9278,0.87633333,1.35333333,0.79407692,3411,5/7/2021 19:29,male,1,1985,3 +0.64575,0.6688,0.88742857,1.101,3411,5/7/2021 19:32,male,1,1985,3 +0.661875,0.58445455,0.81853846,0.64554545,3412,5/7/2021 19:17,male,1,1994,3 +0.99257143,0.943,1.1558,1.25628571,3412,5/7/2021 19:12,male,1,1994,3 +0.81142857,0.71444444,0.75857143,0.899625,3412,5/7/2021 19:18,male,1,1994,3 +0.830875,0.726,1.08971429,0.723,3412,5/7/2021 19:15,male,1,1994,3 +0.71733333,0.742375,1.003375,0.75418182,3412,5/7/2021 19:17,male,1,1994,3 +0.86883333,0.7056,0.786125,0.6039,3413,5/7/2021 19:23,male,1,1981,3 +0.54822222,0.668,0.6833125,0.584,3413,5/7/2021 19:25,male,1,1981,3 +0.6968,0.8232,0.7674,0.6764,3413,5/26/2021 12:47,male,1,1981,3 +0.766,0.85576923,0.81644444,0.75522222,3413,5/7/2021 19:23,male,1,1981,3 +0.9782,0.932,0.8432,0.9306,3413,5/22/2021 11:33,male,1,1981,3 +0.6904,0.8282,0.69,0.7552,3413,5/27/2021 7:50,male,1,1981,3 +1.1035,0.89366667,1.187125,1.06114286,3413,5/7/2021 19:22,male,1,1981,3 +0.66125,0.90733333,0.78236364,0.66166667,3413,5/7/2021 19:24,male,1,1981,3 +0.7708,0.8118,0.9374,0.9598,3413,5/23/2021 10:18,male,1,1981,3 +0.6498,0.8848,0.6862,0.753,3413,5/28/2021 8:40,male,1,1981,3 +1.0286,0.7475,0.80646154,0.66858333,3413,5/7/2021 19:22,male,1,1981,3 +0.77992308,0.95688889,0.808,0.79642857,3413,5/7/2021 19:25,male,1,1981,3 +0.6674,0.8472,0.7964,0.7086,3413,5/25/2021 8:23,male,1,1981,3 +0.6272,0.5834,0.6668,0.8108,3413,6/3/2021 8:15,male,1,1981,3 +0.7901,0.66109091,0.81654545,0.75528571,3414,5/7/2021 19:11,female,1,1994,3 +0.60963636,0.55992308,0.79955556,0.8722,3414,5/7/2021 19:16,female,1,1994,3 +0.589,0.6836,0.72544444,0.62238462,3414,5/7/2021 19:12,female,1,1994,3 +0.7108,0.7368,0.6974,0.8064,3414,5/22/2021 23:53,female,1,1994,3 +0.65435714,0.628,0.7805,0.83055556,3414,5/7/2021 19:14,female,1,1994,3 +0.62078571,0.61190909,0.7642,0.66622222,3414,5/7/2021 19:15,female,1,1994,3 +0.7488,0.6628,0.6844,0.6404,3415,5/28/2021 6:15,female,1,1994,3 +0.81966667,0.841,0.96128571,0.8338,3415,5/7/2021 19:20,female,1,1994,3 +0.8982,0.4992,0.9364,0.587,3415,5/22/2021 8:34,female,1,1994,3 +0.6334,0.6854,0.6562,0.5914,3415,5/30/2021 15:03,female,1,1994,3 +0.7564,0.893875,0.72742857,0.9837,3415,5/7/2021 19:21,female,1,1994,3 +0.6136,0.6182,0.6918,0.5132,3415,5/23/2021 14:08,female,1,1994,3 +0.6692,0.55,0.6678,0.604,3415,5/31/2021 9:09,female,1,1994,3 +0.86428571,0.76557143,1.42642857,1.02125,3415,5/7/2021 19:15,female,1,1994,3 +0.8375,0.80957143,0.72228571,0.74355556,3415,5/7/2021 19:22,female,1,1994,3 +0.6806,0.563,0.716,0.6878,3415,5/26/2021 16:28,female,1,1994,3 +0.866,0.919,0.8962,0.856,3415,5/7/2021 19:18,female,1,1994,3 +0.6934,0.7424,0.7924,0.5934,3415,5/21/2021 10:16,female,1,1994,3 +0.7292,0.654,0.6684,0.6364,3415,5/27/2021 13:13,female,1,1994,3 +0.723,0.7857,0.714,0.8968,3416,5/7/2021 19:41,male,1,1986,4 +0.6925,0.67858333,0.6677,0.7614,3416,5/7/2021 19:42,male,1,1986,4 +0.714875,0.59711765,0.676,0.65841667,3416,5/7/2021 19:42,male,1,1986,4 +0.79925,0.8269,0.76446667,0.905,3416,5/7/2021 18:34,male,1,1986,4 +0.78536364,0.64783333,0.63963636,0.65166667,3416,5/7/2021 19:43,male,1,1986,4 +0.66676923,0.550625,0.591625,0.80266667,3417,5/7/2021 19:13,female,1,1997,3 +0.5392,0.64866667,0.65733333,0.59257143,3417,5/7/2021 19:16,female,1,1997,3 +0.66954545,0.5865,0.64372727,0.64377778,3417,5/7/2021 19:14,female,1,1997,3 +0.5678,0.653625,0.55594118,0.61966667,3417,5/7/2021 19:14,female,1,1997,3 +0.52388889,0.50417647,0.70636364,0.49322222,3417,5/7/2021 19:15,female,1,1997,3 +0.814,0.879,0.00E+00,0.815,3418,5/21/2021 12:18,male,1,1996,3 +0.00E+00,0.00E+00,0.953,0.00E+00,3418,6/3/2021 6:07,male,1,1996,3 +4.156,0.82,0.778,1.048,3418,5/7/2021 19:37,male,1,1996,3 +0.9085,0.967,0.6555,0.00E+00,3418,5/22/2021 13:22,male,1,1996,3 +0.8,0.00E+00,1.056,1.253,3418,6/5/2021 4:08,male,1,1996,3 +0.988,1.18933333,0.8864,0.8,3418,5/7/2021 19:39,male,1,1996,3 +1.6168,0.9912,1.943,1.1252,3418,5/23/2021 13:06,male,1,1996,3 +0.983,1.6675,1.044,1.096,3418,5/7/2021 19:41,male,1,1996,3 +0.6986,0.7692,0.766,0.9778,3418,6/2/2021 19:10,male,1,1996,3 +0.67723077,0.63883333,0.86357143,0.81544444,3421,5/7/2021 19:35,female,1,1970,2 +1.0828,0.928,0.937,0.8452,3421,6/3/2021 20:54,female,1,1970,2 +1.0762,0.877,0.848,0.7952,3421,6/8/2021 9:19,female,1,1970,2 +0.73744444,0.909,0.85683333,1.097,3421,5/7/2021 19:36,female,1,1970,2 +0.8276,0.6734,0.9844,1.0176,3421,6/5/2021 21:23,female,1,1970,2 +0.9766,1.1498,1.847,1.047,3421,5/22/2021 18:53,female,1,1970,2 +0.9436,0.7254,0.7486,0.797,3421,6/6/2021 21:21,female,1,1970,2 +1.4205,2.13383333,1.381,1.00966667,3421,5/7/2021 19:19,female,1,1970,2 +0.675875,0.80275,0.724,0.9448,3421,5/7/2021 19:35,female,1,1970,2 +0.9386,1.3,1.0908,1.1616,3421,6/2/2021 21:24,female,1,1970,2 +0.6834,0.8402,0.877,1.1844,3421,6/7/2021 21:34,female,1,1970,2 +0.85066667,0.84144444,0.99611111,0.80571429,3421,5/7/2021 19:34,female,1,1970,2 +0.75725,0.734,0.82983333,0.86983333,3423,5/7/2021 19:20,male,1,1994,4 +0.71316667,1.07890909,0.79585714,0.90825,3423,5/7/2021 19:17,male,1,1994,4 +0.62763636,0.65785714,0.80025,0.7328125,3423,5/7/2021 19:20,male,1,1994,4 +0.710375,0.57544444,0.72222222,0.76725,3423,5/7/2021 19:18,male,1,1994,4 +0.75125,0.89316667,0.74885714,0.68881818,3423,5/7/2021 19:19,male,1,1994,4 +0.65290909,0.56257143,0.60146154,0.62909091,3424,5/7/2021 19:28,male,0,1996,3 +0.62726667,0.6325,0.60378571,0.61177778,3424,5/7/2021 19:29,male,0,1996,3 +0.75425,0.812375,0.83433333,0.929,3424,5/7/2021 19:25,male,0,1996,3 +0.63033333,0.62928571,0.54388235,0.6847,3424,5/7/2021 19:31,male,0,1996,3 +0.792375,0.78575,0.70435714,1.2185,3424,5/7/2021 19:27,male,0,1996,3 +1.13357143,1.31,1.12333333,1.5375,3425,5/8/2021 14:56,female,1,1961,3 +1.11290909,1.20066667,1.53833333,1.0575,3425,5/8/2021 14:59,female,1,1961,3 +1.5105,1.615,1.6795,1.176,3425,5/8/2021 14:57,female,1,1961,3 +1.22583333,1.129,1.239875,0.90985714,3425,5/8/2021 15:00,female,1,1961,3 +1.73525,1.42066667,1.2755,1.10966667,3425,5/8/2021 14:58,female,1,1961,3 +1.07925,1.13233333,1.1318,1.14409091,3425,5/8/2021 14:55,female,1,1961,3 +1.011875,1.4556,1.263,0.92136364,3425,5/8/2021 14:58,female,1,1961,3 +1.34971429,1.56875,1.406,2.254,3427,5/8/2021 18:42,female,1,1956,3 +1.1222,1.35925,1.58916667,1.37083333,3427,5/8/2021 18:43,female,1,1956,3 +1.3162,1.41925,1.699,1.8915,3427,5/8/2021 18:40,female,1,1956,3 +1.41166667,1.91875,1.3506,1.6925,3427,5/8/2021 18:43,female,1,1956,3 +2.5385,1.9508,1.4455,1.3455,3427,5/8/2021 18:41,female,1,1956,3 +1.543,1.421,1.424,2.061,3430,5/13/2021 14:41,female,1,1961,2 +1.7685,2.663,1.56575,2.136,3430,5/13/2021 14:43,female,1,1961,2 +5.916,1.18133333,1.252,1.447,3430,5/13/2021 14:44,female,1,1961,2 +1.205,1.314,1.2435,1.472,3430,5/13/2021 14:45,female,1,1961,2 +3.648,1.4035,1.47,1.31775,3430,5/13/2021 14:40,female,1,1961,2 +3.891,0.755,1.6275,2.04533333,3432,5/17/2021 10:50,male,1,1963,5 +1.1336,0.986,2.5702,1.603,3432,5/25/2021 7:50,male,1,1963,5 +0.647,0.724,0.6206,0.667,3432,6/4/2021 8:08,male,1,1963,5 +14.865,1.179,1.9935,0.8475,3432,5/20/2021 10:09,male,1,1963,5 +0.982,1.0694,0.8354,1.0042,3432,5/26/2021 9:25,male,1,1963,5 +0.7074,0.7916,0.7204,0.6868,3432,6/5/2021 22:47,male,1,1963,5 +0.928,0.895,0.95966667,1.183,3432,5/24/2021 9:34,male,1,1963,5 +0.808,0.7542,0.7288,0.8232,3432,5/27/2021 7:46,male,1,1963,5 +0.7078,0.84,0.59333333,0.6854,3432,6/6/2021 11:17,male,1,1963,5 +1.1336,0.986,2.5702,1.603,3432,5/25/2021 7:50,male,1,1963,5 +0.7114,0.6754,0.7606,0.8602,3432,6/3/2021 9:14,male,1,1963,5 +0.709125,0.71366667,0.65575,0.66058333,3433,5/14/2021 20:47,male,1,1998,4 +0.8036,0.595,0.8186,0.6288,3434,5/21/2021 7:57,male,1,1994,3 +0.581,0.6032,0.6642,0.6072,3434,6/8/2021 7:56,male,1,1994,3 +0.6232,0.6474,0.7688,0.7044,3434,5/22/2021 7:24,male,1,1994,3 +0.722,0.546,0.6,0.665,3434,6/9/2021 7:30,male,1,1994,3 +0.5538,0.6646,0.6092,0.6144,3434,5/23/2021 10:41,male,1,1994,3 +0.7328,0.6454,0.677,0.6676,3434,6/10/2021 7:27,male,1,1994,3 +1.0146,0.6026,0.6274,0.6656,3434,6/7/2021 7:27,male,1,1994,3 +0.7696,0.722,0.9338,0.8274,3436,5/23/2021 11:09,female,1,1996,3 +0.7834,0.825,0.6854,0.755,3436,6/12/2021 16:40,female,1,1996,3 +0.9272,0.6134,1.0006,0.887,3436,6/8/2021 12:34,female,1,1996,3 +0.7296,0.682,0.7002,0.8692,3436,6/10/2021 15:00,female,1,1996,3 +0.7558,0.7398,1.142,0.8756,3436,5/22/2021 10:56,female,1,1996,3 +0.637,0.6392,0.8296,0.6748,3436,6/11/2021 16:59,female,1,1996,3 +0.9322,1.028,0.9634,1.0462,3438,5/26/2021 11:28,female,1,1960,3 +0.8382,1.0526,1.0344,0.9728,3438,5/26/2021 10:59,female,1,1960,3 +0.9766,1.0038,1.0116,1.1188,3438,5/26/2021 13:48,female,1,1960,3 +1.048,1.1256,1.0402,0.928,3438,5/26/2021 11:06,female,1,1960,3 +0.9952,1.061,0.9022,1.0962,3438,5/26/2021 11:15,female,1,1960,3 +1.3054,1.5776,1.4596,1.5104,3439,5/31/2021 12:57,female,1,1958,3 +1.8622,1.4938,1.2122,1.4592,3439,5/31/2021 13:00,female,1,1958,3 +1.7296,1.6836,1.3422,1.7904,3439,5/31/2021 12:46,female,1,1958,3 +1.2986,0.9482,1.1842,1.4522,3439,5/31/2021 13:02,female,1,1958,3 +1.3054,1.5776,1.4596,1.5104,3439,5/31/2021 12:57,female,1,1958,3 +1.2042,1.2842,1.5832,1.3438,3440,6/3/2021 11:14,male,1,1955,2 +1.1534,1.1816,1.2214,1.4284,3440,6/3/2021 11:29,male,1,1955,2 +1.1694,1.1986,1.2624,1.2174,3440,6/3/2021 13:40,male,1,1955,2 +1.1876,1.2404,1.0726,1.1168,3440,6/3/2021 9:33,male,1,1955,2 +1.228,1.3282,1.4682,1.337,3440,6/3/2021 13:49,male,1,1955,2 +1.7686,1.7162,1.556,1.6696,3441,6/6/2021 15:31,male,1,1959,1 +1.35,1.4212,1.428,1.5102,3441,6/6/2021 15:33,male,1,1959,1 +1.4488,1.5732,1.5886,1.3106,3441,6/6/2021 15:31,male,1,1959,1 +1.3528,1.3226,1.462,1.2804,3441,6/6/2021 15:34,male,1,1959,1 +1.5362,1.3658,1.5052,1.5484,3441,6/6/2021 15:32,male,1,1959,1 +1.323,1.2904,1.189,1.2956,3441,6/6/2021 15:33,male,1,1959,1 +5.3436,4.0946,3.2526,5.0188,3444,6/4/2021 21:24,male,1,1959,1 +2.5784,2.522,2.7282,2.7788,3445,6/4/2021 22:24,male,1,1958,1 +1.1572,1.775,1.9046,1.5914,3446,6/6/2021 13:45,male,1,1958,3 +1.1378,1.3772,1.9064,1.01,3446,6/6/2021 14:05,male,1,1958,3 +1.3084,1.076,1.2222,2.5686,3446,6/6/2021 14:02,male,1,1958,3 +1.1978,1.3692,1.3396,0.986,3446,6/6/2021 14:03,male,1,1958,3 +1.0454,2.2322,1.3892,0.8694,3446,6/6/2021 14:04,male,1,1958,3 +1.3034,1.3226,1.3532,1.1862,3447,6/7/2021 12:37,male,1,1953,3 +1.2438,1.218,1.2912,1.199,3447,6/7/2021 12:35,male,1,1953,3 +1.2734,1.1316,1.3564,1.2892,3447,6/7/2021 12:38,male,1,1953,3 +1.1348,1.2886,1.1342,1.265,3447,6/7/2021 12:36,male,1,1953,3 +1.1964,1.2754,1.299,1.2686,3447,6/7/2021 12:36,male,1,1953,3 +0.68,1.0448,0.7488,0.8398,3448,6/8/2021 10:22,male,1,1960,3 +0.7584,0.8176,1.0976,1.1856,3448,6/8/2021 10:22,male,1,1960,3 +1.4716,1.6444,1.2524,1.4552,3448,6/8/2021 10:21,male,1,1960,3 +0.8192,1.0816,1.1088,0.5552,3448,6/8/2021 10:23,male,1,1960,3 +0.939,1.4344,1.3562,1.409,3448,6/8/2021 10:21,male,1,1960,3 +0.7232,1.11175,0.6208,1.1136,3449,6/8/2021 11:17,female,1,1959,3 +0.8,1.79933333,0.8154,0.9864,3449,6/8/2021 11:56,female,1,1959,3 +0.9018,1.2248,0.9128,1.3276,3449,6/8/2021 11:56,female,1,1959,3 +1.0396,1.364,0.958,1.1146,3449,6/8/2021 11:16,female,1,1959,3 +1.1614,1.2182,0.7568,1.113,3449,6/8/2021 11:57,female,1,1959,3 +1.3086,1.4116,1.2974,1.2128,3450,6/11/2021 8:36,female,1,1959,3 +0.6414,1.0366,0.8142,0.9758,3450,6/11/2021 8:38,female,1,1959,3 +1.0832,1.2176,0.9932,1.094,3450,6/11/2021 8:36,female,1,1959,3 +1.051,1.0448,1.2332,1.3438,3450,6/11/2021 8:37,female,1,1959,3 +0.8982,1.1144,1.1116,1.0814,3450,6/11/2021 8:37,female,1,1959,3 +0.7346,0.6836,0.9658,0.9098,3453,6/24/2021 8:32,male,1,1990,4 +0.9146,0.8366,0.7562,0.8352,3453,6/21/2021 14:09,male,1,1990,4 +0.6144,0.7612,0.7432,0.716,3453,6/25/2021 12:35,male,1,1990,4 +0.726,0.7042,0.6618,0.6264,3453,6/22/2021 8:38,male,1,1990,4 +0.7562,1.1188,0.545,0.5814,3453,6/26/2021 11:22,male,1,1990,4 +0.6874,0.662,0.7174,0.905,3453,6/23/2021 7:45,male,1,1990,4 +0.7906,0.8926,0.7244,1.1148,3453,6/27/2021 15:03,male,1,1990,4 +1.22825,1.592,1.13925,1.37766667,3454,6/27/2021 11:44,male,1,1991,3 +2.36,2.4208,2.564,1.822,3455,6/29/2021 15:14,female,1,1960,1 +2.1704,1.5394,1.8284,1.6858,3456,6/29/2021 15:27,male,1,1958,2 +2.5528,2.5938,2.7084,2.0998,3457,6/29/2021 15:41,female,1,1959,1 +3.1008,1.795,1.6702,1.9114,3458,6/29/2021 15:56,male,1,1960,3 +0.8972,1.0564,1.237,1.233,3461,9/9/2021 18:23,male,1,1992,3 diff --git a/fda-citation-service/rest-service/src/test/resources/integration-test.after b/fda-citation-service/rest-service/src/test/resources/integration-test.after deleted file mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..0000000000000000000000000000000000000000 --- a/fda-citation-service/rest-service/src/test/resources/integration-test.after +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/fda-citation-service/rest-service/src/test/resources/integration-test.before b/fda-citation-service/rest-service/src/test/resources/integration-test.before deleted file mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..0000000000000000000000000000000000000000 --- a/fda-citation-service/rest-service/src/test/resources/integration-test.before +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/fda-citation-service/services/pom.xml b/fda-citation-service/services/pom.xml index 8ef68baceb79c4913280a938eada2ac0e7776e12..d170aecc4b05d570e8b76e236671bea508eaecf3 100644 --- a/fda-citation-service/services/pom.xml +++ b/fda-citation-service/services/pom.xml @@ -13,15 +13,6 @@ <version>0.0.1-SNAPSHOT</version> <name>fda-citation-service-services</name> - <dependencies> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>api</artifactId> - <version>${project.version}</version> - <scope>compile</scope> - </dependency> - </dependencies> - <build> <plugins> <plugin> diff --git a/fda-citation-service/services/src/main/java/at/tuwien/config/JacksonConfig.java b/fda-citation-service/services/src/main/java/at/tuwien/config/JacksonConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..9d59953bb99cafd6743522fbc6f665c15c1cedf5 --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/config/JacksonConfig.java @@ -0,0 +1,20 @@ +package at.tuwien.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JacksonConfig { + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper() + .findAndRegisterModules() + .registerModule(new JavaTimeModule()) + .registerModule(new Jdk8Module()); + } + +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/config/QueryServiceConfig.java b/fda-citation-service/services/src/main/java/at/tuwien/config/QueryServiceConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..42aa55e7ad7427c9cd373ead1680057dfafb2b98 --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/config/QueryServiceConfig.java @@ -0,0 +1,28 @@ +package at.tuwien.config; + +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; + +import javax.validation.constraints.NotNull; + +@Configuration +public class QueryServiceConfig { + + @Getter + @NotNull + @Value("${fda.query.endpoint}") + private String queryEndpoint; + + @Bean + public RestTemplate queryTemplate() { + return new RestTemplateBuilder() + .uriTemplateHandler(new DefaultUriBuilderFactory("http://" + queryEndpoint)) + .build(); + } + +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-citation-service/services/src/main/java/at/tuwien/config/ReadyConfig.java index 7b3b31152b7c32368985f9f528c0eeb0882e872f..1c52a4bc38d502512281920cd32b223aa5c5bf4e 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/config/ReadyConfig.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/config/ReadyConfig.java @@ -1,19 +1,27 @@ package at.tuwien.config; import com.google.common.io.Files; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.context.event.EventListener; +import javax.validation.constraints.NotNull; import java.io.File; import java.io.IOException; @Configuration public class ReadyConfig { + @NotNull + @Value("${fda.ready.path}") + private String readyPath; + @EventListener(ApplicationReadyEvent.class) public void init() throws IOException { - Files.touch(new File("/ready")); + Files.touch(new File(readyPath)); } } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/config/ZenodoConfig.java b/fda-citation-service/services/src/main/java/at/tuwien/config/ZenodoConfig.java index 63a07d24247cefebdf1f2fca9b8fb4d852e79485..25647383e953bec2980395ca85b370d7340d4482 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/config/ZenodoConfig.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/config/ZenodoConfig.java @@ -1,10 +1,6 @@ package at.tuwien.config; -import at.tuwien.exception.ZenodoAuthenticationException; -import at.tuwien.utils.ApiTemplateInterceptor; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import at.tuwien.exception.RemoteAuthenticationException; import lombok.Getter; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Value; @@ -13,10 +9,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.DefaultUriBuilderFactory; -import org.springframework.web.util.UriBuilderFactory; import javax.validation.constraints.NotNull; -import java.util.List; @Log4j2 @Configuration @@ -31,27 +25,18 @@ public class ZenodoConfig { @Value("${zenodo.api_key}") private String apiKey; - public String getApiKey() throws ZenodoAuthenticationException { + public String getApiKey() throws RemoteAuthenticationException { if (apiKey == null || apiKey.isEmpty()) { log.debug("api key is {}", apiKey); - throw new ZenodoAuthenticationException("Did not find a valid Zenodo API key in environment variable ZENODO_API_KEY"); + throw new RemoteAuthenticationException("Did not find a valid Zenodo API key in environment variable ZENODO_API_KEY"); } return apiKey; } @Bean - public ObjectMapper objectMapper() { - return new ObjectMapper() - .findAndRegisterModules() - .registerModule(new JavaTimeModule()) - .registerModule(new Jdk8Module()); - } - - @Bean - public RestTemplate apiTemplate() { - final UriBuilderFactory factory = new DefaultUriBuilderFactory(zenodoEndpoint); + public RestTemplate zenodoTemplate() { return new RestTemplateBuilder() - .uriTemplateHandler(factory) + .uriTemplateHandler(new DefaultUriBuilderFactory(zenodoEndpoint)) .build(); } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoNotFoundException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java similarity index 55% rename from fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoNotFoundException.java rename to fda-citation-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java index 7795fbffd411d11dd83535994dcbd6bf334e56bf..a5e90754898f19f6cce8938d2385f3f9fecd43e4 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoNotFoundException.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java @@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(code = HttpStatus.NOT_FOUND) -public class ZenodoNotFoundException extends Exception { +public class QueryNotFoundException extends Exception { - public ZenodoNotFoundException(String msg) { + public QueryNotFoundException(String msg) { super(msg); } - public ZenodoNotFoundException(String msg, Throwable thr) { + public QueryNotFoundException(String msg, Throwable thr) { super(msg, thr); } - public ZenodoNotFoundException(Throwable thr) { + public QueryNotFoundException(Throwable thr) { super(thr); } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoApiException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteApiException.java similarity index 57% rename from fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoApiException.java rename to fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteApiException.java index a2eaedfb5fb0bf0b41b790e358a73db69df7e2e9..6021bf0298d3cfe85ec385def1c56def12295d68 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoApiException.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteApiException.java @@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(code = HttpStatus.BAD_REQUEST) -public class ZenodoApiException extends Exception { +public class RemoteApiException extends Exception { - public ZenodoApiException(String msg) { + public RemoteApiException(String msg) { super(msg); } - public ZenodoApiException(String msg, Throwable thr) { + public RemoteApiException(String msg, Throwable thr) { super(msg, thr); } - public ZenodoApiException(Throwable thr) { + public RemoteApiException(Throwable thr) { super(thr); } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoAuthenticationException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteAuthenticationException.java similarity index 53% rename from fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoAuthenticationException.java rename to fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteAuthenticationException.java index ca5e6e5fffd23bfb2f3b1e9191296fb1b535996a..bc5b8fdd5923c969960035e0f0e46473da20a659 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoAuthenticationException.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteAuthenticationException.java @@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(code = HttpStatus.FORBIDDEN) -public class ZenodoAuthenticationException extends Exception { +public class RemoteAuthenticationException extends Exception { - public ZenodoAuthenticationException(String msg) { + public RemoteAuthenticationException(String msg) { super(msg); } - public ZenodoAuthenticationException(String msg, Throwable thr) { + public RemoteAuthenticationException(String msg, Throwable thr) { super(msg, thr); } - public ZenodoAuthenticationException(Throwable thr) { + public RemoteAuthenticationException(Throwable thr) { super(thr); } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteDatabaseException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteDatabaseException.java new file mode 100644 index 0000000000000000000000000000000000000000..6372bf0d88b767b17826990e60047d8624179e0e --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteDatabaseException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.METHOD_NOT_ALLOWED) +public class RemoteDatabaseException extends Exception { + + public RemoteDatabaseException(String msg) { + super(msg); + } + + public RemoteDatabaseException(String msg, Throwable thr) { + super(msg, thr); + } + + public RemoteDatabaseException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteFileException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteFileException.java new file mode 100644 index 0000000000000000000000000000000000000000..552ecc43e6e25a912f1d93f013cbd018ea853195 --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteFileException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class RemoteFileException extends Exception { + + public RemoteFileException(String msg) { + super(msg); + } + + public RemoteFileException(String msg, Throwable thr) { + super(msg, thr); + } + + public RemoteFileException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoFileTooLargeException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteFileTooLargeException.java similarity index 55% rename from fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoFileTooLargeException.java rename to fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteFileTooLargeException.java index 855b68bf6f35fc0d6886ccc7b623c104969a7432..ad38f2919c435a5bcb91814b343ddfecd50c6320 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoFileTooLargeException.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteFileTooLargeException.java @@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(code = HttpStatus.UNPROCESSABLE_ENTITY) -public class ZenodoFileTooLargeException extends Exception { +public class RemoteFileTooLargeException extends Exception { - public ZenodoFileTooLargeException(String msg) { + public RemoteFileTooLargeException(String msg) { super(msg); } - public ZenodoFileTooLargeException(String msg, Throwable thr) { + public RemoteFileTooLargeException(String msg, Throwable thr) { super(msg, thr); } - public ZenodoFileTooLargeException(Throwable thr) { + public RemoteFileTooLargeException(Throwable thr) { super(thr); } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteNotFoundException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..d76caca5ac1b6017e7db1cef2bb65eef71eec224 --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class RemoteNotFoundException extends Exception { + + public RemoteNotFoundException(String msg) { + super(msg); + } + + public RemoteNotFoundException(String msg, Throwable thr) { + super(msg, thr); + } + + public RemoteNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoUnavailableException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java similarity index 54% rename from fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoUnavailableException.java rename to fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java index bb9d8c93b3aeb66c6e8765fbb971e1355e0876bc..3f6700d06b277d59ccbf812136faec277261357d 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/exception/ZenodoUnavailableException.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java @@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(code = HttpStatus.NO_CONTENT) -public class ZenodoUnavailableException extends Exception { +public class RemoteUnavailableException extends Exception { - public ZenodoUnavailableException(String msg) { + public RemoteUnavailableException(String msg) { super(msg); } - public ZenodoUnavailableException(String msg, Throwable thr) { + public RemoteUnavailableException(String msg, Throwable thr) { super(msg, thr); } - public ZenodoUnavailableException(Throwable thr) { + public RemoteUnavailableException(Throwable thr) { super(thr); } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/exception/TableServiceException.java b/fda-citation-service/services/src/main/java/at/tuwien/exception/TableServiceException.java new file mode 100644 index 0000000000000000000000000000000000000000..c1a91362facc6ae719979c1045b805c265e8bdc9 --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/exception/TableServiceException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class TableServiceException extends Exception { + + public TableServiceException(String msg) { + super(msg); + } + + public TableServiceException(String msg, Throwable thr) { + super(msg, thr); + } + + public TableServiceException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/mapper/FileMapper.java b/fda-citation-service/services/src/main/java/at/tuwien/mapper/FileMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..32bf59a0e72faedf7b67d186b5711860a1543aa0 --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/mapper/FileMapper.java @@ -0,0 +1,16 @@ +package at.tuwien.mapper; + +import at.tuwien.api.database.deposit.files.FileDto; +import at.tuwien.api.database.query.QueryDto; +import at.tuwien.entities.database.query.File; +import at.tuwien.entities.database.query.Query; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface FileMapper { + + File fileDtoToFile(FileDto data); + + FileDto fileToFileDto(File data); + +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java b/fda-citation-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..fd00ba0470b45e064e27fd7e5eddf2125eec1b01 --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java @@ -0,0 +1,14 @@ +package at.tuwien.mapper; + +import at.tuwien.api.database.query.QueryDto; +import at.tuwien.entities.database.query.Query; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface QueryMapper { + + Query queryDtoToQuery(QueryDto data); + + QueryDto queryToQueryDto(Query data); + +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/mapper/ZenodoMapper.java b/fda-citation-service/services/src/main/java/at/tuwien/mapper/ZenodoMapper.java index 8ffe6f155ff5ac3838df5d292a281818cbc4ebc2..ef23f7c034ad4e370e0a5df6241ec82580d84aa7 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/mapper/ZenodoMapper.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/mapper/ZenodoMapper.java @@ -1,6 +1,12 @@ package at.tuwien.mapper; +import at.tuwien.api.database.deposit.DepositDto; +import at.tuwien.api.database.deposit.DepositTzDto; +import at.tuwien.api.database.query.QueryDto; +import at.tuwien.entities.database.query.Query; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; import org.springframework.core.io.ByteArrayResource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -10,6 +16,9 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.List; @Mapper(componentModel = "spring") @@ -33,4 +42,22 @@ public interface ZenodoMapper { return bodyBuilder.build(); } + @Mappings({ + @Mapping(source = "metadata.prereserveDoi.doi", target = "doi"), + @Mapping(source = "id", target = "depositId"), + @Mapping(ignore = true, target = "id") + }) + Query depositTzDtoToQuery(DepositTzDto data); + + default Instant localDateTimeToInstant(LocalDateTime data) { + return data.toInstant(ZoneOffset.UTC); + } + + @Mappings({ + @Mapping(source = "created", target = "executionTimestamp"), + @Mapping(source = "metadata.prereserveDoi.doi", target = "doi"), + @Mapping(source = "recordId", target = "depositId"), + }) + QueryDto depositChangeResponseDtoToQueryDto(DepositDto data); + } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/repository/jpa/FileRepository.java b/fda-citation-service/services/src/main/java/at/tuwien/repository/jpa/FileRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..f73c1d2aa2cc16c0bb43908f07a56cefc389d6dc --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/repository/jpa/FileRepository.java @@ -0,0 +1,9 @@ +package at.tuwien.repository.jpa; + +import at.tuwien.entities.database.query.File; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface FileRepository extends JpaRepository<File, Long> { +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/repository/jpa/QueryRepository.java b/fda-citation-service/services/src/main/java/at/tuwien/repository/jpa/QueryRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..2adab8fe5aae9245c6982c7b5fa14f636ce14daa --- /dev/null +++ b/fda-citation-service/services/src/main/java/at/tuwien/repository/jpa/QueryRepository.java @@ -0,0 +1,18 @@ +package at.tuwien.repository.jpa; + +import at.tuwien.entities.database.Database; +import at.tuwien.entities.database.query.Query; +import at.tuwien.entities.database.table.Table; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface QueryRepository extends JpaRepository<Query, Long> { + + List<Query> findByDatabase(Database database); + + Optional<Query> findByDatabaseAndId(Database database, Long id); +} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/service/FileService.java b/fda-citation-service/services/src/main/java/at/tuwien/service/FileService.java index ff8fada54575ab81033e572dc86c353804590564..1f3c06722b1fce4a1dda750c425cd85e0749aadf 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/service/FileService.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/service/FileService.java @@ -1,12 +1,10 @@ package at.tuwien.service; -import at.tuwien.api.zenodo.files.FileResponseDto; -import at.tuwien.api.zenodo.files.FileUploadDto; +import at.tuwien.entities.database.query.File; import at.tuwien.exception.*; import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; -import java.io.File; +import javax.transaction.Transactional; import java.util.List; @Service @@ -16,59 +14,56 @@ public interface FileService { * Upload a new file to a remote server for a given database-table id pair and metadata * * @param databaseId The database-table id paid - * @param tableId The database-table id pair - * @param data The metadata - * @param resource The file + * @param queryId The query id * @return The new file - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoApiException Something other went wrong - * @throws ZenodoNotFoundException The deposit id was not found on the remote server - * @throws ZenodoFileTooLargeException The file exceeds the capabilities - * @throws MetadataDatabaseNotFoundException The deposit was not found on the metadata database + * @throws RemoteAuthenticationException Token invalid + * @throws RemoteApiException Something other went wrong + * @throws RemoteNotFoundException The deposit id was not found on the remote server + * @throws RemoteUnavailableException The remote server is not reachable + * @throws QueryNotFoundException The deposit was not found on the metadata database */ - FileResponseDto createResource(Long databaseId, Long tableId, FileUploadDto data, MultipartFile resource) - throws ZenodoAuthenticationException, ZenodoApiException, ZenodoNotFoundException, - ZenodoFileTooLargeException, MetadataDatabaseNotFoundException, ZenodoUnavailableException; + @Transactional + File createResource(Long databaseId, Long queryId) + throws RemoteAuthenticationException, RemoteApiException, RemoteNotFoundException, + RemoteUnavailableException, QueryNotFoundException, RemoteDatabaseException, TableServiceException, RemoteFileException, MetadataDatabaseNotFoundException; /** * List all files known to a deposit number (through the database-table id pair) * - * @param databaseId The database-table id pair - * @param tableId The database-table id pair * @return The list of files - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoApiException Something other went wrong - * @throws ZenodoNotFoundException The deposit id was not found on the remote server - * @throws MetadataDatabaseNotFoundException The deposit was not found on the metadata database */ - List<FileResponseDto> listResources(Long databaseId, Long tableId) throws MetadataDatabaseNotFoundException, ZenodoAuthenticationException, ZenodoNotFoundException, ZenodoApiException, ZenodoUnavailableException; + @Transactional + List<File> listResources(); /** * Find a file for a deposit (through the database-table id pair) by id * * @param databaseId The database-table id pair - * @param tableId The database-table id pair - * @param fileId The file id + * @param queryId The query id * @return The file - * @throws MetadataDatabaseNotFoundException The deposit was not found on the metadata database - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoNotFoundException The deposit id was not found on the remote server - * @throws ZenodoApiException Something other went wrong + * @throws QueryNotFoundException The deposit was not found on the metadata database + * @throws RemoteAuthenticationException Token invalid + * @throws RemoteNotFoundException The deposit id was not found on the remote server + * @throws RemoteUnavailableException The remote server is not reachable + * @throws RemoteApiException Something other went wrong */ - FileResponseDto findResource(Long databaseId, Long tableId, String fileId) throws MetadataDatabaseNotFoundException, ZenodoAuthenticationException, ZenodoNotFoundException, ZenodoApiException, ZenodoUnavailableException; + @Transactional + File findResource(Long databaseId, Long queryId) + throws RemoteAuthenticationException, RemoteNotFoundException, + RemoteApiException, RemoteUnavailableException, QueryNotFoundException, MetadataDatabaseNotFoundException; /** * Delete a file based on the database-table id pair by id * * @param databaseId The database-table id pair - * @param tableId The database-table id pair - * @param fileId The file id - * @throws MetadataDatabaseNotFoundException The deposit was not found on the metadata database - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoNotFoundException The deposit id was not found on the remote server - * @throws ZenodoApiException Something other went wrong + * @param queryId The query id + * @throws QueryNotFoundException The deposit was not found on the metadata database + * @throws RemoteAuthenticationException Token invalid + * @throws RemoteNotFoundException The deposit id was not found on the remote server + * @throws RemoteUnavailableException The remote server is not reachable + * @throws RemoteApiException Something other went wrong */ - void deleteResource(Long databaseId, Long tableId, String fileId) - throws MetadataDatabaseNotFoundException, ZenodoAuthenticationException, ZenodoNotFoundException, - ZenodoApiException, ZenodoUnavailableException; + @Transactional + void deleteResource(Long databaseId, Long queryId) throws RemoteAuthenticationException, + RemoteNotFoundException, RemoteApiException, RemoteUnavailableException, QueryNotFoundException, MetadataDatabaseNotFoundException; } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/service/MetadataService.java b/fda-citation-service/services/src/main/java/at/tuwien/service/MetadataService.java index 94e4f3e272f70b567fecc222d75a21bb756c4784..4af992837debdc97f8c0cba7adb105cf846fb98a 100644 --- a/fda-citation-service/services/src/main/java/at/tuwien/service/MetadataService.java +++ b/fda-citation-service/services/src/main/java/at/tuwien/service/MetadataService.java @@ -1,9 +1,12 @@ package at.tuwien.service; -import at.tuwien.api.zenodo.deposit.*; +import at.tuwien.api.database.deposit.DepositChangeRequestDto; +import at.tuwien.api.database.deposit.record.RecordDto; +import at.tuwien.entities.database.query.Query; import at.tuwien.exception.*; import org.springframework.stereotype.Service; +import javax.transaction.Transactional; import java.util.List; @Service @@ -13,60 +16,100 @@ public interface MetadataService { * List all deposits (e.g. datasets) available * * @param databaseId The database-table id pair - * @param tableId The database-table id pair * @return The deposists - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoApiException Something other went wrong */ - List<DepositResponseDto> listCitations(Long databaseId, Long tableId) throws ZenodoAuthenticationException, ZenodoApiException, MetadataDatabaseNotFoundException, ZenodoUnavailableException; + List<Query> listCitations(Long databaseId) throws MetadataDatabaseNotFoundException; /** * Create a new deposit * * @param databaseId The database-table id pair - * @param tableId The database-table id pair + * @param queryId The query id * @return The created deposit - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoApiException Something other went wrong + * @throws RemoteAuthenticationException Token invalid + * @throws RemoteApiException Something other went wrong + * @throws RemoteUnavailableException The remote server is not available */ - DepositChangeResponseDto storeCitation(Long databaseId, Long tableId) throws ZenodoAuthenticationException, ZenodoApiException, MetadataDatabaseNotFoundException, ZenodoUnavailableException; + Query storeCitation(Long databaseId, Long queryId) throws RemoteAuthenticationException, + RemoteApiException, MetadataDatabaseNotFoundException, RemoteUnavailableException, RemoteNotFoundException; /** * Update a deposit with new metadata for a given id * * @param databaseId The database-table id pair - * @param tableId The database-table id pair + * @param queryId The query id * @param data The new metadata * @return The updated deposit - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoApiException Something other went wrong - * @throws ZenodoNotFoundException The deposit id was not found on the remote server + * @throws RemoteAuthenticationException Token invalid + * @throws RemoteApiException Something other went wrong + * @throws RemoteNotFoundException The deposit id was not found on the remote server + * @throws RemoteUnavailableException The remote server is not available */ - DepositChangeResponseDto updateCitation(Long databaseId, Long tableId, DepositChangeRequestDto data) throws ZenodoAuthenticationException, - ZenodoApiException, ZenodoNotFoundException, MetadataDatabaseNotFoundException, ZenodoUnavailableException; + Query updateCitation(Long databaseId, Long queryId, + DepositChangeRequestDto data) throws RemoteAuthenticationException, RemoteApiException, + RemoteNotFoundException, RemoteUnavailableException, QueryNotFoundException, MetadataDatabaseNotFoundException; /** * Find a deposit by database-table id pair * * @param databaseId The database-table id pair - * @param tableId The database-table id pair + * @param queryId The query id * @return The deposit - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoApiException Something other went wrong - * @throws ZenodoNotFoundException The deposit id was not found on the remote server + * @throws RemoteAuthenticationException Token invalid + * @throws RemoteApiException Something other went wrong + * @throws RemoteNotFoundException The deposit id was not found on the remote server * @throws MetadataDatabaseNotFoundException The deposit id was not found in the metadata database + * @throws RemoteUnavailableException The remote server is not available */ - DepositResponseDto findCitation(Long databaseId, Long tableId) - throws ZenodoAuthenticationException, ZenodoApiException, ZenodoNotFoundException, - MetadataDatabaseNotFoundException, ZenodoUnavailableException; + Query findCitation(Long databaseId, Long queryId) + throws RemoteAuthenticationException, RemoteApiException, RemoteNotFoundException, + MetadataDatabaseNotFoundException, RemoteUnavailableException, QueryNotFoundException; + + /** + * Fetches a record by depositId + * + * @param depositId The depositId (e.g. 956194) + * @return The record + * @throws RemoteAuthenticationException + * @throws RemoteApiException + * @throws RemoteNotFoundException + * @throws QueryNotFoundException + * @throws RemoteUnavailableException + * @throws MetadataDatabaseNotFoundException + */ + @Transactional + RecordDto fetchRemoteRecord(Long depositId) + throws RemoteAuthenticationException, RemoteApiException, RemoteNotFoundException, + QueryNotFoundException, RemoteUnavailableException, MetadataDatabaseNotFoundException; /** * Delete a deposit from a given id * * @param databaseId The database-table id pair - * @param tableId The database-table id pair - * @throws ZenodoAuthenticationException Token invalid - * @throws ZenodoApiException Something other went wrong + * @param queryId The query id + * @throws RemoteAuthenticationException Token invalid + * @throws RemoteApiException Something other went wrong + * @throws MetadataDatabaseNotFoundException The deposit id was not found in the metadata database + * @throws RemoteUnavailableException The remote server is not available + * @throws RemoteNotFoundException The deposit was not found on the remote server + */ + void deleteCitation(Long databaseId, Long queryId) throws RemoteAuthenticationException, + RemoteApiException, MetadataDatabaseNotFoundException, RemoteUnavailableException, RemoteNotFoundException, + QueryNotFoundException; + + /** + * Publishes a deposit with database-table id pair + * + * @param databaseId The database-table id pair + * @param queryId The query id + * @return The deposit + * @throws RemoteAuthenticationException Token invalid + * @throws RemoteApiException Something other went wrong + * @throws MetadataDatabaseNotFoundException The deposit id was not found in the metadata database + * @throws RemoteUnavailableException The remote server is not available + * @throws RemoteNotFoundException The deposit was not found on the remote server */ - void deleteCitation(Long databaseId, Long tableId) throws ZenodoAuthenticationException, ZenodoApiException, MetadataDatabaseNotFoundException, ZenodoUnavailableException, ZenodoNotFoundException; + Query publishCitation(Long databaseId, Long queryId) throws RemoteAuthenticationException, + RemoteApiException, MetadataDatabaseNotFoundException, RemoteUnavailableException, RemoteNotFoundException, + QueryNotFoundException; } diff --git a/fda-citation-service/services/src/main/java/at/tuwien/service/ZenodoFileService.java b/fda-citation-service/services/src/main/java/at/tuwien/service/ZenodoFileService.java deleted file mode 100644 index 8a6b30de379455c90c7b148194d62640a2a34c67..0000000000000000000000000000000000000000 --- a/fda-citation-service/services/src/main/java/at/tuwien/service/ZenodoFileService.java +++ /dev/null @@ -1,175 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.api.zenodo.files.FileResponseDto; -import at.tuwien.api.zenodo.files.FileUploadDto; -import at.tuwien.config.ZenodoConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.table.Table; -import at.tuwien.exception.*; -import at.tuwien.mapper.ZenodoMapper; -import at.tuwien.repository.jpa.TableRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.*; -import org.springframework.stereotype.Service; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.ResourceAccessException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.multipart.MultipartFile; - -import javax.transaction.Transactional; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -@Service -public class ZenodoFileService implements FileService { - - private final RestTemplate apiTemplate; - private final ZenodoConfig zenodoConfig; - private final ZenodoMapper zenodoMapper; - private final TableRepository tableRepository; - - @Autowired - public ZenodoFileService(RestTemplate apiTemplate, ZenodoConfig zenodoConfig, ZenodoMapper zenodoMapper, - TableRepository tableRepository) { - this.apiTemplate = apiTemplate; - this.zenodoConfig = zenodoConfig; - this.zenodoMapper = zenodoMapper; - this.tableRepository = tableRepository; - } - - @Override - @Transactional - public FileResponseDto createResource(Long databaseId, Long tableId, FileUploadDto data, MultipartFile resource) - throws ZenodoAuthenticationException, ZenodoApiException, ZenodoNotFoundException, - ZenodoFileTooLargeException, MetadataDatabaseNotFoundException, ZenodoUnavailableException { - if (resource.getSize() > 50_1000_1000_1000L) { - throw new ZenodoFileTooLargeException("Only 50GB per file is allowed!"); - } - final Table table = getTable(databaseId, tableId); - final ResponseEntity<FileResponseDto> response; - try { - response = apiTemplate.postForEntity("/api/deposit/depositions/{deposit_id}/files?access_token={token}", - zenodoMapper.resourceToHttpEntity(data.getName(), resource), FileResponseDto.class, table.getDepositId(), zenodoConfig.getApiKey()); - } catch (IOException e) { - throw new ZenodoApiException("Could not map file to byte array"); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } catch (HttpClientErrorException.Unauthorized e) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } catch (HttpClientErrorException.BadRequest e) { - throw new ZenodoNotFoundException("Did not find the resource with this id"); - } - if (response.getStatusCode().equals(HttpStatus.BAD_REQUEST)) { - throw new ZenodoNotFoundException("Did not find the resource with this id"); - } - if (response.getBody() == null) { - throw new ZenodoApiException("Endpoint returned null body"); - } - return response.getBody(); - } - - @Override - @Transactional - public List<FileResponseDto> listResources(Long databaseId, Long tableId) throws MetadataDatabaseNotFoundException, - ZenodoAuthenticationException, ZenodoNotFoundException, ZenodoApiException, ZenodoUnavailableException { - final Table table = getTable(databaseId, tableId); - final ResponseEntity<FileResponseDto[]> response; - try { - response = apiTemplate.exchange("/api/deposit/depositions/{deposit_id}/files?access_token={token}", - HttpMethod.GET, addHeaders(null), FileResponseDto[].class, table.getDepositId(), zenodoConfig.getApiKey()); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } catch (HttpClientErrorException.NotFound e) { - throw new ZenodoNotFoundException("Did not find the resoource with this id"); - } catch (HttpClientErrorException.Unauthorized e) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } - if (response.getBody() == null) { - throw new ZenodoApiException("Endpoint returned null body"); - } - return Arrays.asList(response.getBody()); - } - - @Override - @Transactional - public FileResponseDto findResource(Long databaseId, Long tableId, String fileId) - throws MetadataDatabaseNotFoundException, ZenodoAuthenticationException, ZenodoNotFoundException, - ZenodoApiException, ZenodoUnavailableException { - final Table table = getTable(databaseId, tableId); - final ResponseEntity<FileResponseDto> response; - try { - response = apiTemplate.exchange("/api/deposit/depositions/{deposit_id}/files/{file_id}?access_token={token}", - HttpMethod.GET, addHeaders(null), FileResponseDto.class, table.getDepositId(), fileId, - zenodoConfig.getApiKey()); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } catch (HttpClientErrorException.NotFound e) { - throw new ZenodoNotFoundException("Did not find the resoource with this ID"); - } catch (HttpClientErrorException.Unauthorized e) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } - if (response.getBody() == null) { - throw new ZenodoApiException("Endpoint returned null body"); - } - return response.getBody(); - } - - @Override - @Transactional - public void deleteResource(Long databaseId, Long tableId, String fileId) - throws MetadataDatabaseNotFoundException, ZenodoAuthenticationException, ZenodoNotFoundException, - ZenodoApiException, ZenodoUnavailableException { - final Table table = getTable(databaseId, tableId); - final ResponseEntity<String> response; - try { - response = apiTemplate.exchange("/api/deposit/depositions/{deposit_id}/files/{file_id}?access_token={token}", - HttpMethod.DELETE, addHeaders(null), String.class, table.getDepositId(), fileId, - zenodoConfig.getApiKey()); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } catch (HttpClientErrorException.NotFound e) { - throw new ZenodoNotFoundException("Did not find the resource with this ID"); - } catch (HttpClientErrorException.Unauthorized e) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } - if (!response.getStatusCode().equals(HttpStatus.NO_CONTENT)) { - throw new ZenodoApiException("Failed to delete the resource with this ID"); - } - } - - /** - * Wrapper function to throw error when table with id was not found - * - * @param databaseId The database id - * @param tableId The table id - * @return The table - * @throws MetadataDatabaseNotFoundException The error - */ - @Transactional - protected Table getTable(Long databaseId, Long tableId) throws MetadataDatabaseNotFoundException { - final Database database = Database.builder() - .id(databaseId) - .build(); - final Optional<Table> table = tableRepository.findByDatabaseAndId(database, tableId); - if (table.isEmpty()) { - throw new MetadataDatabaseNotFoundException("Failed to find table with this id"); - } - return table.get(); - } - - /** - * Wrapper to add headers to all non-file upload requests - * - * @param body The request data - * @return The request with headers - */ - private HttpEntity<Object> addHeaders(Object body) { - final HttpHeaders headers = new HttpHeaders(); - headers.setAccept(List.of(MediaType.APPLICATION_JSON)); - headers.setContentType(MediaType.APPLICATION_JSON); - return new HttpEntity<>(body, headers); - } - -} diff --git a/fda-citation-service/services/src/main/java/at/tuwien/service/ZenodoMetadataService.java b/fda-citation-service/services/src/main/java/at/tuwien/service/ZenodoMetadataService.java deleted file mode 100644 index ab69c44588aea18cdb89b09845361a19705ca9ca..0000000000000000000000000000000000000000 --- a/fda-citation-service/services/src/main/java/at/tuwien/service/ZenodoMetadataService.java +++ /dev/null @@ -1,194 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.api.zenodo.deposit.*; -import at.tuwien.config.ZenodoConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.table.Table; -import at.tuwien.exception.*; -import at.tuwien.repository.jpa.TableRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.*; -import org.springframework.stereotype.Service; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.ResourceAccessException; -import org.springframework.web.client.RestTemplate; - -import javax.transaction.Transactional; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -@Service -public class ZenodoMetadataService implements MetadataService { - - private final RestTemplate apiTemplate; - private final ZenodoConfig zenodoConfig; - private final TableRepository tableRepository; - - @Autowired - public ZenodoMetadataService(RestTemplate apiTemplate, ZenodoConfig zenodoConfig, TableRepository tableRepository) { - this.apiTemplate = apiTemplate; - this.zenodoConfig = zenodoConfig; - this.tableRepository = tableRepository; - } - - @Override - @Transactional - public List<DepositResponseDto> listCitations(Long databaseId, Long tableId) throws ZenodoAuthenticationException, - ZenodoApiException, ZenodoUnavailableException { - final ResponseEntity<DepositResponseDto[]> response; - try { - response = apiTemplate.exchange("/api/deposit/depositions?access_token={token}", - HttpMethod.GET, addHeaders(null), DepositResponseDto[].class, zenodoConfig.getApiKey()); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } - if (response.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } - if (response.getBody() == null) { - throw new ZenodoApiException("Endpoint returned null body"); - } - return Arrays.asList(response.getBody()); - } - - @Override - @Transactional - public DepositChangeResponseDto storeCitation(Long databaseId, Long tableId) throws ZenodoAuthenticationException, - ZenodoApiException, MetadataDatabaseNotFoundException, ZenodoUnavailableException { - final Table table = getTable(databaseId, tableId); - final ResponseEntity<DepositChangeResponseDto> response; - try { - response = apiTemplate.exchange("/api/deposit/depositions?access_token={token}", HttpMethod.POST, - addHeaders("{}"), DepositChangeResponseDto.class, zenodoConfig.getApiKey()); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } - if (response.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } - if (response.getStatusCode().equals(HttpStatus.BAD_REQUEST)) { // 400 - throw new ZenodoApiException("Failed to store citation."); - } - if (response.getBody() == null) { - throw new ZenodoApiException("Endpoint returned null body"); - } - table.setDepositId(response.getBody().getId()); - tableRepository.save(table); - return response.getBody(); - } - - @Override - @Transactional - public DepositChangeResponseDto updateCitation(Long databaseId, Long tableId, DepositChangeRequestDto data) - throws ZenodoAuthenticationException, ZenodoApiException, ZenodoNotFoundException, - MetadataDatabaseNotFoundException, ZenodoUnavailableException { - final Table table = getTable(databaseId, tableId); - final ResponseEntity<DepositChangeResponseDto> response; - try { - response = apiTemplate.exchange("/api/deposit/depositions/{deposit_id}?access_token={token}", - HttpMethod.PUT, addHeaders(data), DepositChangeResponseDto.class, table.getDepositId(), - zenodoConfig.getApiKey()); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } catch (HttpClientErrorException.NotFound | HttpClientErrorException.BadRequest e) { - throw new ZenodoNotFoundException("Could not get the citation.", e); - } - if (response.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } - if (response.getStatusCode().equals(HttpStatus.BAD_REQUEST)) { - throw new ZenodoNotFoundException("Could not get the citation."); - } - if (!response.getStatusCode().equals(HttpStatus.OK)) { - throw new ZenodoAuthenticationException("Could not update the citation."); - } - if (response.getBody() == null) { - throw new ZenodoApiException("Endpoint returned null body"); - } - return response.getBody(); - } - - @Override - @Transactional - public DepositResponseDto findCitation(Long databaseId, Long tableId) throws ZenodoAuthenticationException, - ZenodoApiException, ZenodoNotFoundException, MetadataDatabaseNotFoundException, ZenodoUnavailableException { - final Table table = getTable(databaseId, tableId); - final ResponseEntity<DepositResponseDto> response; - try { - response = apiTemplate.exchange("/api/deposit/depositions/{deposit_id}?access_token={token}", - HttpMethod.GET, addHeaders(null), DepositResponseDto.class, table.getDepositId(), - zenodoConfig.getApiKey()); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } catch (HttpClientErrorException.NotFound | HttpClientErrorException.BadRequest e) { - throw new ZenodoNotFoundException("Could not get the citation.", e); - } - if (response.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } - if (response.getStatusCode().equals(HttpStatus.BAD_REQUEST)) { - throw new ZenodoNotFoundException("Could not get the citation."); - } - if (response.getBody() == null) { - throw new ZenodoApiException("Endpoint returned null body"); - } - return response.getBody(); - } - - @Override - @Transactional - public void deleteCitation(Long databaseId, Long tableId) throws ZenodoAuthenticationException, ZenodoApiException, - MetadataDatabaseNotFoundException, ZenodoUnavailableException, ZenodoNotFoundException { - final Table table = getTable(databaseId, tableId); - final ResponseEntity<String> response; - try { - response = apiTemplate.exchange("/api/deposit/depositions/{deposit_id}?access_token={token}", - HttpMethod.DELETE, addHeaders(null), String.class, table.getDepositId(), zenodoConfig.getApiKey()); - } catch (ResourceAccessException e) { - throw new ZenodoUnavailableException("Zenodo host is not reachable from the service network", e); - } catch (HttpClientErrorException.NotFound | HttpClientErrorException.BadRequest e) { - throw new ZenodoNotFoundException("Could not get the citation.", e); - } - if (response.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) { - throw new ZenodoAuthenticationException("Token is missing or invalid."); - } - if (!response.getStatusCode().equals(HttpStatus.CREATED)) { - throw new ZenodoApiException("Could not delete the deposit"); - } - } - - - /** - * Wrapper function to throw error when table with id was not found - * - * @param databaseId The database id - * @param tableId The table id - * @return The table - * @throws MetadataDatabaseNotFoundException The error - */ - @Transactional - protected Table getTable(Long databaseId, Long tableId) throws MetadataDatabaseNotFoundException { - final Database database = Database.builder() - .id(databaseId) - .build(); - final Optional<Table> table = tableRepository.findByDatabaseAndId(database, tableId); - if (table.isEmpty()) { - throw new MetadataDatabaseNotFoundException("Failed to find table with this id"); - } - return table.get(); - } - - /** - * Wrapper to add headers to all non-file upload requests - * - * @param body The request data - * @return The request with headers - */ - private HttpEntity<Object> addHeaders(Object body) { - final HttpHeaders headers = new HttpHeaders(); - headers.setAccept(List.of(MediaType.APPLICATION_JSON)); - headers.setContentType(MediaType.APPLICATION_JSON); - return new HttpEntity<>(body, headers); - } -} diff --git a/fda-citation-service/~ b/fda-citation-service/~ new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/fda-container-service/Dockerfile b/fda-container-service/Dockerfile index c363ef4bb9fa2b5eaf8d91301459828ba106c091..fef48057aadb4e586c9fa3de336fba011d31f7d5 100644 --- a/fda-container-service/Dockerfile +++ b/fda-container-service/Dockerfile @@ -15,7 +15,10 @@ COPY ./rest-service ./rest-service COPY ./services ./services COPY ./report ./report -RUN mvn -q clean package -DskipTests +ARG CI_JOB_STAGE + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null ###### THIRD STAGE ###### FROM openjdk:11-jre-slim as runtime @@ -23,7 +26,7 @@ FROM openjdk:11-jre-slim as runtime COPY ./service_ready /usr/bin RUN chmod +x /usr/bin/service_ready -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD service_ready +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready COPY --from=build ./rest-service/target/rest-service-*.jar ./rest-service.jar diff --git a/fda-container-service/rest-service/src/main/resources/application-docker.yml b/fda-container-service/rest-service/src/main/resources/application-docker.yml index c802ffc3eefde6e1a85016ae70807fb9ab5b4082..1035559b257db6a5c99e64ecdb250d6bba1c9443 100644 --- a/fda-container-service/rest-service/src/main/resources/application-docker.yml +++ b/fda-container-service/rest-service/src/main/resources/application-docker.yml @@ -23,4 +23,6 @@ logging: at.tuwien.: debug eureka: instance.hostname: fda-container-service - client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/ \ No newline at end of file + client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/ +fda: + ready.path: /ready \ No newline at end of file diff --git a/fda-container-service/rest-service/src/main/resources/application.yml b/fda-container-service/rest-service/src/main/resources/application.yml index 51d825bd7205885714ba0e91240b5ea5549b27da..8f10219b85e33029b0da1792c8903f17c8590322 100644 --- a/fda-container-service/rest-service/src/main/resources/application.yml +++ b/fda-container-service/rest-service/src/main/resources/application.yml @@ -15,7 +15,7 @@ spring: name: fda-container-service cloud: loadbalancer.ribbon.enabled: false -server.port: 9093 +server.port: 9091 logging: pattern.console: "%d %highlight(%-5level) %msg%n" level: @@ -23,4 +23,6 @@ logging: at.tuwien.: debug eureka: instance.hostname: fda-container-service - client.serviceUrl.defaultZone: http://localhost:9090/eureka/ \ No newline at end of file + client.serviceUrl.defaultZone: http://localhost:9090/eureka/ +fda: + ready.path: ./ready \ No newline at end of file diff --git a/fda-container-service/rest-service/src/test/resources/integration-test.after b/fda-container-service/rest-service/src/test/resources/integration-test.after deleted file mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..0000000000000000000000000000000000000000 --- a/fda-container-service/rest-service/src/test/resources/integration-test.after +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/fda-container-service/rest-service/src/test/resources/integration-test.before b/fda-container-service/rest-service/src/test/resources/integration-test.before deleted file mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..0000000000000000000000000000000000000000 --- a/fda-container-service/rest-service/src/test/resources/integration-test.before +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java index 7b3b31152b7c32368985f9f528c0eeb0882e872f..eebb91e8d66409246ad7f47f0aca1ca8db8791d5 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java +++ b/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java @@ -1,19 +1,38 @@ package at.tuwien.config; import com.google.common.io.Files; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; import java.io.File; import java.io.IOException; +import java.util.Arrays; +@Log4j2 @Configuration public class ReadyConfig { + @Value("${fda.ready.path}") + private String readyPath; + + private final Environment environment; + + @Autowired + public ReadyConfig(Environment environment) { + this.environment = environment; + } + @EventListener(ApplicationReadyEvent.class) public void init() throws IOException { - Files.touch(new File("/ready")); + if (!Arrays.asList(environment.getActiveProfiles()).contains("sandbox")) { + log.info("Service is ready"); + Files.touch(new File(readyPath)); + } } } diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/ContainerSeeder.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/ContainerSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..1c851f594bcbb0a92c435a76f9903f52ae011aad --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/ContainerSeeder.java @@ -0,0 +1,68 @@ +package at.tuwien.seeder; + +import at.tuwien.api.container.ContainerCreateRequestDto; +import at.tuwien.service.ContainerService; +import lombok.SneakyThrows; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Log4j2 +@Component +public class ContainerSeeder implements Seeder { + + private final static Long CONTAINER_1_ID = 1L; + public final static String CONTAINER_1_NAME = "fda-userdb-wetter-aus"; + private final static String CONTAINER_1_REPOSITORY = "mariadb"; + private final static String CONTAINER_1_TAG = "10.5"; + + private final static Long CONTAINER_2_ID = 2L; + public final static String CONTAINER_2_NAME = "fda-userdb-infection"; + private final static String CONTAINER_2_REPOSITORY = "mariadb"; + private final static String CONTAINER_2_TAG = "10.5"; + + private final static Long CONTAINER_3_ID = 3L; + public final static String CONTAINER_3_NAME = "fda-userdb-air"; + private final static String CONTAINER_3_REPOSITORY = "mariadb"; + private final static String CONTAINER_3_TAG = "10.5"; + + private final static ContainerCreateRequestDto CONTAINER_1_CREATE_REQ = ContainerCreateRequestDto.builder() + .name(CONTAINER_1_NAME) + .repository(CONTAINER_1_REPOSITORY) + .tag(CONTAINER_1_TAG) + .build(); + + private final static ContainerCreateRequestDto CONTAINER_2_CREATE_REQ = ContainerCreateRequestDto.builder() + .name(CONTAINER_2_NAME) + .repository(CONTAINER_2_REPOSITORY) + .tag(CONTAINER_2_TAG) + .build(); + + private final static ContainerCreateRequestDto CONTAINER_3_CREATE_REQ = ContainerCreateRequestDto.builder() + .name(CONTAINER_3_NAME) + .repository(CONTAINER_3_REPOSITORY) + .tag(CONTAINER_3_TAG) + .build(); + + private final ContainerService containerService; + + @Autowired + public ContainerSeeder(ContainerService containerService) { + this.containerService = containerService; + } + + @SneakyThrows + @Override + public void seed(){ + if (containerService.getAll().size() > 0) { + return; + } + log.debug("seeded container {}", containerService.create(CONTAINER_1_CREATE_REQ)); + log.debug("started container {}", containerService.start(CONTAINER_1_ID)); + log.debug("seeded container {}", containerService.create(CONTAINER_2_CREATE_REQ)); + log.debug("started container {}", containerService.start(CONTAINER_2_ID)); + log.debug("seeded container {}", containerService.create(CONTAINER_3_CREATE_REQ)); + log.debug("started container {}", containerService.start(CONTAINER_3_ID)); + } + +} diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/ImageSeeder.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/ImageSeeder.java index 0ac9c73f93cded8a879a547da56133e53567715b..9a3b95bd69bad80b811d988b4fbcda3c4b82dce2 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/seeder/ImageSeeder.java +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/ImageSeeder.java @@ -3,26 +3,20 @@ package at.tuwien.seeder; import at.tuwien.api.container.image.ImageCreateDto; import at.tuwien.api.container.image.ImageEnvItemDto; import at.tuwien.api.container.image.ImageEnvItemTypeDto; -import at.tuwien.entities.container.image.ContainerImageEnvironmentItem; -import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType; -import at.tuwien.exception.DockerClientException; -import at.tuwien.exception.ImageNotFoundException; import at.tuwien.service.ImageService; +import lombok.SneakyThrows; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; import java.util.List; @Log4j2 @Component -@Profile("seed") public class ImageSeeder implements Seeder { private final static String IMAGE_1_REPOSITORY = "postgres"; - private final static String IMAGE_1_TAG = "latest"; + private final static String IMAGE_1_TAG = "13.4-alpine"; private final static Integer IMAGE_1_PORT = 5432; private final static String IMAGE_1_DIALECT = "POSTGRES"; private final static String IMAGE_1_DRIVER = "org.postgresql.Driver"; @@ -30,7 +24,7 @@ public class ImageSeeder implements Seeder { private final static String IMAGE_1_LOGO = "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"; private final static String IMAGE_2_REPOSITORY = "mysql"; - private final static String IMAGE_2_TAG = "latest"; + private final static String IMAGE_2_TAG = "8.0"; private final static Integer IMAGE_2_PORT = 3306; private final static String IMAGE_2_DIALECT = "MYSQL"; private final static String IMAGE_2_DRIVER = "com.mysql.jdbc.Driver"; @@ -38,7 +32,7 @@ public class ImageSeeder implements Seeder { private final static String IMAGE_2_LOGO = "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"; private final static String IMAGE_3_REPOSITORY = "mariadb"; - private final static String IMAGE_3_TAG = "latest"; + private final static String IMAGE_3_TAG = "10.5"; private final static Integer IMAGE_3_PORT = 3306; private final static String IMAGE_3_DIALECT = "MARIADB"; private final static String IMAGE_3_DRIVER = "org.mariadb.jdbc.Driver"; @@ -177,16 +171,15 @@ public class ImageSeeder implements Seeder { this.imageService = imageService; } + @SneakyThrows @Override - @PostConstruct - public void seed() throws DockerClientException, ImageNotFoundException { + public void seed() { if (imageService.getAll().size() > 0) { return; } log.debug("seeded image {}", imageService.create(IMAGE_1_CREATE_DTO)); log.debug("seeded image {}", imageService.create(IMAGE_2_CREATE_DTO)); log.debug("seeded image {}", imageService.create(IMAGE_3_CREATE_DTO)); -// log.debug("seeded image {}", imageService.create(IMAGE_4_CREATE_DTO)); } } diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/Seeder.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/Seeder.java index 597fd1e49ec452fd7ce71acd74f6049ab7ce82df..b29b439206904e39f15e7c009c77382f210b3d67 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/seeder/Seeder.java +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/Seeder.java @@ -1,15 +1,10 @@ package at.tuwien.seeder; -import at.tuwien.exception.DockerClientException; -import at.tuwien.exception.ImageNotFoundException; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; - @Component public interface Seeder { - @PostConstruct - void seed() throws DockerClientException, ImageNotFoundException; + void seed(); } diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/ServiceSeeder.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/ServiceSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..738c40088bac0aa3aff40c293459e602c4f7f006 --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/ServiceSeeder.java @@ -0,0 +1,47 @@ +package at.tuwien.seeder; + +import com.google.common.io.Files; +import lombok.SneakyThrows; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.util.Arrays; + +@Log4j2 +@Component +@Profile("seeder") +public class ServiceSeeder implements Seeder { + + @Value("${fda.ready.path}") + private String readyPath; + + private final ImageSeeder imageSeeder; + private final ContainerSeeder containerSeeder; + private final Environment environment; + + @Autowired + public ServiceSeeder(ImageSeeder imageSeeder, ContainerSeeder containerSeeder, Environment environment) { + this.imageSeeder = imageSeeder; + this.containerSeeder = containerSeeder; + this.environment = environment; + } + + @Override + @SneakyThrows + @PostConstruct + public void seed() { + imageSeeder.seed(); + if (Arrays.asList(environment.getActiveProfiles()).contains("sandbox")) { + containerSeeder.seed(); + Thread.sleep(10 * 1000); + log.info("Seeding completed, service is ready"); + Files.touch(new File(readyPath)); + } + } +} diff --git a/fda-database-service/Dockerfile b/fda-database-service/Dockerfile index 489c9beecd38a3d958eb4f3d50c2cbf685f027bf..15fc6fd353487cf2137305b56369527425aaca91 100644 --- a/fda-database-service/Dockerfile +++ b/fda-database-service/Dockerfile @@ -15,7 +15,10 @@ COPY ./rest-service ./rest-service COPY ./services ./services COPY ./report ./report -RUN mvn -q clean package -DskipTests +ARG CI_JOB_STAGE + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null ###### THIRD STAGE ###### FROM openjdk:11-jre-slim as runtime @@ -23,7 +26,7 @@ FROM openjdk:11-jre-slim as runtime COPY ./service_ready /usr/bin RUN chmod +x /usr/bin/service_ready -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD service_ready +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready COPY --from=build ./rest-service/target/rest-service-*.jar ./rest-service.jar diff --git a/fda-database-service/report/pom.xml b/fda-database-service/report/pom.xml index 59853f7a6ca8f6e693662f984174050c84050c42..81ac152db592a8ec762cf29e774db7aa97c6dbcf 100644 --- a/fda-database-service/report/pom.xml +++ b/fda-database-service/report/pom.xml @@ -4,12 +4,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> - <artifactId>fda-database-service</artifactId> <groupId>at.tuwien</groupId> + <artifactId>fda-database-service</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>report</artifactId> + <version>0.0.1-SNAPSHOT</version> <name>fda-database-service-report</name> <properties> diff --git a/fda-database-service/rest-service/src/test/resources/integration-test.after b/fda-database-service/rest-service/src/test/resources/integration-test.after deleted file mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..0000000000000000000000000000000000000000 --- a/fda-database-service/rest-service/src/test/resources/integration-test.after +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/fda-database-service/rest-service/src/test/resources/integration-test.before b/fda-database-service/rest-service/src/test/resources/integration-test.before deleted file mode 100755 index f6fca54b4f90896861b24e6d938b51ed5f8e2b5b..0000000000000000000000000000000000000000 --- a/fda-database-service/rest-service/src/test/resources/integration-test.before +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -docker pull mariadb:latest -docker pull mysql:latest -docker pull postgres:latest \ No newline at end of file diff --git a/fda-database-service/services/src/main/java/at/tuwien/seeder/DatabaseSeeder.java b/fda-database-service/services/src/main/java/at/tuwien/seeder/DatabaseSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..30eb555322dfba1c6b7538aee87ead88bc537800 --- /dev/null +++ b/fda-database-service/services/src/main/java/at/tuwien/seeder/DatabaseSeeder.java @@ -0,0 +1,72 @@ +package at.tuwien.seeder; + +import at.tuwien.api.database.DatabaseCreateDto; +import at.tuwien.exception.AmqpException; +import at.tuwien.exception.ContainerNotFoundException; +import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.exception.ImageNotSupportedException; +import at.tuwien.service.DatabaseService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Slf4j +@Component +public class DatabaseSeeder implements Seeder { + + private final static Long DATABASE_1_ID = 1L; + private final static String DATABASE_1_NAME = "Rain in Australia"; + private final static String DATABASE_1_DESCRIPTION = "This dataset contains about 10 years of daily weather observations from many locations across Australia. RainTomorrow is the target variable to predict. It means -- did it rain the next day, Yes or No? This column is Yes if the rain for that day was 1mm or more."; + private final static Boolean DATABASE_1_PUBLIC = false; + + + private final static Long DATABASE_2_ID = 2L; + private final static String DATABASE_2_NAME = "Novel Coronavirus (COVID-19) Cases Data"; + private final static String DATABASE_2_DESCRIPTION = "Novel Corona Virus (COVID-19) epidemiological data since 22 January 2020. The data is compiled by the Johns Hopkins University Center for Systems Science and Engineering (JHU CCSE) from various sources including the World Health Organization (WHO), DXY.cn, BNO News, National Health Commission of the People’s Republic of China (NHC), China CDC (CCDC), Hong Kong Department of Health, Macau Government, Taiwan CDC, US CDC, Government of Canada, Australia Government Department of Health, European Centre for Disease Prevention and Control (ECDC), Ministry of Health Singapore (MOH), and others. JHU CCSE maintains the data on the 2019 Novel Coronavirus COVID-19 (2019-nCoV) Data Repository on Github."; + private final static Boolean DATABASE_2_PUBLIC = false; + + private final static Long DATABASE_3_ID = 3L; + private final static String DATABASE_3_NAME = "Air Quality in Lower Austria 2019-2021"; + private final static String DATABASE_3_DESCRIPTION = "Openair quality measurements between 2019-01-01 and 2021-01-01 in Wiener Neustadt, Lower Austria, Austria with a low-cost sensor."; + private final static Boolean DATABASE_3_PUBLIC = false; + + private final static DatabaseCreateDto DATABASE_1_CREATE = DatabaseCreateDto.builder() + .containerId(DATABASE_1_ID) + .description(DATABASE_1_DESCRIPTION) + .isPublic(DATABASE_1_PUBLIC) + .name(DATABASE_1_NAME) + .build(); + + private final static DatabaseCreateDto DATABASE_2_CREATE = DatabaseCreateDto.builder() + .containerId(DATABASE_2_ID) + .description(DATABASE_2_DESCRIPTION) + .isPublic(DATABASE_2_PUBLIC) + .name(DATABASE_2_NAME) + .build(); + + private final static DatabaseCreateDto DATABASE_3_CREATE = DatabaseCreateDto.builder() + .containerId(DATABASE_3_ID) + .description(DATABASE_3_DESCRIPTION) + .isPublic(DATABASE_3_PUBLIC) + .name(DATABASE_3_NAME) + .build(); + + private final DatabaseService databaseService; + + @Autowired + public DatabaseSeeder(DatabaseService databaseService) { + this.databaseService = databaseService; + } + + @Override + public void seed() throws ImageNotSupportedException, AmqpException, ContainerNotFoundException, + DatabaseMalformedException { + log.debug("seeded database {}", databaseService.create(DATABASE_1_CREATE)); + log.debug("seeded database {}", databaseService.create(DATABASE_2_CREATE)); + log.debug("seeded database {}", databaseService.create(DATABASE_3_CREATE)); + } + +} diff --git a/fda-database-service/services/src/main/java/at/tuwien/seeder/Seeder.java b/fda-database-service/services/src/main/java/at/tuwien/seeder/Seeder.java new file mode 100644 index 0000000000000000000000000000000000000000..f534434b0ff8353f574d2f876e442fe986b47bb9 --- /dev/null +++ b/fda-database-service/services/src/main/java/at/tuwien/seeder/Seeder.java @@ -0,0 +1,14 @@ +package at.tuwien.seeder; + +import at.tuwien.exception.AmqpException; +import at.tuwien.exception.ContainerNotFoundException; +import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.exception.ImageNotSupportedException; +import org.springframework.stereotype.Component; + +@Component +public interface Seeder { + + void seed() throws ImageNotSupportedException, AmqpException, ContainerNotFoundException, DatabaseMalformedException; + +} diff --git a/fda-database-service/services/src/main/java/at/tuwien/seeder/ServiceSeeder.java b/fda-database-service/services/src/main/java/at/tuwien/seeder/ServiceSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..7a28ee2262c5eb8a4352f472cc46a5b71f469a09 --- /dev/null +++ b/fda-database-service/services/src/main/java/at/tuwien/seeder/ServiceSeeder.java @@ -0,0 +1,39 @@ +package at.tuwien.seeder; + +import at.tuwien.exception.AmqpException; +import at.tuwien.exception.ContainerNotFoundException; +import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.exception.ImageNotSupportedException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.Arrays; + +@Slf4j +@Component +@Profile("seeder") +public class ServiceSeeder implements Seeder { + + private final DatabaseSeeder databaseSeeder; + private final Environment environment; + + @Autowired + public ServiceSeeder(DatabaseSeeder databaseSeeder, Environment environment) { + this.databaseSeeder = databaseSeeder; + this.environment = environment; + } + + @Override + @PostConstruct + public void seed() throws ImageNotSupportedException, AmqpException, ContainerNotFoundException, + DatabaseMalformedException { + if (Arrays.asList(environment.getActiveProfiles()).contains("sandbox")) { + databaseSeeder.seed(); + } + } + +} diff --git a/fda-discovery-service/Dockerfile b/fda-discovery-service/Dockerfile index e98d43d4e9eec6a540e1dc1de205826d85282827..54df4e5baadb603b233a0b234550bc27c5f816e3 100644 --- a/fda-discovery-service/Dockerfile +++ b/fda-discovery-service/Dockerfile @@ -6,9 +6,13 @@ COPY ./pom.xml ./ RUN mvn -fn -B dependency:go-offline > /dev/null -COPY ./src ./src +COPY ./discovery ./discovery +COPY ./report ./report -RUN mvn -q clean package -DskipTests +ARG CI_JOB_STAGE + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null ###### SECOND STAGE ###### FROM openjdk:11-jre-slim as runtime @@ -16,8 +20,8 @@ FROM openjdk:11-jre-slim as runtime COPY ./service_ready /usr/bin RUN chmod +x /usr/bin/service_ready -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD service_ready +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready -COPY --from=build ./target/fda-discovery-service-*.jar ./discovery.jar +COPY --from=build ./discovery/target/discovery-*.jar ./discovery.jar -ENTRYPOINT ["java", "-jar", "./discovery.jar"] \ No newline at end of file +ENTRYPOINT ["java", "-jar", "./discovery.jar"] diff --git a/fda-discovery-service/discovery/pom.xml b/fda-discovery-service/discovery/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..4e508b3d5468693dcef274113ee589eb256f9dc0 --- /dev/null +++ b/fda-discovery-service/discovery/pom.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.tuwien</groupId> + <artifactId>fda-discovery-service</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>discovery</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>fda-discovery-service-discovery</name> + + <properties> + <jacoco.version>0.8.7</jacoco.version> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal><!-- to make it exuteable with $ java -jar ./app.jar --> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-discovery-service/src/main/java/at/tuwien/discoveryserver/DiscoveryServerApplication.java b/fda-discovery-service/discovery/src/main/java/at/tuwien/discoveryserver/DiscoveryServiceApplication.java similarity index 74% rename from fda-discovery-service/src/main/java/at/tuwien/discoveryserver/DiscoveryServerApplication.java rename to fda-discovery-service/discovery/src/main/java/at/tuwien/discoveryserver/DiscoveryServiceApplication.java index acff62a9cec4d7bce01d8b5b92cd983ecd311276..c01e5f4ab50084a91c076284e9880b44e9a66d77 100644 --- a/fda-discovery-service/src/main/java/at/tuwien/discoveryserver/DiscoveryServerApplication.java +++ b/fda-discovery-service/discovery/src/main/java/at/tuwien/discoveryserver/DiscoveryServiceApplication.java @@ -6,10 +6,10 @@ import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer -public class DiscoveryServerApplication { +public class DiscoveryServiceApplication { public static void main(String[] args) { - SpringApplication.run(DiscoveryServerApplication.class, args); + SpringApplication.run(DiscoveryServiceApplication.class, args); } } diff --git a/fda-discovery-service/src/main/java/at/tuwien/discoveryserver/config/ReadyConfig.java b/fda-discovery-service/discovery/src/main/java/at/tuwien/discoveryserver/config/ReadyConfig.java similarity index 100% rename from fda-discovery-service/src/main/java/at/tuwien/discoveryserver/config/ReadyConfig.java rename to fda-discovery-service/discovery/src/main/java/at/tuwien/discoveryserver/config/ReadyConfig.java diff --git a/fda-discovery-service/src/main/resources/application-docker.yml b/fda-discovery-service/discovery/src/main/resources/application-docker.yml similarity index 100% rename from fda-discovery-service/src/main/resources/application-docker.yml rename to fda-discovery-service/discovery/src/main/resources/application-docker.yml diff --git a/fda-discovery-service/src/main/resources/application.properties b/fda-discovery-service/discovery/src/main/resources/application.properties similarity index 100% rename from fda-discovery-service/src/main/resources/application.properties rename to fda-discovery-service/discovery/src/main/resources/application.properties diff --git a/fda-discovery-service/discovery/src/main/resources/config.properties b/fda-discovery-service/discovery/src/main/resources/config.properties new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/fda-discovery-service/pom.xml b/fda-discovery-service/pom.xml index 0aa94e640f30e7fca393bb76d5b669f1b5a1db32..65abac16ce67fd0df23b12663e9e9f33adf24d49 100644 --- a/fda-discovery-service/pom.xml +++ b/fda-discovery-service/pom.xml @@ -14,12 +14,16 @@ <name>fda-discovery-service</name> <description>Demo project for Spring Boot</description> - <packaging>jar</packaging> - <modules /> + <packaging>pom</packaging> + <modules> + <module>report</module> + <module>discovery</module> + </modules> <properties> <java.version>11</java.version> <spring-cloud.version>3.0.1</spring-cloud.version> + <jacoco.version>0.8.7</jacoco.version> </properties> <dependencies> @@ -42,12 +46,31 @@ <build> <plugins> <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <configuration> + <excludes> + <exclude>at/tuwien/utils/**/*</exclude> + <exclude>at/tuwien/seeder/**/*</exclude> + <exclude>at/tuwien/mapper/**/*</exclude> + <exclude>at/tuwien/exception/**/*</exclude> + <exclude>at/tuwien/config/**/*</exclude> + <exclude>**/DiscoveryServiceApplication.class</exclude> + </excludes> + </configuration> <executions> <execution> + <id>default-prepare-agent</id> <goals> - <goal>repackage</goal><!-- to make it exuteable with $ java -jar ./app.jar --> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>report</id> + <phase>verify</phase> + <goals> + <goal>report</goal> </goals> </execution> </executions> diff --git a/fda-discovery-service/report/pom.xml b/fda-discovery-service/report/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..f261a50b5619b59db2f96893e5b408d853a6d06f --- /dev/null +++ b/fda-discovery-service/report/pom.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.tuwien</groupId> + <artifactId>fda-discovery-service</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>report</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>fda-discovery-service-report</name> + + <properties> + <jacoco.version>0.8.7</jacoco.version> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <executions> + <execution> + <id>report-aggregate</id> + <phase>verify</phase> + <goals> + <goal>report-aggregate</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-gateway-service/Dockerfile b/fda-gateway-service/Dockerfile index df702c0f0e4a1d68850ecc2aafc5bf0536d3018a..dcdbda7b9c40bc2b38e826c31966c554298124ac 100644 --- a/fda-gateway-service/Dockerfile +++ b/fda-gateway-service/Dockerfile @@ -6,9 +6,13 @@ COPY ./pom.xml ./ RUN mvn -fn -B dependency:go-offline > /dev/null -COPY ./src ./src +COPY ./gateway ./gateway +COPY ./report ./report -RUN mvn -q clean package +ARG CI_JOB_STAGE + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null ###### SECOND STAGE ###### FROM openjdk:11-jre-slim as runtime @@ -16,9 +20,9 @@ FROM openjdk:11-jre-slim as runtime COPY ./service_ready /usr/bin RUN chmod +x /usr/bin/service_ready -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD service_ready +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready -COPY --from=build ./target/fda-gateway-service-*.jar ./gateway.jar +COPY --from=build ./gateway/target/gateway-*.jar ./gateway.jar EXPOSE 9095 diff --git a/fda-gateway-service/gateway/pom.xml b/fda-gateway-service/gateway/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..df0e27dba7130336da98dadf3e1d3b202cd1ceb6 --- /dev/null +++ b/fda-gateway-service/gateway/pom.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.tuwien</groupId> + <artifactId>fda-gateway-service</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>gateway</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>fda-gateway-service-gateway</name> + + <properties> + <jacoco.version>0.8.7</jacoco.version> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal><!-- to make it exuteable with $ java -jar ./app.jar --> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-gateway-service/src/main/java/at/tuwien/gatewayservice/FdaGatewayServiceApplication.java b/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/FdaGatewayServiceApplication.java similarity index 100% rename from fda-gateway-service/src/main/java/at/tuwien/gatewayservice/FdaGatewayServiceApplication.java rename to fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/FdaGatewayServiceApplication.java diff --git a/fda-gateway-service/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java b/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java similarity index 64% rename from fda-gateway-service/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java rename to fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java index 47182f176a71de21fdeff19d20b58ca70ff28b8d..70fe42bb69cdca146bacaa307b7d4200118703c7 100644 --- a/fda-gateway-service/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java +++ b/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java @@ -13,37 +13,39 @@ public class GatewayConfig { return builder.routes() .route("fda-analyse-service", r -> r.path("/api/analyse/**") .and() - .method("POST","GET","PUT","DELETE") + .method("POST", "GET", "PUT", "DELETE") .and() .uri("lb://fda-analyse-service")) - .route("fda-container-service", r -> r.path("/api/container/**") + .route("fda-authentication-service", r -> r.path("/api/auth/**") .and() - .method("POST","GET","PUT","DELETE") + .method("POST", "GET") .and() - .uri("lb://fda-container-service")) - .route("fda-container-service", r -> r.path("/api/image/**") + .uri("lb://fda-authentication-service")) + .route("fda-container-service", r -> r.path("/api/container/**", + "/api/image/**") .and() - .method("POST","GET","PUT","DELETE") + .method("POST", "GET", "PUT", "DELETE") .and() .uri("lb://fda-container-service")) - .route("fda-query-service", r -> r.path("/api/database/**/query/**") + .route("fda-query-service", r -> r.path("/api/database/**/metadata/**", + "/api/database/**/store/**") .and() - .method("POST","GET","PUT","DELETE") + .method("POST", "GET", "PUT", "DELETE") .and() .uri("lb://fda-query-service")) - .route("fda-query-service", r -> r.path("/api/database/**/querystore/**") + .route("fda-citation-service", r -> r.path("/api/database/**/cite/**") .and() - .method("POST","GET","PUT","DELETE") + .method("POST", "GET", "PUT", "DELETE") .and() - .uri("lb://fda-query-service")) + .uri("lb://fda-citation-service")) .route("fda-table-service", r -> r.path("/api/database/**/table/**") .and() - .method("POST","GET","PUT","DELETE") + .method("POST", "GET", "PUT", "DELETE") .and() .uri("lb://fda-table-service")) .route("fda-database-service", r -> r.path("/api/database/**") .and() - .method("POST","GET","PUT","DELETE") + .method("POST", "GET", "PUT", "DELETE") .and() .uri("lb://fda-database-service")) .build(); diff --git a/fda-gateway-service/src/main/java/at/tuwien/gatewayservice/config/ReadyConfig.java b/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/ReadyConfig.java similarity index 100% rename from fda-gateway-service/src/main/java/at/tuwien/gatewayservice/config/ReadyConfig.java rename to fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/ReadyConfig.java diff --git a/fda-gateway-service/src/main/java/at/tuwien/gatewayservice/config/WebConfig.java b/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/WebConfig.java similarity index 100% rename from fda-gateway-service/src/main/java/at/tuwien/gatewayservice/config/WebConfig.java rename to fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/WebConfig.java diff --git a/fda-gateway-service/src/main/resources/application-docker.yml b/fda-gateway-service/gateway/src/main/resources/application-docker.yml similarity index 100% rename from fda-gateway-service/src/main/resources/application-docker.yml rename to fda-gateway-service/gateway/src/main/resources/application-docker.yml diff --git a/fda-gateway-service/src/main/resources/application.properties b/fda-gateway-service/gateway/src/main/resources/application.properties similarity index 100% rename from fda-gateway-service/src/main/resources/application.properties rename to fda-gateway-service/gateway/src/main/resources/application.properties diff --git a/fda-gateway-service/gateway/src/main/resources/config.properties b/fda-gateway-service/gateway/src/main/resources/config.properties new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/fda-gateway-service/pom.xml b/fda-gateway-service/pom.xml index 18f6f2b68dc57f2e0ef4001838828a5549297711..98d5c62681acd935d2fe4808f2b8424d1d130747 100644 --- a/fda-gateway-service/pom.xml +++ b/fda-gateway-service/pom.xml @@ -13,11 +13,18 @@ <name>fda-gateway-service</name> <description>Demo project for Spring Boot</description> + <packaging>pom</packaging> + <modules> + <module>gateway</module> + <module>report</module> + </modules> + <properties> <java.version>11</java.version> <spring-cloud.version>Hoxton.SR10</spring-cloud.version><!-- SR11 not working yet --> <swagger.version>2.1.7</swagger.version> <springfox.version>3.0.0</springfox.version> + <jacoco.version>0.8.7</jacoco.version> </properties> <dependencies> @@ -81,12 +88,31 @@ <build> <plugins> <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <configuration> + <excludes> + <exclude>at/tuwien/utils/**/*</exclude> + <exclude>at/tuwien/seeder/**/*</exclude> + <exclude>at/tuwien/mapper/**/*</exclude> + <exclude>at/tuwien/exception/**/*</exclude> + <exclude>at/tuwien/config/**/*</exclude> + <exclude>**/FdaContainerManagingApplication.class</exclude> + </excludes> + </configuration> <executions> <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>report</id> + <phase>verify</phase> <goals> - <goal>repackage</goal><!-- to make it exuteable with $ java -jar ./app.jar --> + <goal>report</goal> </goals> </execution> </executions> diff --git a/fda-gateway-service/report/pom.xml b/fda-gateway-service/report/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..b847cd4c333fcea93404b12cb42a43f47e3634a8 --- /dev/null +++ b/fda-gateway-service/report/pom.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.tuwien</groupId> + <artifactId>fda-gateway-service</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>report</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>fda-gateway-service-report</name> + <description> + This module is only intended for the pipeline coverage report. See the detailed report in the + respective modules + </description> + + <properties> + <jacoco.version>0.8.7</jacoco.version> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <executions> + <execution> + <id>report-aggregate</id> + <phase>verify</phase> + <goals> + <goal>report-aggregate</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-metadata-db/Dockerfile b/fda-metadata-db/Dockerfile index e1dd99c751f1f2b6dbef74bdd7702410ea0df146..be221c1de54829109496f958a468fc2dafb1f60e 100644 --- a/fda-metadata-db/Dockerfile +++ b/fda-metadata-db/Dockerfile @@ -9,17 +9,19 @@ RUN mvn -fn -B dependency:go-offline > /dev/null COPY ./api ./api COPY ./entities ./entities +ARG CI_JOB_STAGE + # Make sure it compiles -RUN mvn clean package -DskipTests > /dev/null +RUN mvn -q clean package -DskipTests > /dev/null # Install to local repository -RUN mvn clean install > /dev/null +RUN mvn -q clean install > /dev/null ###### SECOND STAGE ###### FROM postgres:latest as runtime # Scripts are copied to /docker-entrypoint-initdb.d/ in docker-compose from analyze service -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD pg_isready +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD pg_isready COPY ./initi.sh /docker-entrypoint-initdb.d/ RUN chmod +x /docker-entrypoint-initdb.d/initi.sh diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseDto.java index 2eba38cf96de134a524c868c92681ca66abb8cbf..55d854dbcf4a4f63f2813b25b53560172dfa5400 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseDto.java @@ -2,6 +2,9 @@ package at.tuwien.api.database; import at.tuwien.api.container.ContainerDto; import at.tuwien.api.container.image.ImageDto; +import at.tuwien.api.database.query.QueryDto; +import at.tuwien.api.database.table.TableDto; +import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModelProperty; import io.swagger.v3.oas.annotations.Parameter; import lombok.*; @@ -10,6 +13,7 @@ import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.time.Instant; +import java.util.List; @Getter @Setter @@ -29,6 +33,7 @@ public class DatabaseDto { private String name; @NotBlank + @JsonProperty("internal_name") @ApiModelProperty(name = "database internal name", example = "weather_australia") private String internalName; @@ -36,6 +41,14 @@ public class DatabaseDto { @ApiModelProperty(name = "database description", example = "Weather Australia 2009-2021") private String description; + @NotNull + @ApiModelProperty(name = "tables") + private List<TableDto> tables; + + @NotNull + @ApiModelProperty(name = "queries") + private List<QueryDto> queries; + @NotBlank @ApiModelProperty(name = "database exchange", example = "fda.c1.d1") private String exchange; diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositChangeRequestDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositChangeRequestDto.java similarity index 59% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositChangeRequestDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositChangeRequestDto.java index c7aa055d5746146bce9a8767815537d0168ab5fd..d98551d84d276c6aaecdadb2ae6433a32a3c1d62 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositChangeRequestDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositChangeRequestDto.java @@ -1,10 +1,12 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit; +import at.tuwien.api.database.deposit.metadata.MetadataDto; import lombok.*; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor public class DepositChangeRequestDto { diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositResponseDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositDto.java similarity index 80% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositResponseDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositDto.java index 25cc5c9a90c145d0eda3c9a9ddae1cc6a27fda1d..79b5852f3092608cb1f2f4b7c41474406820f4b7 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositResponseDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositDto.java @@ -1,6 +1,8 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit; -import at.tuwien.api.zenodo.files.FileResponseDto; +import at.tuwien.api.database.deposit.files.FileDto; +import at.tuwien.api.database.deposit.metadata.CreatorDto; +import at.tuwien.api.database.deposit.metadata.MetadataDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @@ -12,9 +14,10 @@ import java.util.List; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor -public class DepositResponseDto { +public class DepositDto { /** * {@link Instant} without timezone seems broken @@ -46,7 +49,7 @@ public class DepositResponseDto { private CreatorDto[] contributors; - private List<FileResponseDto> files; + private List<FileDto> files; private Long id; diff --git a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositLinksDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositLinksDto.java similarity index 88% rename from fda-table-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositLinksDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositLinksDto.java index 3cb5bb8317f0c9813ccd2b69898c25fd2701c24a..ca00ac9bcc0358d5c46a3dd4b0ad862abffcf697 100644 --- a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositLinksDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositLinksDto.java @@ -1,10 +1,11 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit; import lombok.*; @Setter @Getter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor public class DepositLinksDto { diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositChangeResponseDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositTzDto.java similarity index 78% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositChangeResponseDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositTzDto.java index 8a7297df21605c727af4bf436abdc9755678617a..de1d3ac0ec0bb470c4450c3477ad6b77739925d5 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositChangeResponseDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/DepositTzDto.java @@ -1,6 +1,8 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit; -import at.tuwien.api.zenodo.files.FileResponseDto; +import at.tuwien.api.database.deposit.files.FileDto; +import at.tuwien.api.database.deposit.metadata.CreatorDto; +import at.tuwien.api.database.deposit.metadata.MetadataDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @@ -11,9 +13,10 @@ import java.util.List; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor -public class DepositChangeResponseDto { +public class DepositTzDto { @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX") private Instant created; @@ -40,7 +43,7 @@ public class DepositChangeResponseDto { private CreatorDto[] contributors; - private List<FileResponseDto> files; + private List<FileDto> files; private Long id; diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/LinksDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/LinksDto.java similarity index 88% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/LinksDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/LinksDto.java index 2400b19d94c9213d4dd13c1a9b1da488c386c2af..5082132137d18cdc5f16b8b55b3ad31fb508ad3c 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/LinksDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/LinksDto.java @@ -1,5 +1,5 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit; import lombok.*; @@ -8,6 +8,7 @@ import java.net.URI; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor public class LinksDto { diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/StatisticDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/StatisticDto.java new file mode 100644 index 0000000000000000000000000000000000000000..32dbeb4a2d5cd11f466b1ed5d04bb86978a93695 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/StatisticDto.java @@ -0,0 +1,41 @@ +package at.tuwien.api.database.deposit; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class StatisticDto { + + private Long downloads; + + private Long views; + + private Long volume; + + @JsonProperty("unique_downloads") + private Long uniqueDownloads; + + @JsonProperty("unique_views") + private Long uniqueViews; + + @JsonProperty("version_views") + private Long versionViews; + + @JsonProperty("version_volume") + private Long versionVolume; + + @JsonProperty("version_downloads") + private Long versionDownloads; + + @JsonProperty("version_unique_downloads") + private Long versionUniqueDownloads; + + @JsonProperty("version_unique_views") + private Long versionUniqueViews; + +} diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/FileBinaryRequestDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileBinaryRequestDto.java similarity index 82% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/FileBinaryRequestDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileBinaryRequestDto.java index 1e823a91feb4e84e373c8bf774c3b8ea9728f44f..c9e36421761cd794ede57be9e3dc994eace89301 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/FileBinaryRequestDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileBinaryRequestDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.files; import lombok.*; import org.springframework.core.io.ByteArrayResource; @@ -7,6 +7,7 @@ import org.springframework.http.HttpEntity; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor public class FileBinaryRequestDto { diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileDto.java new file mode 100644 index 0000000000000000000000000000000000000000..f425c8522150a0de9638cdf03e89f8b789fa813f --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileDto.java @@ -0,0 +1,31 @@ +package at.tuwien.api.database.deposit.files; + +import at.tuwien.api.database.query.QueryDto; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.time.Instant; + +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class FileDto { + + private Long id; + + private Long fqid; + + private Long fdbid; + + private String refId; + + private QueryDto query; + + private Instant created; + + private Instant lastModified; +} diff --git a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/files/FileLinksDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileLinksDto.java similarity index 75% rename from fda-table-service/api/src/main/java/at/tuwien/api/zenodo/files/FileLinksDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileLinksDto.java index d543b62cf48dcf419187245a5f1cbc9e69a1eb3b..fd19a246776644728b6f135d3aa82e5f2f08b028 100644 --- a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/files/FileLinksDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileLinksDto.java @@ -1,10 +1,11 @@ -package at.tuwien.api.zenodo.files; +package at.tuwien.api.database.deposit.files; import lombok.*; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor public class FileLinksDto { diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/FileRequestDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileRequestDto.java similarity index 71% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/FileRequestDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileRequestDto.java index 96b31aa483d4c70202fea4fae11db5b5e81bd227..61f00860901576e46f351e70e553b37225908cdb 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/FileRequestDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileRequestDto.java @@ -1,10 +1,11 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.files; import lombok.*; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor public class FileRequestDto { diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..4ba687c73f75b6120d36086ee791d5199c4d69fc --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileTypeDto.java @@ -0,0 +1,12 @@ +package at.tuwien.api.database.deposit.files; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum FileTypeDto { + + @JsonProperty("csv") + CSV, + + @JsonProperty("other") + OTHER; +} diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileUploadDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileUploadDto.java similarity index 71% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileUploadDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileUploadDto.java index 96cfe3b5b3bef5d6bee6fab7b93f28d3fb799d98..48e405a8e15b8afcf042fe8f9ab771f6624069c2 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/files/FileUploadDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/FileUploadDto.java @@ -1,10 +1,11 @@ -package at.tuwien.api.zenodo.files; +package at.tuwien.api.database.deposit.files; import lombok.*; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor public class FileUploadDto { diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/ImageTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/ImageTypeDto.java similarity index 87% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/ImageTypeDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/ImageTypeDto.java index 5536e9ff893b5ccfa9a1f2bbb353eb609c67245f..bd71dba2231a9ac6b44aa9660874ef3e469cce52 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/ImageTypeDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/ImageTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.files; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/RecordFileDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/RecordFileDto.java new file mode 100644 index 0000000000000000000000000000000000000000..7febd984a1a9a99fc9818703ec6c1ba7ef592481 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/files/RecordFileDto.java @@ -0,0 +1,28 @@ +package at.tuwien.api.database.deposit.files; + +import at.tuwien.api.database.deposit.metadata.ResourceTypeDto; +import at.tuwien.api.database.deposit.record.RecordLinksDto; +import at.tuwien.api.database.query.QueryDto; +import lombok.*; + +import java.time.Instant; + +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class RecordFileDto { + + private String bucket; + + private String checksum; + + private String key; + + private RecordLinksDto links; + + private ResourceTypeDto type; + +} diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/AccessRightDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/AccessRightDto.java similarity index 84% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/AccessRightDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/AccessRightDto.java index 9f8d1b4f740ab47dabd9d91f82869b5d3c413a87..b48c48d5ac5b47376dd9c16d6e4fb67929b81594 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/AccessRightDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/AccessRightDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.metadata; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/CreatorDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/CreatorDto.java similarity index 84% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/CreatorDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/CreatorDto.java index 7c7f0738bdb6b969dd6098f427d4d3be19db59de..b3b0d45d7ce653defa54b5177e12d4f508dc44b0 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/CreatorDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/CreatorDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.metadata; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.*; @@ -6,6 +6,7 @@ import lombok.*; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/IdentifierDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/IdentifierDto.java new file mode 100644 index 0000000000000000000000000000000000000000..5b4e976410724554319542b1530a8ecfe94e25e8 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/IdentifierDto.java @@ -0,0 +1,21 @@ +package at.tuwien.api.database.deposit.metadata; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.*; + +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class IdentifierDto { + + private String identifier; + + private String relation; + + private String scheme; + +} diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/LicenseTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/LicenseTypeDto.java similarity index 86% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/LicenseTypeDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/LicenseTypeDto.java index 8f791d8bd075e0af9f5f46852a7fc8012e64ca3c..598f1cb8757d67511279e7c58d1e99d5ce600e1b 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/LicenseTypeDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/LicenseTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.metadata; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/MetadataDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/MetadataDto.java similarity index 78% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/MetadataDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/MetadataDto.java index 0bf0a663006cfe7cedd2c61fea9599f89bef5ca7..47e31612bf1025ab97ff11b7bf7e60ee9104d90a 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/MetadataDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/MetadataDto.java @@ -1,17 +1,16 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.metadata; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonValue; import lombok.*; -import java.time.Instant; import java.util.Date; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) @@ -29,12 +28,16 @@ public class MetadataDto { private String doi; -// private LicenseTypeDto license; + @JsonProperty("related_identifiers") + private IdentifierDto[] relatedIdentifiers; @JsonProperty("publication_date") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") private Date publicationDate; + @JsonProperty("resource_type") + private ResourceTypeDto resourceType; + @JsonProperty("access_right") private AccessRightDto accessRight; diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/PreserveDoiDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/PreserveDoiDto.java similarity index 73% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/PreserveDoiDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/PreserveDoiDto.java index 4e99bc1bf4a1e4233b90164a578391d931117809..6e8bea513ab2a4355e032a30e5d17c57fc6b1499 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/PreserveDoiDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/PreserveDoiDto.java @@ -1,10 +1,11 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.metadata; import lombok.*; @Getter @Setter @Builder +@ToString @NoArgsConstructor @AllArgsConstructor public class PreserveDoiDto { diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/PublicationTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/PublicationTypeDto.java similarity index 95% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/PublicationTypeDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/PublicationTypeDto.java index 958034c1c3d01ba8625e199516492f9449536b37..a62ea17057bb3221dae2155ff5bdea450ffae080 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/PublicationTypeDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/PublicationTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.metadata; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/ResourceTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/ResourceTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..b2f179f4b382e681448bf1483473aeba2c0512c3 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/ResourceTypeDto.java @@ -0,0 +1,23 @@ +package at.tuwien.api.database.deposit.metadata; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.util.Date; + +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResourceTypeDto { + + private String title; + + private UploadTypeDto type; + +} diff --git a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/UploadTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/UploadTypeDto.java similarity index 91% rename from fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/UploadTypeDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/UploadTypeDto.java index 0089aaefff5ce345264136f854f794aaf54a76ee..c739a30a7869969b199ab35ceb2539156e840cf4 100644 --- a/fda-citation-service/api/src/main/java/at/tuwien/api/zenodo/deposit/UploadTypeDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/metadata/UploadTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.zenodo.deposit; +package at.tuwien.api.database.deposit.metadata; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/record/RecordDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/record/RecordDto.java new file mode 100644 index 0000000000000000000000000000000000000000..c1a35d53668eb428f87715628a359963b133939d --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/record/RecordDto.java @@ -0,0 +1,36 @@ +package at.tuwien.api.database.deposit.record; + +import at.tuwien.api.database.deposit.files.RecordFileDto; +import at.tuwien.api.database.deposit.metadata.MetadataDto; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.time.Instant; + +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class RecordDto { + + @JsonProperty("conceptdoi") + private String conceptDoi; + + private String doi; + + @JsonProperty("conceptrecid") + private String recordId; + + @JsonProperty("id") + private Long refId; + + private RecordFileDto[] files; + + private MetadataDto metadata; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX") + private Instant created; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/record/RecordLinksDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/record/RecordLinksDto.java new file mode 100644 index 0000000000000000000000000000000000000000..db7124cd5b6b349ea3e37f8848aa53bd97a888e5 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/deposit/record/RecordLinksDto.java @@ -0,0 +1,16 @@ +package at.tuwien.api.database.deposit.record; + +import lombok.*; + +import java.net.URI; + +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class RecordLinksDto { + + private URI self; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/ExecuteQueryDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/ExecuteQueryDto.java index 7b4a084e69f374562f1f39fb85c9d710fa726d71..ec0289793d46912567624717f9c5ac265e7b1035 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/ExecuteQueryDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/ExecuteQueryDto.java @@ -1,6 +1,5 @@ package at.tuwien.api.database.query; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @Getter @@ -10,7 +9,8 @@ import lombok.*; @NoArgsConstructor public class ExecuteQueryDto { - @JsonProperty("Query") + private String title; + private String query; } diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/QueryDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/QueryDto.java index 67d7a7765264eb7a51960d7a0db0508decb5cd75..004094b4d46c19edc7e3770ebd677410b0d8bca5 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/QueryDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/QueryDto.java @@ -1,13 +1,16 @@ package at.tuwien.api.database.query; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - +import at.tuwien.api.database.deposit.files.FileDto; +import at.tuwien.api.database.table.TableDto; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import javax.persistence.Column; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; import java.sql.Timestamp; +import java.time.Instant; +import java.util.List; @Data @@ -15,19 +18,46 @@ import java.sql.Timestamp; @Setter @Builder public class QueryDto { + + @NotNull private Long id; - private Timestamp execution_timestamp; + @NotNull + private Long qdbid; + + @JsonProperty("execution_timestamp") + private Instant executionTimestamp; + @NotBlank private String query; + @NotBlank + private String title; + private String doi; - private String query_normalized; + @JsonProperty("deposit_id") + private Long depositId; + + private List<FileDto> files; + + private TableDto table; + + @JsonProperty("query_normalized") + private String queryNormalized; + + @JsonProperty("query_hash") + private String queryHash; + + @JsonProperty("result_hash") + private String resultHash; - private String query_hash; + @JsonProperty("result_number") + private Long resultNumber; - private String result_hash; + @NotNull + private Instant created; - private Integer result_number; + @NotNull + private Instant lastModified; } diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/QueryResultDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/QueryResultDto.java index cbc571b5665333af81b03c83bcb6a61e9534b1e6..c2f4a798d75b2be0e60032ec27f4d8fb02e8ceff 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/QueryResultDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/query/QueryResultDto.java @@ -1,6 +1,5 @@ package at.tuwien.api.database.query; -import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModelProperty; import lombok.*; @@ -13,25 +12,16 @@ import java.util.Map; @Builder @AllArgsConstructor @NoArgsConstructor +@EqualsAndHashCode @ToString public class QueryResultDto { @NotNull - @ApiModelProperty(name = "query result") + @ApiModelProperty(notes = "query result") private List<Map<String, Object>> result; - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - QueryResultDto that = (QueryResultDto) o; - - return result != null ? result.equals(that.result) : that.result == null; - } + @NotNull + @ApiModelProperty(notes = "query id") + private Long id; - @Override - public int hashCode() { - return result != null ? result.hashCode() : 0; - } } diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/error/ApiErrorDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/error/ApiErrorDto.java index 12bf82d4a6e694e504791f2dd4376c4d6ea95b85..098f26212d46fac437f56c181ab3e0ac96463fd5 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/error/ApiErrorDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/error/ApiErrorDto.java @@ -6,6 +6,7 @@ import org.springframework.http.HttpStatus; @Getter @Setter @Builder +@ToString @NoArgsConstructor public class ApiErrorDto { diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java new file mode 100644 index 0000000000000000000000000000000000000000..f3e4c2f988ba2d53c8cc40bf7b042784de5695e3 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java @@ -0,0 +1,21 @@ +package at.tuwien.api.user; + +import lombok.*; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class UserDto { + + private String id; + + private String givenName; + + private String surname; + + private String mail; + +} diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java index 6c2f22431f5f844de6059ef9dbc0c81be8e0441a..e9e816fe8899b2447d59f513e8bd731d904a1d45 100644 --- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java @@ -1,6 +1,7 @@ package at.tuwien.entities.database; import at.tuwien.entities.container.Container; +import at.tuwien.entities.database.query.Query; import at.tuwien.entities.database.table.Table; import lombok.*; import org.hibernate.annotations.GenericGenerator; @@ -25,7 +26,6 @@ import java.util.List; @Where(clause = "deleted is null") @ToString(onlyExplicitlyIncluded = true) @EntityListeners(AuditingEntityListener.class) -@EqualsAndHashCode(onlyExplicitlyIncluded = true) @SQLDelete(sql = "update mdb_databases set deleted = NOW() where id = ?") @javax.persistence.Table(name = "mdb_databases") public class Database { @@ -71,6 +71,10 @@ public class Database { }) private List<Table> tables; + @ToString.Exclude + @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "database") + private List<Query> queries; + @ToString.Include @Column(nullable = false) private Boolean isPublic; diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/File.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/File.java new file mode 100644 index 0000000000000000000000000000000000000000..61198b7c414c8ed1a489aeea66e88d208a239385 --- /dev/null +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/File.java @@ -0,0 +1,60 @@ +package at.tuwien.entities.database.query; + +import lombok.*; +import org.hibernate.annotations.GenericGenerator; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import java.time.Instant; + +@Data +@Entity +@Builder +@ToString +@AllArgsConstructor +@NoArgsConstructor +@IdClass(FileKey.class) +@EntityListeners(AuditingEntityListener.class) +@javax.persistence.Table(name = "mdb_files") +public class File { + + @Id + @EqualsAndHashCode.Include + @GeneratedValue(generator = "files-sequence") + @GenericGenerator( + name = "files-sequence", + strategy = "enhanced-sequence", + parameters = @org.hibernate.annotations.Parameter(name = "sequence_name", value = "mdb_files_seq") + ) + private Long id; + + @Id + @EqualsAndHashCode.Include + private Long fqid; + + @Id + @EqualsAndHashCode.Include + private Long fdbid; + + @Column(name = "ref_id", nullable = false) + private String refId; + + @ToString.Exclude + @JoinColumns({ + @JoinColumn(name = "fdbid", referencedColumnName = "qdbid", insertable = false, updatable = false), + @JoinColumn(name = "fqid", referencedColumnName = "id", insertable = false, updatable = false) + }) + @ManyToOne(fetch = FetchType.LAZY) + private Query query; + + @Column(nullable = false, updatable = false) + @CreatedDate + private Instant created; + + @Column + @LastModifiedDate + private Instant lastModified; + +} diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/FileKey.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/FileKey.java new file mode 100644 index 0000000000000000000000000000000000000000..ec7bddb7f3a07cbc5bd32febfb983212fd3a41bc --- /dev/null +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/FileKey.java @@ -0,0 +1,16 @@ +package at.tuwien.entities.database.query; + +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@EqualsAndHashCode +public class FileKey implements Serializable { + + private Long id; + + private Long fdbid; + + private Long fqid; + +} diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/Query.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/Query.java index 6c6b9f363827ef5b39d2bc97cbd0f5b4b321bb20..00f941b0c35a9bb750dd46411f22962cef68fc93 100644 --- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/Query.java +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/Query.java @@ -1,5 +1,6 @@ package at.tuwien.entities.database.query; +import at.tuwien.entities.database.Database; import lombok.*; import org.hibernate.annotations.GenericGenerator; import org.springframework.data.annotation.CreatedDate; @@ -7,42 +8,74 @@ import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import javax.persistence.*; -import java.sql.Timestamp; import java.time.Instant; +import java.util.List; @Data +@Entity @Builder @AllArgsConstructor @NoArgsConstructor -@ToString(onlyExplicitlyIncluded = true) +@IdClass(QueryKey.class) @EntityListeners(AuditingEntityListener.class) -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -public class Query { +@javax.persistence.Table(name = "mdb_queries") +public class Query { - @EqualsAndHashCode.Include - @ToString.Include - private Long id; + @Id + @EqualsAndHashCode.Include + @ToString.Include + @GeneratedValue(generator = "query-sequence") + @GenericGenerator( + name = "query-sequence", + strategy = "enhanced-sequence", + parameters = @org.hibernate.annotations.Parameter(name = "sequence_name", value = "mdb_queries_seq") + ) + private Long id; - @ToString.Include - private String doi; + @Id + @EqualsAndHashCode.Include + @ToString.Include + private Long qdbid; - @ToString.Include - private Timestamp executionTimestamp; + @Column + private String doi; - @ToString.Include - private String query; + @Column + private String title; - @ToString.Include - private String queryNormalized; + @Column + private String query; - @ToString.Include - private String queryHash; + @Column + private String queryNormalized; - @ToString.Include - private String resultHash; + @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "query") + private List<File> files; - @ToString.Include - private Integer resultNumber; + @Column(name = "deposit_id", unique = true) + private Long depositId; + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JoinColumns({ + @JoinColumn(name = "qdbid", referencedColumnName = "id", insertable = false, updatable = false) + }) + private Database database; + + @Column + private Instant executionTimestamp; + + @Column + private String resultHash; + + @Column + private Long resultNumber; + + @Column(nullable = false, updatable = false) + @CreatedDate + private Instant created; + + @Column + @LastModifiedDate + private Instant lastModified; } diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/QueryKey.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/QueryKey.java new file mode 100644 index 0000000000000000000000000000000000000000..a4bfa7e1c2a7b8417aebb09ed48004610d7a54ac --- /dev/null +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/query/QueryKey.java @@ -0,0 +1,13 @@ +package at.tuwien.entities.database.query; + +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@EqualsAndHashCode +public class QueryKey implements Serializable { + + private Long id; + + private Long qdbid; +} diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/Table.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/Table.java index 94b5da4c9d7464383f9d7995bbbe06f353828e7f..2387da8345640c2068417dc1d7eadf830a7ca6b7 100644 --- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/Table.java +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/Table.java @@ -1,6 +1,7 @@ package at.tuwien.entities.database.table; import at.tuwien.entities.database.Database; +import at.tuwien.entities.database.query.Query; import at.tuwien.entities.database.table.columns.TableColumn; import lombok.*; import org.hibernate.annotations.GenericGenerator; @@ -30,7 +31,6 @@ public class Table { @Id @EqualsAndHashCode.Include - @ToString.Include @GeneratedValue(generator = "table-sequence") @GenericGenerator( name = "table-sequence", @@ -41,26 +41,17 @@ public class Table { @Id @EqualsAndHashCode.Include - @ToString.Include private Long tdbid; - @ToString.Include - @Column(nullable = true, name = "dep_id") - private Long depositId; - - @ToString.Include @Column(nullable = false, name = "tname") private String name; - @ToString.Include @Column(name = "tdescription") private String description; - @ToString.Include @Column(nullable = false) private String internalName; - @ToString.Include @Column(nullable = false, updatable = false) private String topic; @@ -69,7 +60,6 @@ public class Table { @JoinColumn(name = "tdbid", insertable = false, updatable = false) private Database database; - @ToString.Include @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "table") @Field(type = FieldType.Nested) private List<TableColumn> columns; diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java index 5419fde5fefe20ec766cf719a7cbed8b634c78bd..1a275eb465fa08ff4ff26aaa45d036fd3759c0e1 100644 --- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java @@ -16,62 +16,56 @@ import java.time.Instant; @Builder @AllArgsConstructor @NoArgsConstructor -@ToString(onlyExplicitlyIncluded = true) +@ToString @EntityListeners(AuditingEntityListener.class) @EqualsAndHashCode(onlyExplicitlyIncluded = true) @Table(name = "mdb_users") public class User { - @Id - @EqualsAndHashCode.Include - @ToString.Include - @Column(name = "userid", columnDefinition = "numeric(19, 2)") - @GeneratedValue(generator = "user-sequence") - @GenericGenerator( - name = "user-sequence", - strategy = "enhanced-sequence", - parameters = @org.hibernate.annotations.Parameter(name = "sequence_name", value = "mdb_user_seq") - ) - private Long id; + @Id + @EqualsAndHashCode.Include + @Column(name = "userid", columnDefinition = "numeric(19, 2)") + @GeneratedValue(generator = "user-sequence") + @GenericGenerator( + name = "user-sequence", + strategy = "enhanced-sequence", + parameters = @org.hibernate.annotations.Parameter(name = "sequence_name", value = "mdb_user_seq") + ) + private Long id; - @ToString.Include - @EqualsAndHashCode.Include - @Column(name = "tiss_id", unique = true) - private Long tissId; + @EqualsAndHashCode.Include + @Column(name = "tiss_id", unique = true) + private Long tissId; - @ToString.Include - @EqualsAndHashCode.Include - @Column(name = "oid", nullable = false) - private Long organizationid; + @EqualsAndHashCode.Include + @Column(name = "oid", nullable = false) + private Long organizationId; - @ToString.Include - @Column(name = "first_name", nullable = false) - private String firstname; + @EqualsAndHashCode.Include + @Column(name = "external_id", nullable = false, unique = true) + private String externalId; - @ToString.Include - @Column(name = "last_name", nullable = false) - private String lastname; + @Column(name = "first_name", nullable = false) + private String firstname; - @ToString.Include - @Column(name = "preceding_titles") - private String titlesBefore; + @Column(name = "last_name", nullable = false) + private String lastname; - @ToString.Include - @Column(name = "postpositioned_title") - private String titlesAfter; + @Column(name = "preceding_titles") + private String titlesBefore; - @ToString.Include - @Column(name = "main_email") - private String email; + @Column(name = "postpositioned_title") + private String titlesAfter; + @Column(name = "main_email") + private String email; + @Column(nullable = false, updatable = false) + @CreatedDate + private Instant created; - @Column(nullable = false, updatable = false) - @CreatedDate - private Instant created; - - @Column - @LastModifiedDate - private Instant lastModified; + @Column + @LastModifiedDate + private Instant lastModified; } diff --git a/fda-metadata-db/initi.sh b/fda-metadata-db/initi.sh index c7ec5cfe52c4cb31517532089d2689b86d4f85be..f1c2b6f2f7581a5a25e83da812ab27cac76ceb0f 100644 --- a/fda-metadata-db/initi.sh +++ b/fda-metadata-db/initi.sh @@ -22,6 +22,13 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E NO MAXVALUE CACHE 1; + CREATE SEQUENCE public.mdb_files_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + CREATE TABLE public.mdb_image_environment_item ( id bigint NOT NULL DEFAULT nextval('mdb_image_environment_item_seq'), created timestamp without time zone NOT NULL, @@ -106,6 +113,7 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E CREATE TABLE IF NOT EXISTS mdb_USERS ( UserID bigint PRIMARY KEY DEFAULT nextval('mdb_user_seq'), + external_id VARCHAR(255) UNIQUE NOT NULL, TISS_ID bigint, OID bigint, First_name VARCHAR(50), @@ -153,19 +161,6 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E NO MAXVALUE CACHE 1; - CREATE TABLE IF NOT EXISTS mdb_queries ( - ID bigint NOT NULL DEFAULT nextval('mdb_queries_seq'), - execution_timestamp timestamp without time zone NOT NULL, - query TEXT NOT NULL, - query_normalized TEXT NOT NULL, - query_hash character varying(255) NULL, - result_hash character varying(255) NULL, - result_number INTEGER NULL, - created timestamp without time zone NOT NULL, - last_modified timestamp without time zone, - PRIMARY KEY(ID) - ); - CREATE TABLE IF NOT EXISTS mdb_DATABASES ( ID bigint PRIMARY KEY DEFAULT nextval('mdb_databases_seq'), container_id bigint REFERENCES mdb_CONTAINER(id), @@ -192,7 +187,6 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E internal_name character varying(255) NOT NULL, topic character varying(255) NOT NULL, last_modified timestamp without time zone, - dep_id bigint UNIQUE, tName VARCHAR(50), tDescription TEXT, NumCols INTEGER, @@ -201,6 +195,36 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E PRIMARY KEY(tDBID,ID) ); + CREATE TABLE IF NOT EXISTS mdb_queries ( + ID bigint NOT NULL DEFAULT nextval('mdb_queries_seq'), + execution_timestamp timestamp without time zone, + deposit_id bigint NULL UNIQUE, + qdbid bigint NOT NULL, + title character varying(255) NULL, + doi character varying(255), + query TEXT NULL, + query_normalized TEXT NULL, + query_hash character varying(255) NULL, + result_hash character varying(255) NULL, + result_number bigint NULL, + created timestamp without time zone NOT NULL, + last_modified timestamp without time zone, + FOREIGN KEY (qdbid) REFERENCES mdb_DATABASES(ID), + PRIMARY KEY(qdbid, ID) + ); + + CREATE TABLE IF NOT EXISTS mdb_files ( + id bigint DEFAULT nextval('mdb_files_seq'), + fdbid bigint NOT NULL, + fqid bigint NOT NULL, + ref_id varchar(255) NOT NULL, + created timestamp without time zone NOT NULL, + last_modified timestamp without time zone, + FOREIGN KEY (fdbid) REFERENCES mdb_DATABASES(ID), + FOREIGN KEY (fdbid, fqid) REFERENCES mdb_queries(qdbid, ID), + PRIMARY KEY (fdbid, fqid, id) + ); + CREATE TABLE IF NOT EXISTS mdb_COLUMNS ( ID bigint DEFAULT nextval('mdb_columns_seq'), cDBID bigint, diff --git a/fda-query-service/.gitignore b/fda-query-service/.gitignore index 549e00a2a96fa9d7c5dbc9859664a78d980158c2..2365e522b6b8cfd3a10e3972137e8ff081c7be47 100644 --- a/fda-query-service/.gitignore +++ b/fda-query-service/.gitignore @@ -4,6 +4,8 @@ target/ !**/src/main/**/target/ !**/src/test/**/target/ +ready + ### STS ### .apt_generated .classpath diff --git a/fda-query-service/Dockerfile b/fda-query-service/Dockerfile index 2d105522da7a2700092d1bb99d3e7ddafc5aab17..aff9fe1a8add7f7a42c6c400a963b8ec974767d4 100644 --- a/fda-query-service/Dockerfile +++ b/fda-query-service/Dockerfile @@ -15,7 +15,10 @@ COPY ./rest-service ./rest-service COPY ./services ./services COPY ./report ./report -RUN mvn -q clean package -DskipTests +ARG CI_JOB_STAGE + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null ###### THIRD STAGE ###### FROM openjdk:11-jre-slim as runtime @@ -23,7 +26,7 @@ FROM openjdk:11-jre-slim as runtime COPY ./service_ready /usr/bin RUN chmod +x /usr/bin/service_ready -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD service_ready +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready COPY --from=build ./rest-service/target/rest-service-*.jar ./rest-service.jar diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-query-service/rest-service/src/main/java/at/tuwien/config/ReadyConfig.java index 08fe3d60dcd372e8268c3b3412599690a105b0ff..0bee3b961edd4ca456f0243c8eede630a4a54716 100644 --- a/fda-query-service/rest-service/src/main/java/at/tuwien/config/ReadyConfig.java +++ b/fda-query-service/rest-service/src/main/java/at/tuwien/config/ReadyConfig.java @@ -1,6 +1,7 @@ package at.tuwien.config; import com.google.common.io.Files; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; @@ -11,9 +12,12 @@ import java.io.IOException; @Configuration public class ReadyConfig { + @Value("${fda.ready.path}") + private String readyPath; + @EventListener(ApplicationReadyEvent.class) public void init() throws IOException { - Files.touch(new File("/tmp/ready")); + Files.touch(new File(readyPath)); } } diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java index e9fca78d057ed5d2abc16c795175d2e273403870..51668573f1d0ba9926e934901368ff99dcec070e 100644 --- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java +++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java @@ -1,8 +1,6 @@ package at.tuwien.endpoint; -import at.tuwien.api.database.query.ExecuteQueryDto; import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.entities.database.query.Query; import at.tuwien.exception.*; import at.tuwien.mapper.QueryMapper; @@ -10,77 +8,56 @@ import at.tuwien.service.QueryService; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import net.sf.jsqlparser.JSQLParserException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; -import java.awt.print.Pageable; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; import java.util.List; import java.util.stream.Collectors; @RestController -@RequestMapping("/api/database/{id}") +@RequestMapping("/api/database/{id}/metadata/query") public class QueryEndpoint { - private QueryService queryService; - private QueryMapper queryMapper; + private final QueryMapper queryMapper; + private final QueryService queryService; @Autowired - public QueryEndpoint(QueryService queryService, QueryMapper queryMapper) { - this.queryService = queryService; + public QueryEndpoint(QueryMapper queryMapper, QueryService queryService) { this.queryMapper = queryMapper; + this.queryService = queryService; } - @Transactional - @PutMapping("/query") - @ApiOperation(value = "executes a query") - @ApiResponses(value = { - @ApiResponse(code = 200, message = "Executed the query, Saved it and return the results"), + @GetMapping + @ApiOperation(value = "List all queries", notes = "Lists all known queries") + @ApiResponses({ + @ApiResponse(code = 200, message = "All queries are listed."), + @ApiResponse(code = 400, message = "Problem with reading the stored query."), @ApiResponse(code = 404, message = "The database does not exist."), - @ApiResponse(code = 405, message = "The container is not running."), - @ApiResponse(code = 409, message = "The container image is not supported."),}) - public ResponseEntity<QueryResultDto> execute(@PathVariable Long id, @RequestBody ExecuteQueryDto dto) - throws DatabaseNotFoundException, ImageNotSupportedException, SQLException, - JSQLParserException, QueryMalformedException, QueryStoreException { - final QueryResultDto response = queryService.execute(id, queryMapper.queryDTOtoQuery(dto)); - return ResponseEntity.ok(response); - } - + }) @Transactional - @PutMapping("/save") - @ApiOperation(value = "saves a query without execution") - @ApiResponses(value = { - @ApiResponse(code = 200, message = "Executed the query, Saved it and return the results"), - @ApiResponse(code = 404, message = "The database does not exist."), - @ApiResponse(code = 405, message = "The container is not running."), - @ApiResponse(code = 409, message = "The container image is not supported."),}) - public ResponseEntity<QueryResultDto> save(@PathVariable Long id, @RequestBody ExecuteQueryDto dto) - throws DatabaseNotFoundException, ImageNotSupportedException, SQLException, - JSQLParserException, QueryMalformedException, QueryStoreException { - final QueryResultDto response = queryService.save(id, queryMapper.queryDTOtoQuery(dto)); - return ResponseEntity.ok(response); + public ResponseEntity<List<QueryDto>> findAll(@PathVariable("id") Long databaseId) + throws DatabaseNotFoundException { + final List<Query> queries = queryService.findAll(databaseId); + return ResponseEntity.ok(queries.stream() + .map(queryMapper::queryToQueryDto) + .collect(Collectors.toList())); } - @Transactional - @GetMapping("/query/{queryId}") - @ApiOperation(value = "re-executes a query") - @ApiResponses(value = { - @ApiResponse(code = 200, message = "Re-Execute a saved query and return the results"), + @GetMapping("/{queryId}") + @ApiOperation(value = "Find a query", notes = "Find a query") + @ApiResponses({ + @ApiResponse(code = 200, message = "All queries are listed."), + @ApiResponse(code = 400, message = "Problem with reading the stored queries."), @ApiResponse(code = 404, message = "The database does not exist."), - @ApiResponse(code = 405, message = "The container is not running."), - @ApiResponse(code = 409, message = "The container image is not supported."),}) - public ResponseEntity<QueryResultDto> reexecute(@PathVariable Long id, @PathVariable Long queryId, @RequestParam(name="page", required= false) Integer page, @RequestParam(name = "size", required = false) Integer size) - throws DatabaseNotFoundException, ImageNotSupportedException, SQLException, - JSQLParserException, QueryMalformedException, QueryStoreException { - final QueryResultDto response = queryService.reexecute(id, queryId, page, size); - return ResponseEntity.ok(response); + }) + @Transactional + public ResponseEntity<QueryDto> find(@PathVariable("id") Long databaseId, + @PathVariable("queryId") Long queryId) + throws QueryNotFoundException { + return ResponseEntity.ok(queryMapper.queryToQueryDto(queryService.findById(databaseId, queryId))); } - } diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryStoreEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryStoreEndpoint.java index 9c2fb4013268c02936795cc48c0999433338c20d..6442f80422b9a3f372963d54be89f4c6b35c7233 100644 --- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryStoreEndpoint.java +++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryStoreEndpoint.java @@ -1,11 +1,11 @@ package at.tuwien.endpoint; +import at.tuwien.api.database.query.ExecuteQueryDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.entities.database.query.Query; import at.tuwien.exception.*; import at.tuwien.mapper.QueryMapper; -import at.tuwien.service.QueryService; import at.tuwien.service.QueryStoreService; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; @@ -13,16 +13,13 @@ import io.swagger.annotations.ApiResponses; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; -import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @RestController -@RequestMapping("/api/database/{id}/querystore") +@RequestMapping("/api/database/{id}/store") public class QueryStoreEndpoint { private QueryStoreService querystoreService; @@ -34,34 +31,92 @@ public class QueryStoreEndpoint { this.queryMapper = queryMapper; } - @Transactional - @GetMapping() + @PostMapping + @ApiOperation(value = "Creates the query Store") + @ApiResponses(value = { + @ApiResponse(code = 201, message = "Created the querystore successfully"), + @ApiResponse(code = 404, message = "The database does not exist."), + @ApiResponse(code = 405, message = "The container is not running."), + @ApiResponse(code = 409, message = "The container image is not supported."),}) + public ResponseEntity<?> create(@PathVariable Long id) throws ImageNotSupportedException, DatabaseNotFoundException, + QueryStoreException, DatabaseConnectionException { + querystoreService.create(id); + return ResponseEntity.status(HttpStatus.CREATED) + .build(); + } + + @PutMapping("/table/{tableId}/execute") + @ApiOperation(value = "executes a query") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Executed the query, Saved it and return the results"), + @ApiResponse(code = 404, message = "The database does not exist."), + @ApiResponse(code = 405, message = "The container is not running."), + @ApiResponse(code = 409, message = "The container image is not supported."),}) + public ResponseEntity<QueryResultDto> execute(@PathVariable("id") Long databaseId, + @PathVariable Long tableId, + @RequestBody ExecuteQueryDto data) + throws QueryStoreException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, + ImageNotSupportedException { + return ResponseEntity.ok(querystoreService.execute(databaseId, tableId, data)); + } + + @PostMapping("/table/{tableId}/save") + @ApiOperation(value = "saves a query without execution") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Executed the query, Saved it and return the results"), + @ApiResponse(code = 404, message = "The database does not exist."), + @ApiResponse(code = 405, message = "The container is not running."), + @ApiResponse(code = 409, message = "The container image is not supported."),}) + public ResponseEntity<QueryResultDto> save(@PathVariable("id") Long databaseId, + @PathVariable Long tableId, + @RequestBody ExecuteQueryDto data) + throws DatabaseNotFoundException, ImageNotSupportedException, QueryStoreException, + DatabaseConnectionException, QueryMalformedException { + return ResponseEntity.ok(querystoreService.save(databaseId, tableId, data)); + } + + @PutMapping("/table/{tableId}/execute/{queryId}") + @ApiOperation(value = "re-executes a query") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Re-Execute a saved query and return the results"), + @ApiResponse(code = 404, message = "The database does not exist."), + @ApiResponse(code = 405, message = "The container is not running."), + @ApiResponse(code = 409, message = "The container image is not supported."),}) + public ResponseEntity<QueryResultDto> reexecute(@PathVariable Long id, + @PathVariable Long queryId, + @RequestParam(name = "page", required = false) Integer page, + @RequestParam(name = "size", required = false) Integer size) + throws DatabaseNotFoundException, ImageNotSupportedException, DatabaseConnectionException, + QueryStoreException, QueryMalformedException { + return ResponseEntity.ok(querystoreService.reexecute(id, queryId, page, size)); + } + + @GetMapping @ApiOperation(value = "List all queries", notes = "Lists all already executed queries") @ApiResponses({ @ApiResponse(code = 200, message = "All queries are listed."), - @ApiResponse(code = 400, message = "Problem with reading the stored queries."), + @ApiResponse(code = 400, message = "Problem with reading the stored query."), @ApiResponse(code = 404, message = "The database does not exist."), }) - public ResponseEntity<List<Query>> findAll(@PathVariable Long id) throws DatabaseNotFoundException, - ImageNotSupportedException, DatabaseConnectionException, QueryMalformedException, SQLException, QueryStoreException { - final List<Query> result = querystoreService.findAll(id); - List<QueryDto> res = new ArrayList<>(); - /*for(Query r : result) { - res.add(queryMapper.queryToQueryDto(r)); - };*/ - return ResponseEntity.ok(result); + public ResponseEntity<List<QueryDto>> findAll(@PathVariable Long id) throws DatabaseNotFoundException, + ImageNotSupportedException, DatabaseConnectionException, QueryStoreException { + final List<Query> queries = querystoreService.findAll(id); + return ResponseEntity.ok(queries.stream() + .map(q -> queryMapper.queryToQueryDto(q)) + .collect(Collectors.toList())); } - @PostMapping() - @ApiOperation(value = "Creates the query Story") - @ApiResponses(value = { - @ApiResponse(code = 201, message = "Created the Querystore successfully"), + @GetMapping("/{queryId}") + @ApiOperation(value = "Find a query", notes = "Find a query") + @ApiResponses({ + @ApiResponse(code = 200, message = "All queries are listed."), + @ApiResponse(code = 400, message = "Problem with reading the stored queries."), @ApiResponse(code = 404, message = "The database does not exist."), - @ApiResponse(code = 405, message = "The container is not running."), - @ApiResponse(code = 409, message = "The container image is not supported."),}) - public ResponseEntity<?> create(@PathVariable Long id) throws ImageNotSupportedException, DatabaseNotFoundException, QueryStoreException, SQLException { - querystoreService.create(id); - return ResponseEntity.status(HttpStatus.CREATED) - .build(); + }) + public ResponseEntity<QueryDto> find(@PathVariable Long id, + @PathVariable Long queryId) + throws DatabaseNotFoundException, ImageNotSupportedException, DatabaseConnectionException, + QueryStoreException { + return ResponseEntity.ok(querystoreService.findOne(id, queryId)); } } diff --git a/fda-query-service/rest-service/src/main/resources/application-docker.yml b/fda-query-service/rest-service/src/main/resources/application-docker.yml index 6e33c51aee703dc76b3c8e01d09958554236e23d..68acda1c0805cef0c14a8bd3411f0cecd59550d8 100644 --- a/fda-query-service/rest-service/src/main/resources/application-docker.yml +++ b/fda-query-service/rest-service/src/main/resources/application-docker.yml @@ -20,7 +20,9 @@ logging: pattern.console: "%d %highlight(%-5level) %msg%n" level: root: warn - at.tuwien.: debug + at.tuwien.: trace eureka: instance.hostname: fda-query-service - client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/ \ No newline at end of file + client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/ +fda: + ready.path: /ready \ No newline at end of file diff --git a/fda-query-service/rest-service/src/main/resources/application.yml b/fda-query-service/rest-service/src/main/resources/application.yml index 043b450e16b7a263feb53ddfcc69f9ae943f915f..6cd3d360c0605a3aac2bff3f4ba26bf6a2ddeeea 100644 --- a/fda-query-service/rest-service/src/main/resources/application.yml +++ b/fda-query-service/rest-service/src/main/resources/application.yml @@ -9,7 +9,7 @@ spring: show-sql: true database-platform: org.hibernate.dialect.PostgreSQLDialect hibernate: - ddl-auto: update + ddl-auto: validate open-in-view: false application: name: fda-query-service @@ -23,4 +23,6 @@ logging: at.tuwien.: debug eureka: instance.hostname: fda-query-service - client.serviceUrl.defaultZone: http://localhost:9090/eureka/ \ No newline at end of file + client.serviceUrl.defaultZone: http://localhost:9090/eureka/ +fda: + ready.path: ./ready \ No newline at end of file diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index 13865fc91028b4decc5ae582803ac349a7b12207..aa365483693cc7c570e4350176b6312bc31cb0b2 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -144,19 +144,4 @@ public abstract class BaseUnitTest { .container(CONTAINER_2) .build(); - public final Query QUERY_1 = Query.builder().query("ST * from t").build(); - - /* - public final Query QUERY_1 = Query.builder() - .id(QUERY_1_ID) - .created(QUERY_1_CREATED) - .lastModified(QUERY_1_UPDATED) - .query(QUERY_1_STATEMENT) - .executionTimestamp(QUERY_1_TIMESTAMP) - .queryHash(QUERY_1_HASH) - .queryNormalized(QUERY_1_NORMALIZED) - .resultHash(QUERY_1_RESULTHASH) - .resultNumber(QUERY_1_RESULTNUMBER) - .build(); -*/ } diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java index 8cc4252b6db746829f9bd5cc0e7ff272d5dd801b..3d327f154e8eb8a08e0b4111d7ebfad0f4cb2651 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java @@ -38,39 +38,14 @@ public class QueryServiceUnitTest extends BaseUnitTest { @Autowired private QueryStoreService queryStoreService; - - - - - - - /* - @Test - public void findAll_notPostgres_fails() throws DatabaseConnectionException, QueryMalformedException { - when(databaseRepository.findById(DATABASE_2_ID)) - .thenReturn(Optional.of(DATABASE_2)); - when(postgresService.getQueries(DATABASE_2)) - .thenThrow(QueryMalformedException.class); - - /* test - assertThrows(QueryMalformedException.class, () -> { - queryService.findAll(DATABASE_2_ID); - }); - } */ - @Test public void executeStatement_succeeds() { // } - //@Test - public void execute_notValidSyntax_fails() throws DatabaseNotFoundException, SQLException, ImageNotSupportedException { - when(queryStoreService.exists(DATABASE_1)) - .thenReturn(true); - - assertThrows(JSQLParserException.class, () -> { - queryService.execute(DATABASE_1_ID, QUERY_1); - }); + @Test + public void execute_notValidSyntax_fails() throws ImageNotSupportedException, DatabaseConnectionException { + // } @Test diff --git a/fda-query-service/rest-service/src/test/resources/application.properties b/fda-query-service/rest-service/src/test/resources/application.properties index 2871cae9642987896d091460c42d1f27f857c25c..1f8a9f4089f393b2a8d25f28472a80a35658aab5 100644 --- a/fda-query-service/rest-service/src/test/resources/application.properties +++ b/fda-query-service/rest-service/src/test/resources/application.properties @@ -6,8 +6,10 @@ spring.cloud.config.discovery.enabled = false spring.cloud.config.enabled = false # disable datasource -spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect \ No newline at end of file +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=false \ No newline at end of file diff --git a/fda-query-service/rest-service/src/test/resources/integration-test.after b/fda-query-service/rest-service/src/test/resources/integration-test.after deleted file mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..0000000000000000000000000000000000000000 --- a/fda-query-service/rest-service/src/test/resources/integration-test.after +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/fda-query-service/rest-service/src/test/resources/integration-test.before b/fda-query-service/rest-service/src/test/resources/integration-test.before deleted file mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..0000000000000000000000000000000000000000 --- a/fda-query-service/rest-service/src/test/resources/integration-test.before +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/fda-query-service/service_ready b/fda-query-service/service_ready index 3e660ed2801a7a88b2227f3a4b093774beaa0350..b2e4f9df6804f249ba8aadd72f742929072badaa 100644 --- a/fda-query-service/service_ready +++ b/fda-query-service/service_ready @@ -1,5 +1,5 @@ #!/bin/bash -if [ -f /tmp/ready ]; then +if [ -f /ready ]; then echo "service is ready and accepting connections" exit 0 fi diff --git a/fda-query-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java b/fda-query-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..a5e90754898f19f6cce8938d2385f3f9fecd43e4 --- /dev/null +++ b/fda-query-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class QueryNotFoundException extends Exception { + + public QueryNotFoundException(String msg) { + super(msg); + } + + public QueryNotFoundException(String msg, Throwable thr) { + super(msg, thr); + } + + public QueryNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java index 73276208e4564d77c4cc03897cc7d98b50214818..820e177fc3f8132f5a368ab6f924d0d222f21e67 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java +++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java @@ -7,21 +7,34 @@ import at.tuwien.entities.database.query.Query; import org.jooq.Field; import org.jooq.Record; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.Named; -import java.sql.Timestamp; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.stream.Collectors; @Mapper(componentModel = "spring") public interface QueryMapper { - QueryResultDto queryToQueryResultDTO(Query query); + QueryResultDto queryToQueryResultDto(Query data); - Query queryDTOtoQuery(ExecuteQueryDto queryDTO); + Query executeQueryDtoToQuery(ExecuteQueryDto data); - QueryDto queryToQueryDto(Query query); + Query queryDtotoQuery(QueryDto data); + QueryDto queryToQueryDto(Query data); - default QueryResultDto recordListToQueryResultDto(List<Record> data) { + @Mappings({ + @Mapping(source = "query", target = "query"), + @Mapping(source = "query", target = "queryNormalized") + }) + QueryDto executeQueryDtoToQueryDto(ExecuteQueryDto data); + + default QueryResultDto recordListToQueryResultDto(List<Record> data, Long queryId) { final List<Map<String, Object>> result = new LinkedList<>(); for (Record record : data) { final Map<String, Object> map = new HashMap<>(); @@ -31,28 +44,40 @@ public interface QueryMapper { result.add(map); } return QueryResultDto.builder() + .id(queryId) .result(result) .build(); } - default List<Query> recordListToQueryList(List<Record> data) { - QueryResultDto queryResultDto = recordListToQueryResultDto(data); - List<Query> queries = new ArrayList<>(); - int i=0; - for (Map<String, Object> m : queryResultDto.getResult()) { - queries.add(Query.builder() - .id((Long.valueOf((Integer) m.get("id")))) - .query((String)m.get("query")) - .queryHash((String)m.get("query_hash")) - .queryNormalized((String)m.get("query_normalized")) - .resultHash((String)m.get("result_hash")) - .resultNumber((Integer)m.get("result_number")) - .executionTimestamp((Timestamp)m.get("execution_timestamp")) - .build()); - } - return queries; + default QueryDto recordToQueryDto(Record data) { + return QueryDto.builder() + .id(Long.parseLong(String.valueOf(data.get("id")))) + .query(String.valueOf(data.get("query"))) + .queryHash(String.valueOf(data.get("query_hash"))) + .executionTimestamp(objectToInstant(data.get("execution_timestamp"))) + .resultHash(String.valueOf(data.get("result_hash"))) + .resultNumber(Long.parseLong(String.valueOf(data.get("result_number")))) + .build(); } + default List<Query> recordListToQueryList(List<Record> data) { + return recordListToQueryResultDto(data, null) + .getResult() + .stream() + .map(row -> Query.builder() + .id(Long.valueOf(String.valueOf(row.get("id")))) + .resultHash(String.valueOf(row.get("result_hash"))) + .resultNumber(Long.valueOf(String.valueOf(row.get("result_number")))) + .executionTimestamp(objectToInstant(row.get("execution_timestamp"))) + .build()) + .collect(Collectors.toList()); + } + default Instant objectToInstant(Object data) { + if (data == null) { + return null; + } + return Instant.parse(data.toString()); + } } diff --git a/fda-query-service/services/src/main/java/at/tuwien/repository/ContainerRepository.java b/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java similarity index 88% rename from fda-query-service/services/src/main/java/at/tuwien/repository/ContainerRepository.java rename to fda-query-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java index ae72a7d1feaabbaf1a9a27a890feae604a5a8343..39566b1cc0c471f71212f9319e1497d0e3dcac66 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/repository/ContainerRepository.java +++ b/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java @@ -1,4 +1,4 @@ -package at.tuwien.repository; +package at.tuwien.repository.jpa; import at.tuwien.entities.container.Container; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/fda-query-service/services/src/main/java/at/tuwien/repository/ImageRepository.java b/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/ImageRepository.java similarity index 85% rename from fda-query-service/services/src/main/java/at/tuwien/repository/ImageRepository.java rename to fda-query-service/services/src/main/java/at/tuwien/repository/jpa/ImageRepository.java index f82f82165e4e3f9f53354b27bb0fbbe1a8d1208f..21f191f8eddc0ebf9e0d6a01f8961a81f0fb6c39 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/repository/ImageRepository.java +++ b/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/ImageRepository.java @@ -1,4 +1,4 @@ -package at.tuwien.repository; +package at.tuwien.repository.jpa; import at.tuwien.entities.container.image.ContainerImage; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/QueryRepository.java b/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/QueryRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..db78a5a26bde7996627ff6cca17139174116900b --- /dev/null +++ b/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/QueryRepository.java @@ -0,0 +1,17 @@ +package at.tuwien.repository.jpa; + +import at.tuwien.entities.database.Database; +import at.tuwien.entities.database.query.Query; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + + +@Repository +public interface QueryRepository extends JpaRepository<Query, Long> { + + Optional<Query> findByDatabaseAndId(Database database, Long id); + +} + diff --git a/fda-query-service/services/src/main/java/at/tuwien/repository/TableRepository.java b/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/TableRepository.java similarity index 94% rename from fda-query-service/services/src/main/java/at/tuwien/repository/TableRepository.java rename to fda-query-service/services/src/main/java/at/tuwien/repository/jpa/TableRepository.java index c65c8e38f95dcd7f14b69f0549f1ccf2171d155e..ffecb43d937bf00bbaecb3459bdd83ac8372d0b4 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/repository/TableRepository.java +++ b/fda-query-service/services/src/main/java/at/tuwien/repository/jpa/TableRepository.java @@ -1,4 +1,4 @@ -package at.tuwien.repository; +package at.tuwien.repository.jpa; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.table.Table; diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/JdbcConnector.java b/fda-query-service/services/src/main/java/at/tuwien/service/JdbcConnector.java index ec85196832f2fa339fad658dfa1ed88cfc33fba2..44590f5aa4d045f7b0bdc72fcc7f3f76f254e329 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/JdbcConnector.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/JdbcConnector.java @@ -1,44 +1,31 @@ package at.tuwien.service; -import at.tuwien.api.database.query.QueryResultDto; -import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.query.Query; -import at.tuwien.exception.DatabaseConnectionException; -import at.tuwien.exception.DatabaseNotFoundException; import at.tuwien.exception.ImageNotSupportedException; -import at.tuwien.exception.QueryMalformedException; import at.tuwien.mapper.ImageMapper; -import at.tuwien.mapper.QueryMapper; import lombok.extern.log4j.Log4j2; import org.jooq.*; -import org.jooq.Record; import org.jooq.impl.DSL; import org.springframework.beans.factory.annotation.Autowired; import java.sql.*; -import java.util.List; -import java.util.Properties; -import static org.jooq.impl.DSL.*; @Log4j2 public abstract class JdbcConnector { private final ImageMapper imageMapper; - private final QueryMapper queryMapper; @Autowired - protected JdbcConnector(ImageMapper imageMapper, QueryMapper queryMapper) { + protected JdbcConnector(ImageMapper imageMapper) { this.imageMapper = imageMapper; - this.queryMapper = queryMapper; } protected DSLContext open(Database database) throws SQLException, ImageNotSupportedException { final String url = "jdbc:" + database.getContainer().getImage().getJdbcMethod() + "://" + database.getContainer().getInternalName() + "/" + database.getInternalName(); - log.info("Attempt to connect to '{}'", url); + log.trace("Attempt to connect to '{}'", url); final Connection connection = DriverManager.getConnection(url, imageMapper.containerImageToProperties(database.getContainer().getImage())); return DSL.using(connection, SQLDialect.valueOf(database.getContainer().getImage().getDialect())); } diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java index 25dc227cf8db48ce5ca7e4d83c5e6a822482088c..ef100f813282c295499612cccaa3185b9ef75e76 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java @@ -1,255 +1,56 @@ package at.tuwien.service; -import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.query.Query; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.exception.*; import at.tuwien.mapper.ImageMapper; -import at.tuwien.mapper.QueryMapper; import at.tuwien.repository.jpa.DatabaseRepository; +import at.tuwien.repository.jpa.QueryRepository; import lombok.extern.log4j.Log4j2; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.parser.CCJSqlParserManager; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.select.*; -import org.jooq.DSLContext; -import org.jooq.Record; -import org.jooq.Result; -import org.jooq.ResultQuery; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.awt.print.Pageable; -import java.io.StringReader; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.Optional; -import static org.jooq.impl.DSL.constraint; - @Log4j2 @Service public class QueryService extends JdbcConnector { + private final QueryRepository queryRepository; private final DatabaseRepository databaseRepository; - private final QueryStoreService queryStoreService; - private final QueryMapper queryMapper; @Autowired - public QueryService(ImageMapper imageMapper, QueryMapper queryMapper, DatabaseRepository databaseRepository, QueryStoreService queryStoreService) { - super(imageMapper, queryMapper); + public QueryService(ImageMapper imageMapper, QueryRepository queryRepository, + DatabaseRepository databaseRepository) { + super(imageMapper); + this.queryRepository = queryRepository; this.databaseRepository = databaseRepository; - this.queryStoreService = queryStoreService; - this.queryMapper = queryMapper; } @Deprecated @Transactional - public QueryResultDto execute(Long id, Query query) throws ImageNotSupportedException, DatabaseNotFoundException, JSQLParserException, SQLException, QueryMalformedException, QueryStoreException { - Database database = findDatabase(id); - if(database.getContainer().getImage().getDialect().equals("MARIADB")){ - if(!queryStoreService.exists(database)) { - queryStoreService.create(id); - } - } - DSLContext context = open(database); - //TODO Fix that import - StringBuilder parsedQuery = new StringBuilder(); - String q = parse(query, database).getQuery(); - if(q.charAt(q.length()-1) == ';') { - parsedQuery.append(q.substring(0, q.length()-2)); - } else { - parsedQuery.append(q); - } - parsedQuery.append(";"); - - ResultQuery<Record> resultQuery = context.resultQuery(parsedQuery.toString()); - Result<Record> result = resultQuery.fetch(); - QueryResultDto queryResultDto = queryMapper.recordListToQueryResultDto(result); - log.debug("Result of the query is: \n {}", result.toString()); - - // Save the query in the store - boolean b = queryStoreService.saveQuery(database, query, queryResultDto); - log.debug("Save query returned code {}", b); - return queryResultDto; - } - - private Query parse(Query query, Database database) throws SQLException, ImageNotSupportedException, JSQLParserException { - Timestamp ts = new Timestamp(System.currentTimeMillis()); - query.setExecutionTimestamp(ts); - CCJSqlParserManager parserRealSql = new CCJSqlParserManager(); - Statement statement = parserRealSql.parse(new StringReader(query.getQuery())); - log.debug("Given query {}", query.getQuery()); - - if(statement instanceof Select) { - Select selectStatement = (Select) statement; - PlainSelect ps = (PlainSelect)selectStatement.getSelectBody(); - List<SelectItem> selectItems = ps.getSelectItems(); - - //Parse all tables - List<FromItem> fromItems = new ArrayList<>(); - fromItems.add(ps.getFromItem()); - if(ps.getJoins() != null && ps.getJoins().size() > 0) { - for (Join j : ps.getJoins()) { - if (j.getRightItem() != null) { - fromItems.add(j.getRightItem()); - } - } - } - //Checking if all tables exist - List<TableColumn> allColumns = new ArrayList<>(); - for(FromItem f : fromItems) { - boolean i = false; - log.debug("from item iterated through: {}", f); - for(Table t : database.getTables()) { - if(f.toString().equals(t.getInternalName()) || f.toString().equals(t.getName())) { - allColumns.addAll(t.getColumns()); - i=false; - break; - } - i = true; - } - if(i) { - throw new JSQLParserException("Table "+f.toString() + " does not exist"); - } - } - - //Checking if all columns exist - for(SelectItem s : selectItems) { - String select = s.toString(); - if(select.trim().equals("*")) { - log.debug("Please do not use * to query data"); - continue; - } - // ignore prefixes - if(select.contains(".")) { - log.debug(select); - select = select.split("\\.")[1]; - } - boolean i = false; - for(TableColumn tc : allColumns ) { - log.debug("{},{},{}", tc.getInternalName(), tc.getName(), s); - if(select.equals(tc.getInternalName()) || select.toString().equals(tc.getName())) { - i=false; - break; - } - i = true; - } - if(i) { - throw new JSQLParserException("Column "+s.toString() + " does not exist"); - } - } - //TODO Future work - if(ps.getWhere() != null) { - Expression where = ps.getWhere(); - log.debug("Where clause: {}", where); - } - return query; - } - else { - throw new JSQLParserException("SQL Query is not a SELECT statement - please only use SELECT statements"); - } - - } - - @Transactional - public Database findDatabase(Long id) throws DatabaseNotFoundException { - final Optional<Database> database = databaseRepository.findById(id); + public List<Query> findAll(Long databaseId) throws DatabaseNotFoundException { + final Optional<Database> database = databaseRepository.findById(databaseId); if (database.isEmpty()) { - log.error("no database with this id found in metadata database"); - throw new DatabaseNotFoundException("database not found in metadata database"); + throw new DatabaseNotFoundException("Database not found in the metadata database"); } - return database.get(); - } - - - public QueryResultDto reexecute(Long databaseId, Long queryId, Integer page, Integer size) throws DatabaseNotFoundException, SQLException, ImageNotSupportedException { - log.info("re-execute query with the id {}", queryId); - DSLContext context = open(findDatabase(databaseId)); - QueryResultDto savedQuery = queryStoreService.findOne(databaseId, queryId); - StringBuilder query = new StringBuilder(); - query.append("SELECT * FROM ("); - String q = (String)savedQuery.getResult().get(0).get("query"); - if(q.toLowerCase(Locale.ROOT).contains("where")) { - String[] split = q.toLowerCase(Locale.ROOT).split("where"); - if(split.length > 2) { - //TODO FIX SUBQUERIES WITH MULTIPLE Wheres - throw new SQLException("Query Contains Subqueries, this will be supported in a future version"); - } else { - query.append(split[0]); - query.append(" FOR SYSTEM_TIME AS OF TIMESTAMP'"); - Timestamp t = (Timestamp)savedQuery.getResult().get(0).get("execution_timestamp"); - query.append(t.toLocalDateTime().toString()); - - query.append("' WHERE"); - query.append(split[1]); - query.append(") as tab"); - } - } else { - query.append(q); - query.append(" FOR SYSTEM_TIME AS OF TIMESTAMP'"); - Timestamp t = (Timestamp)savedQuery.getResult().get(0).get("execution_timestamp"); - - query.append(t.toLocalDateTime().toString()); - query.append("') as tab"); - } - - - if(page != null && size != null) { - page = Math.abs(page); - size = Math.abs(size); - query.append(" LIMIT "); - query.append(size); - query.append(" OFFSET "); - query.append(page * size); - } - query.append(";"); - - log.debug(query.toString()); - ResultQuery<Record> resultQuery = context.resultQuery(query.toString()); - Result<Record> result = resultQuery.fetch(); - QueryResultDto queryResultDto = queryMapper.recordListToQueryResultDto(result); - log.debug(result.toString()); - - return queryResultDto; + final List<Query> queries = database.get() + .getQueries(); + return queries; } @Transactional - public QueryResultDto save(Long id, Query query) throws SQLException, ImageNotSupportedException, DatabaseNotFoundException, QueryStoreException, JSQLParserException { - Database database = findDatabase(id); - if(database.getContainer().getImage().getDialect().equals("MARIADB")){ - if(!queryStoreService.exists(database)) { - queryStoreService.create(id); - } - } - DSLContext context = open(database); - StringBuilder parsedQuery = new StringBuilder(); - String q = parse(query, database).getQuery(); - if(q.charAt(q.length()-1) == ';') { - parsedQuery.append(q.substring(0, q.length()-2)); - } else { - parsedQuery.append(q); - } - parsedQuery.append(";"); - - ResultQuery<Record> resultQuery = context.resultQuery(parsedQuery.toString()); - Result<Record> result = resultQuery.fetch(); - QueryResultDto queryResultDto = queryMapper.recordListToQueryResultDto(result); - log.debug("Result of the query is: \n {}", result.toString()); - - // Save the query in the store - boolean b = queryStoreService.saveQuery(database, query, queryResultDto); - log.debug("Save query returned code {}", b); - QueryResultDto savedQuery = queryStoreService.findLast(database.getId()); - return savedQuery; + public Query findById(Long databaseId, Long queryId) throws QueryNotFoundException { + final Database database = Database.builder() + .id(databaseId) + .build(); + final Optional<Query> query = queryRepository.findByDatabaseAndId(database, queryId); + if (query.isEmpty()) { + log.error("Query with id {} was not found to metadata database", queryId); + throw new QueryNotFoundException("Query was not found to metadata database"); + } + return query.get(); } -} +} \ No newline at end of file diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/QueryStoreService.java b/fda-query-service/services/src/main/java/at/tuwien/service/QueryStoreService.java index da1f17b8efd2644f157c4e432e6c99d579f8c494..d7f9c8d996cd958bd6d0339ce28a1f2aa32339b0 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/QueryStoreService.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/QueryStoreService.java @@ -1,23 +1,37 @@ package at.tuwien.service; +import at.tuwien.api.database.query.ExecuteQueryDto; +import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.query.Query; +import at.tuwien.entities.database.table.Table; +import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.exception.*; import at.tuwien.mapper.ImageMapper; import at.tuwien.mapper.QueryMapper; import at.tuwien.repository.jpa.DatabaseRepository; +import at.tuwien.repository.jpa.QueryRepository; import lombok.extern.log4j.Log4j2; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.parser.CCJSqlParserManager; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.select.*; +import net.sf.jsqlparser.statement.select.Select; import org.jooq.*; -import org.jooq.impl.DSL; import org.junit.jupiter.params.shadow.com.univocity.parsers.common.DataProcessingException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.StringReader; import java.sql.SQLException; import java.sql.Timestamp; -import java.util.Comparator; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Optional; @@ -29,129 +43,152 @@ import static org.jooq.impl.SQLDataType.*; @Service public class QueryStoreService extends JdbcConnector { + private final static String QUERYSTORENAME = "mdb_querystore"; + private final DatabaseRepository databaseRepository; - private final String QUERYSTORENAME = "mdb_querystore"; + private final QueryRepository queryRepository; private final QueryMapper queryMapper; @Autowired - public QueryStoreService(ImageMapper imageMapper, QueryMapper queryMapper, DatabaseRepository databaseRepository) { - super(imageMapper, queryMapper); + public QueryStoreService(ImageMapper imageMapper, QueryMapper queryMapper, DatabaseRepository databaseRepository, + QueryRepository queryRepository) { + super(imageMapper); this.databaseRepository = databaseRepository; this.queryMapper = queryMapper; + this.queryRepository = queryRepository; } @Transactional - public List<Query> findAll(Long id) throws ImageNotSupportedException, DatabaseNotFoundException, DatabaseConnectionException, QueryMalformedException, SQLException, QueryStoreException { - Database database = findDatabase(id); - if(!exists(database)){ + public List<Query> findAll(Long id) throws ImageNotSupportedException, DatabaseNotFoundException, + DatabaseConnectionException, QueryStoreException { + final Database database = findDatabase(id); + if (!exists(database)) { create(id); } - DSLContext context = open(database); - ResultQuery<org.jooq.Record> resultQuery = context.selectQuery(); - Result<org.jooq.Record> result = resultQuery.fetch(); - log.debug(result.toString()); + final DSLContext context; + try { + context = open(database); + } catch (SQLException e) { + throw new DatabaseConnectionException("Could not connect to remote container", e); + } + log.trace("select query {}", context.selectQuery() + .fetch() + .toString()); return queryMapper.recordListToQueryList(context - .selectFrom(QUERYSTORENAME) //TODO Order after timestamps - .fetch()); - } - - public QueryResultDto findOne(Long databaseId, Long queryId) throws DatabaseNotFoundException, SQLException, ImageNotSupportedException { - Database database = findDatabase(databaseId); - DSLContext context = open(database); - ResultQuery<org.jooq.Record> resultQuery = context.selectQuery(); - Result<org.jooq.Record> result = resultQuery.fetch(); - log.debug(result.toString()); - return queryMapper.recordListToQueryResultDto(context - .selectFrom(QUERYSTORENAME).where("id = "+ queryId) + .selectFrom(QUERYSTORENAME) + .orderBy(field("execution_timestamp")) .fetch()); } - public QueryResultDto findLast(Long databaseId) throws DatabaseNotFoundException, SQLException, ImageNotSupportedException { + @Transactional + public QueryDto findOne(Long databaseId, Long queryId) throws DatabaseNotFoundException, + ImageNotSupportedException, DatabaseConnectionException, QueryStoreException { Database database = findDatabase(databaseId); - DSLContext context = open(database); - StringBuilder sb = new StringBuilder(); - sb.append("SELECT * FROM "); - sb.append(QUERYSTORENAME); - sb.append(" ORDER BY id desc LIMIT 1;"); - return queryMapper.recordListToQueryResultDto(context - .fetch(sb.toString())); + final DSLContext context; + try { + context = open(database); + } catch (SQLException e) { + throw new DatabaseConnectionException("Could not connect to remote container", e); + } + log.trace("select query {}", context.selectQuery() + .fetch() + .toString()); + final List<org.jooq.Record> records = context + .selectFrom(QUERYSTORENAME).where(condition("id = " + queryId)) + .fetch(); + if (records.size() != 1) { + throw new QueryStoreException("Failed to get query from querystore"); + } + return queryMapper.recordToQueryDto(records.get(0)); } /** - * Creates the querystore for a given database - * @param databaseId - * @throws ImageNotSupportedException - * @throws DatabaseNotFoundException + * Creates the query store on the remote container for a given database id + * mw: unfortunately we cannot provide a default sequence nextval for the id + * + * @param databaseId The database id + * @throws ImageNotSupportedException The image is not supported + * @throws DatabaseNotFoundException The database was not found in the metadata database + * @throws QueryStoreException Some error with the query store + * @throws DatabaseConnectionException The connection to the remote container was not able to be established */ @Transactional - public void create(Long databaseId) throws ImageNotSupportedException, DatabaseNotFoundException, QueryStoreException, SQLException { - log.info("Create QueryStore"); + public void create(Long databaseId) throws ImageNotSupportedException, DatabaseNotFoundException, + QueryStoreException, DatabaseConnectionException { final Database database = findDatabase(databaseId); - if(exists(database)) { - log.info("Querystore already exists"); - throw new QueryStoreException("Querystore already exists"); + if (exists(database)) { + log.error("Query store already exists for database id {}", databaseId); + throw new QueryStoreException("Query store already exists"); } /* create database in container */ try { final DSLContext context = open(database); + context.createSequence("seq_id") + .execute(); context.createTable(QUERYSTORENAME) - .column("id", INTEGER) + .column("id", BIGINT) .column("doi", VARCHAR(255).nullable(false)) + .column("title", VARCHAR(255).nullable(false)) .column("query", VARCHAR(255).nullable(false)) .column("query_hash", VARCHAR(255)) .column("execution_timestamp", TIMESTAMP) .column("result_hash", VARCHAR(255)) - .column("result_number", INTEGER) + .column("result_number", BIGINT) .constraints( constraint("pk").primaryKey("id"), constraint("uk").unique("doi") - ) - .execute(); - + ).execute(); + log.info("Created query store in database id {}", databaseId); + log.debug("created query store in database {}", database); } catch (SQLException e) { + log.error("Failed to create query store: {}", e.getMessage()); throw new DataProcessingException("could not create table", e); } } - public boolean saveQuery(Database database, Query query, QueryResultDto queryResult) throws SQLException, ImageNotSupportedException { - log.debug("Save Query"); - String q = query.getQuery(); - - - query.setExecutionTimestamp(new Timestamp(System.currentTimeMillis())); + public QueryDto saveQuery(Database database, QueryDto query, QueryResultDto queryResult) + throws ImageNotSupportedException, QueryStoreException { + // TODO map in mapper next iteration + query.setExecutionTimestamp(Instant.now()); query.setQueryNormalized(normalizeQuery(query.getQuery())); - query.setQueryHash(query.getQueryNormalized().toLowerCase(Locale.ROOT).hashCode() + ""); + query.setQueryHash(String.valueOf(query.getQueryNormalized().toLowerCase(Locale.ROOT).hashCode())); query.setResultHash(query.getQueryHash()); - query.setResultNumber(0); - query.setId(Long.valueOf(maxId(database))+1); - DSLContext context = open(database); - int success = context.insertInto(table(QUERYSTORENAME)) - .columns(field("id"), - field("doi"), - field("query"), - field("query_hash"), - field("execution_timestamp"), - field("result_hash"), - field("result_number")) - .values(query.getId(), "doi/"+query.getId(), query.getQuery(), query.getQueryHash(), query.getExecutionTimestamp(), ""+queryResult.hashCode(), queryResult.getResult().size()).execute(); - return success == 1 ? true : false; - } - - public Integer maxId(Database database) throws SQLException, ImageNotSupportedException { - DSLContext context = open(database); - QueryResultDto queryResultDto = queryMapper.recordListToQueryResultDto(context - .selectFrom(QUERYSTORENAME).orderBy(field("id").desc()).limit(1) - .fetch()); - if(queryResultDto.getResult() == null || queryResultDto.getResult().size() == 0) { - return 0; + query.setResultNumber(0L); + try { + final DSLContext context = open(database); + int success = context.insertInto(table(QUERYSTORENAME)) + .columns(field("id"), + field("doi"), + field("title"), + field("query"), + field("query_hash"), + field("execution_timestamp"), + field("result_hash"), + field("result_number")) + .values(sequence("seq_id").nextval(), "doi/" + query.getId(), query.getTitle(), query.getQuery(), + query.getQueryHash(), LocalDateTime.ofInstant(query.getExecutionTimestamp(), + ZoneId.of("Europe/Vienna")), "" + queryResult.hashCode(), + queryResult.getResult().size()) + .execute(); + log.info("Saved query into query store id {}", query.getId()); + log.debug("Saved query into query store {}", query); + if (success != 1) { + log.error("Failed to insert record into query store"); + throw new QueryStoreException("Failed to insert record into query store"); + } + } catch (SQLException e) { + log.error("The mapped query is not valid: {}", e.getMessage()); + throw new QueryStoreException("The mapped query is not valid", e); } - return (Integer) queryResultDto.getResult().get(0).get("id"); + return query; } + // FIXME mw: lel private String normalizeQuery(String query) { return query; } + @Deprecated private boolean checkValidity(String query) { String queryparts[] = query.toLowerCase().split("from"); if (queryparts[0].contains("select")) { @@ -162,21 +199,289 @@ public class QueryStoreService extends JdbcConnector { } @Transactional - public Database findDatabase(Long id) throws DatabaseNotFoundException { + public QueryResultDto execute(Long databaseId, Long tableId, ExecuteQueryDto data) throws ImageNotSupportedException, + DatabaseNotFoundException, QueryStoreException, DatabaseConnectionException, QueryMalformedException { + final Database database = findDatabase(databaseId); + if (database.getContainer().getImage().getDialect().equals("MARIADB")) { + if (!exists(database)) { + create(databaseId); + } + } + final DSLContext context; + try { + context = open(database); + } catch (SQLException e) { + log.error("Failed to connect to the remote database: {}", e.getMessage()); + throw new DatabaseConnectionException("Failed to connect to the remote database", e); + } + final QueryDto query = queryMapper.executeQueryDtoToQueryDto(data); + final QueryResultDto queryResultDto = executeQueryOnContext(context, query, database); + log.trace("Result of the query is: \n {}", queryResultDto.getResult()); + + /* save some metadata */ + final Query metaQuery = queryMapper.queryDtotoQuery(query); + metaQuery.setExecutionTimestamp(null); + metaQuery.setTitle(data.getTitle()); + metaQuery.setQdbid(databaseId); + final Query res = queryRepository.save(metaQuery); + log.info("Saved executed query in metadata database id {}", res.getId()); + + /* save the query in the store */ + final QueryDto out = saveQuery(database, query, queryResultDto); + queryResultDto.setId(out.getId()); + log.info("Saved executed query in query store {}", out.getId()); + log.debug("query store {}", out); + return queryResultDto; + } + + private QueryDto parse(QueryDto query, Database database) throws JSQLParserException, QueryMalformedException { + query.setExecutionTimestamp(query.getExecutionTimestamp()); + final CCJSqlParserManager parserRealSql = new CCJSqlParserManager(); + final Statement statement = parserRealSql.parse(new StringReader(query.getQuery())); + log.trace("given query {}", query.getQuery()); + + if (statement instanceof net.sf.jsqlparser.statement.select.Select) { + final net.sf.jsqlparser.statement.select.Select selectStatement = (Select) statement; + final PlainSelect select = (PlainSelect) selectStatement.getSelectBody(); + final List<SelectItem> selectItems = select.getSelectItems(); + + /* parse all tables */ + final List<FromItem> items = new ArrayList<>() {{ + add(select.getFromItem()); + }}; + if (select.getJoins() != null && select.getJoins().size() > 0) { + for (Join j : select.getJoins()) { + if (j.getRightItem() != null) { + items.add(j.getRightItem()); + } + } + } + //Checking if all tables exist + List<TableColumn> allColumns = new ArrayList<>(); + for (FromItem item : items) { + boolean error = false; + log.debug("from item iterated through: {}", item); + for (Table t : database.getTables()) { + if (item.toString().equals(t.getInternalName()) || item.toString().equals(t.getName())) { + allColumns.addAll(t.getColumns()); + error = false; + break; + } + error = true; + } + if (error) { + log.error("Table {} does not exist in remote database", item.toString()); + throw new JSQLParserException("Table does not exist in remote database"); + } + } + + //Checking if all columns exist + for (SelectItem s : selectItems) { + String manualSelect = s.toString(); + if (manualSelect.trim().equals("*")) { + log.warn("Please do not use * ('star select') to query data"); + continue; + } + // ignore prefixes + if (manualSelect.contains(".")) { + log.debug("manual select {}", manualSelect); + manualSelect = manualSelect.split("\\.")[1]; + } + boolean i = false; + for (TableColumn tc : allColumns) { + log.trace("table column {}, {}, {}", tc.getInternalName(), tc.getName(), s); + if (manualSelect.equals(tc.getInternalName()) || manualSelect.toString().equals(tc.getName())) { + i = false; + break; + } + i = true; + } + if (i) { + log.error("Column {} does not exist", s); + throw new JSQLParserException("Column does not exist"); + } + } + //TODO Future work + if (select.getWhere() != null) { + Expression where = select.getWhere(); + log.debug("where clause: {}", where); + } + return query; + } else { + log.error("Provided query is not a select statement, currently we only support 'select' statements"); + throw new QueryMalformedException("Provided query is not a select statement"); + } + + } + + @Transactional + public QueryResultDto save(Long databaseId, Long tableId, ExecuteQueryDto data) throws ImageNotSupportedException, + DatabaseNotFoundException, QueryStoreException, DatabaseConnectionException, + QueryMalformedException { + final Database database = findDatabase(databaseId); + if (database.getContainer().getImage().getDialect().equals("MARIADB")) { + if (!exists(database)) { + create(databaseId); + } + } + final QueryDto query = queryMapper.executeQueryDtoToQueryDto(data); + final DSLContext context; + try { + context = open(database); + } catch (SQLException e) { + throw new QueryMalformedException("Could not connect to the remote container database", e); + } + final QueryResultDto queryResultDto = executeQueryOnContext(context, query, database); + log.trace("Result of the query is: \n {}", queryResultDto.getResult()); + + /* save some metadata */ + final Query metaQuery = queryMapper.queryDtotoQuery(query); + metaQuery.setExecutionTimestamp(null); + metaQuery.setTitle(data.getTitle()); + metaQuery.setQdbid(databaseId); + final Query res = queryRepository.save(metaQuery); + log.info("Saved query in metadata database id {}", res.getId()); + + // Save the query in the store + final QueryDto out = saveQuery(database, query, queryResultDto); + queryResultDto.setId(out.getId()); + log.info("Saved query in query store {}", out.getId()); + log.debug("Save query {}", out); +// return queryStoreService.findLast(database.getId(), query); // FIXME mw: why query last entry when we set it in the line above? + return queryResultDto; + } + + /** + * Re-executes a query with given id in a database by given id, returns a result of size and offset + * + * @param databaseId The database id + * @param queryId The query id + * @param page The offset + * @param size The size + * @return The result set + * @throws DatabaseNotFoundException The database was not found in the metadata database + * @throws ImageNotSupportedException The image is not supported + * @throws DatabaseConnectionException The remote container is not available right now + * @throws QueryStoreException There was an error with the query store in the remote container + */ + public QueryResultDto reexecute(Long databaseId, Long queryId, Integer page, Integer size) + throws DatabaseNotFoundException, ImageNotSupportedException, + QueryStoreException, QueryMalformedException, DatabaseConnectionException { + log.info("re-execute query with the id {}", queryId); + final DSLContext context; + try { + context = open(findDatabase(databaseId)); + } catch (SQLException e) { + throw new QueryStoreException("Could not establish connection to query store", e); + } + final QueryDto savedQuery = findOne(databaseId, queryId); + final StringBuilder query = new StringBuilder(); + query.append("SELECT * FROM ("); + final String q = savedQuery.getQuery(); + if (q.toLowerCase(Locale.ROOT).contains("where")) { + String[] split = q.toLowerCase(Locale.ROOT).split("where"); + if (split.length > 2) { + //TODO FIX SUBQUERIES WITH MULTIPLE Wheres + throw new QueryMalformedException("Query Contains Subqueries, this will be supported in a future version"); + } else { + query.append(split[0]) + .append(" FOR SYSTEM_TIME AS OF TIMESTAMP'") + .append(Timestamp.valueOf(savedQuery.getExecutionTimestamp().toString())) + .append("' WHERE") + .append(split[1]) + .append(") as tab"); + } + } else { + query.append(q) + .append(" FOR SYSTEM_TIME AS OF TIMESTAMP'") + .append(Timestamp.valueOf(savedQuery.getExecutionTimestamp().toString())) + .append("') as tab"); + } + + if (page != null && size != null) { + page = Math.abs(page); + size = Math.abs(size); + query.append(" LIMIT ") + .append(size) + .append(" OFFSET ") + .append(page * size); + } + query.append(";"); + final Result<org.jooq.Record> result = context.resultQuery(query.toString()) + .fetch(); + log.debug("query string {}", query.toString()); + log.trace("query result \n {}", result.toString()); + return queryMapper.recordListToQueryResultDto(result, queryId); + } + + /** + * Find a database in the metadata database by id + * + * @param id The id + * @return The database + * @throws DatabaseNotFoundException The database is not found + */ + @Transactional + protected Database findDatabase(Long id) throws DatabaseNotFoundException { final Optional<Database> database = databaseRepository.findById(id); if (database.isEmpty()) { - log.error("no database with this id found in metadata database"); - throw new DatabaseNotFoundException("database not found in metadata database"); + log.error("Database with id {} not found in metadata database", id); + throw new DatabaseNotFoundException("Database not found in metadata database"); } return database.get(); } - public boolean exists(Database database) throws SQLException, ImageNotSupportedException { - final DSLContext context = open(database); + /** + * Checks if a database exists in a remote container + * + * @param database The database + * @return True if exists, false otherwise + * @throws ImageNotSupportedException The image is not supported + * @throws DatabaseConnectionException The remote container is not reachable + */ + protected boolean exists(Database database) throws ImageNotSupportedException, DatabaseConnectionException { + final DSLContext context; + try { + context = open(database); + } catch (SQLException e) { + log.error("Could not connect to remote container: {}", e.getMessage()); + throw new DatabaseConnectionException("Could not connect to remote container", e); + } return context.select(count()) .from("information_schema.tables") .where("table_name like '" + QUERYSTORENAME + "'") .fetchOne(0, int.class) == 1; } + /** + * Execute query on a remote database context with database metadata to retrieve result + * mw: did some refactoring for duplicate code + * + * @param context The context + * @param query The query + * @param database The database metadata + * @return The result + * @throws QueryMalformedException The query mapping is wrong + */ + protected QueryResultDto executeQueryOnContext(DSLContext context, QueryDto query, Database database) + throws QueryMalformedException { + final StringBuilder parsedQuery = new StringBuilder(); + final String q; + try { + q = parse(query, database).getQuery(); + if (q.charAt(q.length() - 1) == ';') { + parsedQuery.append(q.substring(0, q.length() - 2)); + } else { + parsedQuery.append(q); + } + parsedQuery.append(";"); + } catch (JSQLParserException e) { + log.error("The manual mapped query is malformed: {}", e.getMessage()); + throw new QueryMalformedException("The manual mapped query is malformed", e); + } + final List<org.jooq.Record> result = context.resultQuery(parsedQuery.toString()) + .fetch(); + return queryMapper.recordListToQueryResultDto(result, query.getId()); + } + } diff --git a/fda-query-service/services/src/test/resources/application.properties b/fda-query-service/services/src/test/resources/application.properties index 2871cae9642987896d091460c42d1f27f857c25c..69df4a312304990e2f284318cd5428d960f14f0b 100644 --- a/fda-query-service/services/src/test/resources/application.properties +++ b/fda-query-service/services/src/test/resources/application.properties @@ -10,4 +10,5 @@ spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect \ No newline at end of file +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.jpa.hibernate.ddl-auto=update \ No newline at end of file diff --git a/fda-table-service/.dockerignore b/fda-table-service/.dockerignore index 36998121983d45bf75bdcdeded0116019f0b6f82..fcdfe8de55e91b3b65fcf598c5980ae256087910 100644 --- a/fda-table-service/.dockerignore +++ b/fda-table-service/.dockerignore @@ -1 +1 @@ -**/*.csv \ No newline at end of file +rest-service/src/main/resources/*.csv \ No newline at end of file diff --git a/fda-table-service/.gitignore b/fda-table-service/.gitignore index 648659eaf4f4567251f8be20833a11e6f43e8c31..8e5c311b11047e6a821fed6e279bf28c129ca3bd 100644 --- a/fda-table-service/.gitignore +++ b/fda-table-service/.gitignore @@ -10,7 +10,6 @@ target/ ### Generated ### ready mapping.xml -rest-service/src/main/java/at/tuwien/userdb/Table.java ### STS ### .apt_generated diff --git a/fda-table-service/Dockerfile b/fda-table-service/Dockerfile index ecc73ca56b437c48a254cfc7f9eb78118beb0216..37f0c347670855b08e1b50ba8149e3f887709b8e 100644 --- a/fda-table-service/Dockerfile +++ b/fda-table-service/Dockerfile @@ -14,9 +14,11 @@ COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tu COPY ./rest-service ./rest-service COPY ./services ./services COPY ./report ./report -COPY ./api ./api -RUN mvn -q clean package -DskipTests +ARG CI_JOB_STAGE + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null ###### THIRD STAGE ###### FROM openjdk:11-jre-slim as runtime @@ -24,7 +26,7 @@ FROM openjdk:11-jre-slim as runtime COPY ./service_ready /usr/bin RUN chmod +x /usr/bin/service_ready -HEALTHCHECK --interval=25s --timeout=3s --retries=2 CMD service_ready +HEALTHCHECK --interval=10s --timeout=3s --retries=6 CMD service_ready COPY --from=build ./rest-service/target/rest-service-*.jar ./rest.jar diff --git a/fda-table-service/api/pom.xml b/fda-table-service/api/pom.xml deleted file mode 100644 index a89f234fde1cbe809ace2bdfcf892f319c27f3d5..0000000000000000000000000000000000000000 --- a/fda-table-service/api/pom.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <artifactId>fda-table-service</artifactId> - <groupId>at.tuwien</groupId> - <version>0.0.1-SNAPSHOT</version> - </parent> - <modelVersion>4.0.0</modelVersion> - - <artifactId>api</artifactId> - -</project> \ No newline at end of file diff --git a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/MetadataDto.java b/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/MetadataDto.java deleted file mode 100644 index 979405e8c4027b6bf724cba88128477a794ef335..0000000000000000000000000000000000000000 --- a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/MetadataDto.java +++ /dev/null @@ -1,16 +0,0 @@ -package at.tuwien.api.zenodo; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class MetadataDto { - - @JsonProperty("prereserve_doi") - private PreserveDoiDto prereserveDoi; - -} diff --git a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/PreserveDoiDto.java b/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/PreserveDoiDto.java deleted file mode 100644 index 674930f36ac42f5f8adbeb5da1c67f05b494bec5..0000000000000000000000000000000000000000 --- a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/PreserveDoiDto.java +++ /dev/null @@ -1,18 +0,0 @@ -package at.tuwien.api.zenodo; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class PreserveDoiDto { - - private String doi; - - @JsonProperty("recid") - private Long recId; - -} diff --git a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositDto.java b/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositDto.java deleted file mode 100644 index 3499a829c27a389d3f0519132775e9717e4e050c..0000000000000000000000000000000000000000 --- a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/deposit/DepositDto.java +++ /dev/null @@ -1,42 +0,0 @@ -package at.tuwien.api.zenodo.deposit; - -import at.tuwien.api.zenodo.MetadataDto; -import at.tuwien.api.zenodo.files.FileDto; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; - -import java.time.Instant; -import java.util.List; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class DepositDto { - - @JsonProperty("conceptrecid") - private Long conceptRecId; - - private Instant created; - - private List<FileDto> files; - - private Long id; - - private Instant modified; - - private Long owner; - - private MetadataDto metadata; - - @JsonProperty("record_id") - private Long recordId; - - private String state; - - private Boolean submitted; - - private String title; - -} diff --git a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/files/FileDto.java b/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/files/FileDto.java deleted file mode 100644 index 054146a746a4f723dacb26f3be31243a07faa63d..0000000000000000000000000000000000000000 --- a/fda-table-service/api/src/main/java/at/tuwien/api/zenodo/files/FileDto.java +++ /dev/null @@ -1,22 +0,0 @@ -package at.tuwien.api.zenodo.files; - -import lombok.*; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class FileDto { - - private String checksum; - - private String filename; - - private Long filesize; - - private String id; - - private FileLinksDto links; - -} diff --git a/fda-table-service/pom.xml b/fda-table-service/pom.xml index 2dae8bf5a72ff8cb77b71ef48e92af0c99151282..03a31fdfbf3528023564ddb70f6127fbaffb94e9 100644 --- a/fda-table-service/pom.xml +++ b/fda-table-service/pom.xml @@ -19,7 +19,6 @@ <module>rest-service</module> <module>services</module> <module>report</module> - <module>api</module> </modules> <properties> diff --git a/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/DataEndpoint.java b/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/DataEndpoint.java index d0fa6ea495f30db036e414201052b99c598e5165..c35089b58d90615d10f4c4a2cd95fa0711e50dc2 100644 --- a/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/DataEndpoint.java +++ b/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/DataEndpoint.java @@ -43,7 +43,7 @@ public class DataEndpoint { @ApiResponse(code = 422, message = "The csv was not processible."), }) public ResponseEntity<?> insertFromFile(@PathVariable("id") Long databaseId, - @PathVariable("tableId") Long tableId, + @PathVariable Long tableId, @Valid @RequestBody TableInsertDto data) throws TableNotFoundException, TableMalformedException, DatabaseNotFoundException, ImageNotSupportedException, FileStorageException { dataService.insertCsv(databaseId, tableId, data); @@ -63,7 +63,7 @@ public class DataEndpoint { @ApiResponse(code = 422, message = "The csv was not processible."), }) public ResponseEntity<?> insertFromTuple(@PathVariable("id") Long databaseId, - @PathVariable("tableId") Long tableId, + @PathVariable Long tableId, @Valid @RequestBody TableCsvDto data) throws ImageNotSupportedException, TableMalformedException, TableNotFoundException, DatabaseNotFoundException { final Table table = dataService.findById(databaseId, tableId); @@ -82,10 +82,10 @@ public class DataEndpoint { @ApiResponse(code = 405, message = "The connection to the database was unsuccessful."), }) public ResponseEntity<QueryResultDto> getAll(@PathVariable("id") Long databaseId, - @PathVariable("tableId") Long tableId, + @PathVariable Long tableId, @RequestParam(required = false) Instant timestamp, - @RequestParam(name = "page", required = false) Long page, - @RequestParam(name = "size", required = false) Long size) + @RequestParam(required = false) Long page, + @RequestParam(required = false) Long size) throws TableNotFoundException, DatabaseNotFoundException, DatabaseConnectionException, ImageNotSupportedException, TableMalformedException { final QueryResultDto data = dataService.selectAll(databaseId, tableId, timestamp, page, size); diff --git a/fda-table-service/rest-service/src/main/resources/mariadb/reserved.csv b/fda-table-service/rest-service/src/main/resources/mariadb/reserved.csv new file mode 100644 index 0000000000000000000000000000000000000000..1aace34a415929fe8c427f0656e1e8566f288cfd --- /dev/null +++ b/fda-table-service/rest-service/src/main/resources/mariadb/reserved.csv @@ -0,0 +1,586 @@ +ACCESSIBLE +ACTION +ADD +AFTER +AGAINST +AGGREGATE +ALL +ALGORITHM +ALTER +ALWAYS +ANALYZE +AND +ANY +AS +ASC +ASCII +ASENSITIVE +AT +AUTHORS +AUTO_INCREMENT +AUTOEXTEND_SIZE +AVG +AVG_ROW_LENGTH +BACKUP +BEFORE +BEGIN +BETWEEN +BIGINT +BINARY +BINLOG +BIT +BLOB +BLOCK +BOOL +BOOLEAN +BOTH +BTREE +BY +BYTE +CACHE +CALL +CASCADE +CASCADED +CASE +CATALOG_NAME +CHAIN +CHANGE +CHANGED +CHAR +CHARACTER +CHARSET +CHECK +CHECKPOINT +CHECKSUM +CIPHER +CLASS_ORIGIN +CLIENT +CLIENT_STATISTICS +CLOSE +COALESCE +CODE +COLLATE +COLLATION +COLUMN +COLUMN_NAME +COLUMNS +COLUMN_ADD +COLUMN_CREATE +COLUMN_DELETE +COLUMN_EXISTS +COLUMN_GET +COLUMN_LIST +COMMENT +COMMIT +COMMITTED +COMPACT +COMPLETION +COMPRESSED +CONCURRENT +CONDITION +CONNECTION +CONSISTENT +CONSTRAINT +CONSTRAINT_CATALOG +CONSTRAINT_NAME +CONSTRAINT_SCHEMA +CONTAINS +CONTEXT +CONTINUE +CONTRIBUTORS +CONVERT +CPU +CREATE +CROSS +CUBE +CURRENT_DATE +CURRENT_TIME +CURRENT_TIMESTAMP +CURRENT_USER +CURSOR +CURSOR_NAME +DATA +DATABASE +DATABASES +DATAFILE +DATE +DATETIME +DAY +DAY_HOUR +DAY_MICROSECOND +DAY_MINUTE +DAY_SECOND +DEALLOCATE +DEC +DECIMAL +DECLARE +DEFAULT +DEFINER +DELAYED +DELAY_KEY_WRITE +DELETE +DESC +DESCRIBE +DES_KEY_FILE +DETERMINISTIC +DIRECTORY +DISABLE +DISCARD +DISK +DISTINCT +DISTINCTROW +DIV +DO +DOUBLE +DROP +DUAL +DUMPFILE +DUPLICATE +DYNAMIC +EACH +ELSE +ELSEIF +ENABLE +ENCLOSED +END +ENDS +ENGINE +ENGINES +ENUM +ERROR +ERRORS +ESCAPE +ESCAPED +EVENT +EVENTS +EVERY +EXAMINED +EXECUTE +EXISTS +EXIT +EXPANSION +EXPLAIN +EXTENDED +EXTENT_SIZE +FALSE +FAST +FAULTS +FETCH +FIELDS +FILE +FIRST +FIXED +FLOAT +FLOAT4 +FLOAT8 +FLUSH +FOR +FORCE +FOREIGN +FOUND +FROM +FULL +FULLTEXT +FUNCTION +GENERAL +GENERATED +GEOMETRY +GEOMETRYCOLLECTION +GET_FORMAT +GLOBAL +GRANT +GRANTS +GROUP +HANDLER +HARD +HASH +HAVING +HELP +HIGH_PRIORITY +HOST +HOSTS +HOUR +HOUR_MICROSECOND +HOUR_MINUTE +HOUR_SECOND +IDENTIFIED +IF +IGNORE +IGNORE_SERVER_IDS +IMPORT +IN +INDEX +INDEXES +INDEX_STATISTICS +INFILE +INITIAL_SIZE +INNER +INOUT +INSENSITIVE +INSERT +INSERT_METHOD +INSTALL +INT +INT1 +INT2 +INT3 +INT4 +INT8 +INTEGER +INTERVAL +INTO +IO +IO_THREAD +IPC +IS +ISOLATION +ISSUER +ITERATE +INVOKER +JOIN +KEY +KEYS +KEY_BLOCK_SIZE +KILL +LANGUAGE +LAST +LAST_VALUE +LEADING +LEAVE +LEAVES +LEFT +LESS +LEVEL +LIKE +LIMIT +LINEAR +LINES +LINESTRING +LIST +LOAD +LOCAL +LOCALTIME +LOCALTIMESTAMP +LOCK +LOCKS +LOGFILE +LOGS +LONG +LONGBLOB +LONGTEXT +LOOP +LOW_PRIORITY +MASTER +MASTER_CONNECT_RETRY +MASTER_HOST +MASTER_LOG_FILE +MASTER_LOG_POS +MASTER_PASSWORD +MASTER_PORT +MASTER_SERVER_ID +MASTER_SSL +MASTER_SSL_CA +MASTER_SSL_CAPATH +MASTER_SSL_CERT +MASTER_SSL_CIPHER +MASTER_SSL_KEY +MASTER_SSL_VERIFY_SERVER_CERT +MASTER_USER +MASTER_HEARTBEAT_PERIOD +MATCH +MAX_CONNECTIONS_PER_HOUR +MAX_QUERIES_PER_HOUR +MAX_ROWS +MAX_SIZE +MAX_UPDATES_PER_HOUR +MAX_USER_CONNECTIONS +MAXVALUE +MEDIUM +MEDIUMBLOB +MEDIUMINT +MEDIUMTEXT +MEMORY +MERGE +MESSAGE_TEXT +MICROSECOND +MIDDLEINT +MIGRATE +MINUTE +MINUTE_MICROSECOND +MINUTE_SECOND +MIN_ROWS +MOD +MODE +MODIFIES +MODIFY +MONTH +MULTILINESTRING +MULTIPOINT +MULTIPOLYGON +MUTEX +MYSQL_ERRNO +NAME +NAMES +NATIONAL +NATURAL +NDB +NDBCLUSTER +NCHAR +NEW +NEXT +NO +NO_WAIT +NODEGROUP +NONE +NOT +NO_WRITE_TO_BINLOG +NULL +NUMERIC +NVARCHAR +OFFSET +OLD_PASSWORD +ON +ONE +ONE_SHOT +ONLINE +OPEN +OPTIMIZE +OPTIONS +OPTION +OPTIONALLY +OR +ORDER +OUT +OUTER +OUTFILE +OWNER +PACK_KEYS +PAGE +PAGE_CHECKSUM +PARSER +PARSE_VCOL_EXPR +PARTIAL +PARTITION +PARTITIONING +PARTITIONS +PASSWORD +PERSISTENT +PHASE +PLUGIN +PLUGINS +POINT +POLYGON +PORT +PRECISION +PREPARE +PRESERVE +PREV +PRIMARY +PRIVILEGES +PROCEDURE +PROCESS +PROCESSLIST +PROFILE +PROFILES +PROXY +PURGE +QUARTER +QUERY +QUICK +RANGE +READ +READ_ONLY +READ_WRITE +READS +REAL +REBUILD +RECOVER +REDO_BUFFER_SIZE +REDOFILE +REDUNDANT +REFERENCES +REGEXP +RELAY +RELAYLOG +RELAY_LOG_FILE +RELAY_LOG_POS +RELAY_THREAD +RELEASE +RELOAD +REMOVE +RENAME +REORGANIZE +REPAIR +REPEATABLE +REPLACE +REPLICATION +REPEAT +REQUIRE +RESET +RESIGNAL +RESTORE +RESTRICT +RESUME +RETURN +RETURNS +REVOKE +RIGHT +RLIKE +ROLLBACK +ROLLUP +ROUTINE +ROW +ROWS +ROW_FORMAT +RTREE +SAVEPOINT +SCHEDULE +SCHEMA +SCHEMA_NAME +SCHEMAS +SECOND +SECOND_MICROSECOND +SECURITY +SELECT +SENSITIVE +SEPARATOR +SERIAL +SERIALIZABLE +SESSION +SERVER +SET +SHARE +SHOW +SHUTDOWN +SIGNAL +SIGNED +SIMPLE +SLAVE +SLOW +SNAPSHOT +SMALLINT +SOCKET +SOFT +SOME +SONAME +SOUNDS +SOURCE +SPATIAL +SPECIFIC +SQL +SQLEXCEPTION +SQLSTATE +SQLWARNING +SQL_BIG_RESULT +SQL_BUFFER_RESULT +SQL_CACHE +SQL_CALC_FOUND_ROWS +SQL_NO_CACHE +SQL_SMALL_RESULT +SQL_THREAD +SQL_TSI_SECOND +SQL_TSI_MINUTE +SQL_TSI_HOUR +SQL_TSI_DAY +SQL_TSI_WEEK +SQL_TSI_MONTH +SQL_TSI_QUARTER +SQL_TSI_YEAR +SSL +START +STARTING +STARTS +STATUS +STOP +STORAGE +STRAIGHT_JOIN +STRING +SUBCLASS_ORIGIN +SUBJECT +SUBPARTITION +SUBPARTITIONS +SUPER +SUSPEND +SWAPS +SWITCHES +TABLE +TABLE_NAME +TABLES +TABLESPACE +TABLE_STATISTICS +TABLE_CHECKSUM +TEMPORARY +TEMPTABLE +TERMINATED +TEXT +THAN +THEN +TIME +TIMESTAMP +TIMESTAMPADD +TIMESTAMPDIFF +TINYBLOB +TINYINT +TINYTEXT +TO +TRAILING +TRANSACTION +TRANSACTIONAL +TRIGGER +TRIGGERS +TRUE +TRUNCATE +TYPE +TYPES +UNCOMMITTED +UNDEFINED +UNDO_BUFFER_SIZE +UNDOFILE +UNDO +UNICODE +UNION +UNIQUE +UNKNOWN +UNLOCK +UNINSTALL +UNSIGNED +UNTIL +UPDATE +UPGRADE +USAGE +USE +USER +USER_RESOURCES +USER_STATISTICS +USE_FRM +USING +UTC_DATE +UTC_TIME +UTC_TIMESTAMP +VALUE +VALUES +VARBINARY +VARCHAR +VARCHARACTER +VARIABLES +VARYING +VIA +VIEW +VIRTUAL +WAIT +WARNINGS +WEEK +WHEN +WHERE +WHILE +WITH +WORK +WRAPPER +WRITE +X509 +XOR +XA +XML +YEAR +YEAR_MONTH +ZEROFILL \ No newline at end of file diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index 13664eea12763ea46f318fd19abeac50081d3cc9..d342dfbfc03fb059d6939ebe2ce95001ef4150d4 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -33,6 +33,11 @@ public abstract class BaseUnitTest extends CsvUnitTest { public final static String DATABASE_2_INTERNALNAME = "weather"; public final static String DATABASE_2_EXCHANGE = "fda." + DATABASE_2_INTERNALNAME; + public final static Long DATABASE_3_ID = 3L; + public final static String DATABASE_3_NAME = "Biomedical"; + public final static String DATABASE_3_INTERNALNAME = "biomedical"; + public final static String DATABASE_3_EXCHANGE = "fda." + DATABASE_3_INTERNALNAME; + public final static Long TABLE_1_ID = 1L; public final static String TABLE_1_NAME = "Weather AUS"; public final static String TABLE_1_INTERNALNAME = "weather_aus"; @@ -45,74 +50,119 @@ public abstract class BaseUnitTest extends CsvUnitTest { public final static String TABLE_2_DESCRIPTION = "Weather in the world"; public final static String TABLE_2_TOPIC = DATABASE_2_EXCHANGE + "." + TABLE_2_INTERNALNAME; - public final static Long COLUMN_1_ID = 1L; - public final static Integer COLUMN_1_ORDINALPOS = 0; - public final static Boolean COLUMN_1_PRIMARY = true; - public final static String COLUMN_1_NAME = "id"; - public final static String COLUMN_1_INTERNAL_NAME = "mdb_id"; - public final static TableColumnType COLUMN_1_TYPE = TableColumnType.NUMBER; - public final static ColumnTypeDto COLUMN_1_TYPE_DTO = ColumnTypeDto.NUMBER; - public final static Boolean COLUMN_1_NULL = false; - public final static Boolean COLUMN_1_UNIQUE = true; - public final static String COLUMN_1_FOREIGN_KEY = null; - public final static String COLUMN_1_CHECK = null; - public final static List<String> COLUMN_1_ENUM_VALUES = null; - - public final static Long COLUMN_2_ID = 2L; - public final static Integer COLUMN_2_ORDINALPOS = 1; - public final static Boolean COLUMN_2_PRIMARY = false; - public final static String COLUMN_2_NAME = "Date"; - public final static String COLUMN_2_INTERNAL_NAME = "mdb_date"; - public final static TableColumnType COLUMN_2_TYPE = TableColumnType.DATE; - public final static ColumnTypeDto COLUMN_2_TYPE_DTO = ColumnTypeDto.DATE; - public final static Boolean COLUMN_2_NULL = true; - public final static Boolean COLUMN_2_UNIQUE = false; - public final static String COLUMN_2_FOREIGN_KEY = null; - public final static String COLUMN_2_CHECK = null; - public final static List<String> COLUMN_2_ENUM_VALUES = null; - - public final static Long COLUMN_3_ID = 3L; - public final static Integer COLUMN_3_ORDINALPOS = 2; - public final static Boolean COLUMN_3_PRIMARY = false; - public final static String COLUMN_3_NAME = "MinTemp"; - public final static String COLUMN_3_INTERNAL_NAME = "mdb_mintemp"; - public final static TableColumnType COLUMN_3_TYPE = TableColumnType.NUMBER; - public final static ColumnTypeDto COLUMN_3_TYPE_DTO = ColumnTypeDto.NUMBER; - public final static Boolean COLUMN_3_NULL = true; - public final static Boolean COLUMN_3_UNIQUE = false; - public final static String COLUMN_3_FOREIGN_KEY = null; - public final static String COLUMN_3_CHECK = null; - public final static List<String> COLUMN_3_ENUM_VALUES = null; - - public final static Long COLUMN_4_ID = 4L; - public final static Integer COLUMN_4_ORDINALPOS = 3; - public final static Boolean COLUMN_4_PRIMARY = false; - public final static String COLUMN_4_NAME = "Location"; - public final static String COLUMN_4_INTERNAL_NAME = "mdb_location"; - public final static TableColumnType COLUMN_4_TYPE = TableColumnType.STRING; - public final static ColumnTypeDto COLUMN_4_TYPE_DTO = ColumnTypeDto.STRING; - public final static Boolean COLUMN_4_NULL = true; - public final static Boolean COLUMN_4_UNIQUE = false; - public final static String COLUMN_4_FOREIGN_KEY = null; - public final static String COLUMN_4_CHECK = null; - public final static List<String> COLUMN_4_ENUM_VALUES = null; - - public final static Long COLUMN_5_ID = 5L; - public final static Integer COLUMN_5_ORDINALPOS = 4; - public final static Boolean COLUMN_5_PRIMARY = false; - public final static String COLUMN_5_NAME = "Rainfall"; - public final static String COLUMN_5_INTERNAL_NAME = "mdb_rainfall"; - public final static TableColumnType COLUMN_5_TYPE = TableColumnType.NUMBER; - public final static ColumnTypeDto COLUMN_5_TYPE_DTO = ColumnTypeDto.NUMBER; - public final static Boolean COLUMN_5_NULL = true; - public final static Boolean COLUMN_5_UNIQUE = false; - public final static String COLUMN_5_FOREIGN_KEY = null; - public final static String COLUMN_5_CHECK = null; - public final static List<String> COLUMN_5_ENUM_VALUES = null; + public final static Long TABLE_3_ID = 3L; + public final static String TABLE_3_NAME = "MALDI MS Data"; + public final static String TABLE_3_INTERNALNAME = "maldi_ms_data"; + public final static String TABLE_3_DESCRIPTION = "See Ruffini-Ronzani et al. (https://doi.org/10.1098/rsos.210210)"; + public final static String TABLE_3_TOPIC = DATABASE_3_EXCHANGE + "." + TABLE_3_INTERNALNAME; + + public final static Long COLUMN_1_1_ID = 1L; + public final static Integer COLUMN_1_1_ORDINALPOS = 0; + public final static Boolean COLUMN_1_1_PRIMARY = true; + public final static String COLUMN_1_1_NAME = "id"; + public final static String COLUMN_1_1_INTERNAL_NAME = "mdb_id"; + public final static TableColumnType COLUMN_1_1_TYPE = TableColumnType.NUMBER; + public final static ColumnTypeDto COLUMN_1_1_TYPE_DTO = ColumnTypeDto.NUMBER; + public final static Boolean COLUMN_1_1_NULL = false; + public final static Boolean COLUMN_1_1_UNIQUE = true; + public final static String COLUMN_1_1_FOREIGN_KEY = null; + public final static String COLUMN_1_1_CHECK = null; + public final static List<String> COLUMN_1_1_ENUM_VALUES = null; + + public final static Long COLUMN_1_2_ID = 2L; + public final static Integer COLUMN_1_2_ORDINALPOS = 1; + public final static Boolean COLUMN_1_2_PRIMARY = false; + public final static String COLUMN_1_2_NAME = "Date"; + public final static String COLUMN_1_2_INTERNAL_NAME = "mdb_date"; + public final static TableColumnType COLUMN_1_2_TYPE = TableColumnType.DATE; + public final static ColumnTypeDto COLUMN_1_2_TYPE_DTO = ColumnTypeDto.DATE; + public final static Boolean COLUMN_1_2_NULL = true; + public final static Boolean COLUMN_1_2_UNIQUE = false; + public final static String COLUMN_1_2_FOREIGN_KEY = null; + public final static String COLUMN_1_2_CHECK = null; + public final static List<String> COLUMN_1_2_ENUM_VALUES = null; + + public final static Long COLUMN_1_3_ID = 3L; + public final static Integer COLUMN_1_3_ORDINALPOS = 2; + public final static Boolean COLUMN_1_3_PRIMARY = false; + public final static String COLUMN_1_3_NAME = "Location"; + public final static String COLUMN_1_3_INTERNAL_NAME = "mdb_location"; + public final static TableColumnType COLUMN_1_3_TYPE = TableColumnType.STRING; + public final static ColumnTypeDto COLUMN_1_3_TYPE_DTO = ColumnTypeDto.STRING; + public final static Boolean COLUMN_1_3_NULL = true; + public final static Boolean COLUMN_1_3_UNIQUE = false; + public final static String COLUMN_1_3_FOREIGN_KEY = null; + public final static String COLUMN_1_3_CHECK = null; + public final static List<String> COLUMN_1_3_ENUM_VALUES = null; + + public final static Long COLUMN_1_4_ID = 4L; + public final static Integer COLUMN_1_4_ORDINALPOS = 3; + public final static Boolean COLUMN_1_4_PRIMARY = false; + public final static String COLUMN_1_4_NAME = "MinTemp"; + public final static String COLUMN_1_4_INTERNAL_NAME = "mdb_mintemp"; + public final static TableColumnType COLUMN_1_4_TYPE = TableColumnType.STRING; + public final static ColumnTypeDto COLUMN_1_4_TYPE_DTO = ColumnTypeDto.STRING; + public final static Boolean COLUMN_1_4_NULL = true; + public final static Boolean COLUMN_1_4_UNIQUE = false; + public final static String COLUMN_1_4_FOREIGN_KEY = null; + public final static String COLUMN_1_4_CHECK = null; + public final static List<String> COLUMN_1_4_ENUM_VALUES = null; + + public final static Long COLUMN_1_5_ID = 5L; + public final static Integer COLUMN_1_5_ORDINALPOS = 4; + public final static Boolean COLUMN_1_5_PRIMARY = false; + public final static String COLUMN_1_5_NAME = "Rainfall"; + public final static String COLUMN_1_5_INTERNAL_NAME = "mdb_rainfall"; + public final static TableColumnType COLUMN_1_5_TYPE = TableColumnType.NUMBER; + public final static ColumnTypeDto COLUMN_1_5_TYPE_DTO = ColumnTypeDto.NUMBER; + public final static Boolean COLUMN_1_5_NULL = true; + public final static Boolean COLUMN_1_5_UNIQUE = false; + public final static String COLUMN_1_5_FOREIGN_KEY = null; + public final static String COLUMN_1_5_CHECK = null; + public final static List<String> COLUMN_1_5_ENUM_VALUES = null; + + public final static Long COLUMN_3_1_ID = 1L; + public final static Integer COLUMN_3_1_ORDINALPOS = 0; + public final static Boolean COLUMN_3_1_PRIMARY = false; + public final static String COLUMN_3_1_NAME = "qu"; + public final static String COLUMN_3_1_INTERNAL_NAME = "mdb_qu"; + public final static TableColumnType COLUMN_3_1_TYPE = TableColumnType.STRING; + public final static ColumnTypeDto COLUMN_3_1_TYPE_DTO = ColumnTypeDto.STRING; + public final static Boolean COLUMN_3_1_NULL = false; + public final static Boolean COLUMN_3_1_UNIQUE = false; + public final static String COLUMN_3_1_FOREIGN_KEY = null; + public final static String COLUMN_3_1_CHECK = null; + public final static List<String> COLUMN_3_1_ENUM_VALUES = null; + + public final static Long COLUMN_3_2_ID = 2L; + public final static Integer COLUMN_3_2_ORDINALPOS = 1; + public final static Boolean COLUMN_3_2_PRIMARY = false; + public final static String COLUMN_3_2_NAME = "species"; + public final static String COLUMN_3_2_INTERNAL_NAME = "mdb_species"; + public final static TableColumnType COLUMN_3_2_TYPE = TableColumnType.ENUM; + public final static ColumnTypeDto COLUMN_3_2_TYPE_DTO = ColumnTypeDto.ENUM; + public final static Boolean COLUMN_3_2_NULL = false; + public final static Boolean COLUMN_3_2_UNIQUE = false; + public final static String COLUMN_3_2_FOREIGN_KEY = null; + public final static String COLUMN_3_2_CHECK = null; + public final static List<String> COLUMN_3_2_ENUM_VALUES = List.of("sheep", "calf", "undetermined", "sheep or goat", "goat", "not anal."); + + public final static Long COLUMN_3_3_ID = 3L; + public final static Integer COLUMN_3_3_ORDINALPOS = 2; + public final static Boolean COLUMN_3_3_PRIMARY = false; + public final static String COLUMN_3_3_NAME = "score"; + public final static String COLUMN_3_3_INTERNAL_NAME = "mdb_score"; + public final static TableColumnType COLUMN_3_3_TYPE = TableColumnType.STRING; + public final static ColumnTypeDto COLUMN_3_3_TYPE_DTO = ColumnTypeDto.STRING; + public final static Boolean COLUMN_3_3_NULL = false; + public final static Boolean COLUMN_3_3_UNIQUE = false; + public final static String COLUMN_3_3_FOREIGN_KEY = null; + public final static String COLUMN_3_3_CHECK = null; + public final static List<String> COLUMN_3_3_ENUM_VALUES = null; public final static Long IMAGE_1_ID = 1L; public final static String IMAGE_1_REPOSITORY = "postgres"; - public final static String IMAGE_1_TAG = "13-alpine"; + public final static String IMAGE_1_TAG = "13.4-alpine"; public final static String IMAGE_1_HASH = "83b40f2726e5"; public final static String IMAGE_1_DIALECT = "POSTGRES"; public final static String IMAGE_1_DRIVER = "org.postgresql.Driver"; @@ -124,7 +174,7 @@ public abstract class BaseUnitTest extends CsvUnitTest { public final static Long IMAGE_2_ID = 2L; public final static String IMAGE_2_REPOSITORY = "mariadb"; - public final static String IMAGE_2_TAG = "latest"; + public final static String IMAGE_2_TAG = "10.5"; public final static String IMAGE_2_HASH = "d6a5e003eae42397f7ee4589e9f21e231d3721ac131970d2286bd616e7f55bb4\n"; public final static String IMAGE_2_DIALECT = "MARIADB"; public final static String IMAGE_2_DRIVER = "org.mariadb.jdbc.Driver"; @@ -203,7 +253,7 @@ public abstract class BaseUnitTest extends CsvUnitTest { public final static Long CONTAINER_1_ID = 1L; public final static String CONTAINER_1_HASH = "deadbeef"; - public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1; + public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_2; public final static String CONTAINER_1_NAME = "u01"; public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01"; public final static String CONTAINER_1_IP = "172.28.0.5"; @@ -217,6 +267,14 @@ public abstract class BaseUnitTest extends CsvUnitTest { public final static String CONTAINER_2_IP = "172.28.0.6"; public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS); + public final static Long CONTAINER_3_ID = 3L; + public final static String CONTAINER_3_HASH = "deadbeef"; + public final static ContainerImage CONTAINER_3_IMAGE = IMAGE_2; + public final static String CONTAINER_3_NAME = "u03"; + public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03"; + public final static String CONTAINER_3_IP = "172.28.0.7"; + public final static Instant CONTAINER_3_CREATED = Instant.now().minus(1, HOURS); + public final static Container CONTAINER_1 = Container.builder() .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) @@ -235,70 +293,119 @@ public abstract class BaseUnitTest extends CsvUnitTest { .containerCreated(CONTAINER_2_CREATED) .build(); + public final static Container CONTAINER_3 = Container.builder() + .id(CONTAINER_3_ID) + .name(CONTAINER_3_NAME) + .internalName(CONTAINER_3_INTERNALNAME) + .image(CONTAINER_3_IMAGE) + .hash(CONTAINER_3_HASH) + .containerCreated(CONTAINER_3_CREATED) + .build(); + + public final static List<TableColumn> TABLE_3_COLUMNS = List.of(TableColumn.builder() + .id(COLUMN_3_1_ID) + .ordinalPosition(COLUMN_3_1_ORDINALPOS) + .cdbid(DATABASE_3_ID) + .tid(TABLE_3_ID) + .name(COLUMN_3_1_NAME) + .internalName(COLUMN_3_1_INTERNAL_NAME) + .columnType(COLUMN_3_1_TYPE) + .isNullAllowed(COLUMN_3_1_NULL) + .isUnique(COLUMN_3_1_UNIQUE) + .isPrimaryKey(COLUMN_3_1_PRIMARY) + .enumValues(COLUMN_3_1_ENUM_VALUES) + .build(), + TableColumn.builder() + .id(COLUMN_3_2_ID) + .ordinalPosition(COLUMN_3_2_ORDINALPOS) + .cdbid(DATABASE_3_ID) + .tid(TABLE_3_ID) + .name(COLUMN_3_2_NAME) + .internalName(COLUMN_3_2_INTERNAL_NAME) + .columnType(COLUMN_3_2_TYPE) + .isNullAllowed(COLUMN_3_2_NULL) + .isUnique(COLUMN_3_2_UNIQUE) + .isPrimaryKey(COLUMN_3_2_PRIMARY) + .enumValues(COLUMN_3_2_ENUM_VALUES) + .build(), + TableColumn.builder() + .id(COLUMN_3_3_ID) + .ordinalPosition(COLUMN_3_3_ORDINALPOS) + .cdbid(DATABASE_3_ID) + .tid(TABLE_3_ID) + .name(COLUMN_3_3_NAME) + .internalName(COLUMN_3_3_INTERNAL_NAME) + .columnType(COLUMN_3_3_TYPE) + .isNullAllowed(COLUMN_3_3_NULL) + .isUnique(COLUMN_3_3_UNIQUE) + .isPrimaryKey(COLUMN_3_3_PRIMARY) + .enumValues(COLUMN_3_3_ENUM_VALUES) + .build()); + public final static List<TableColumn> TABLE_1_COLUMNS = List.of(TableColumn.builder() - .id(COLUMN_1_ID) - .ordinalPosition(COLUMN_1_ORDINALPOS) + .id(COLUMN_1_1_ID) + .ordinalPosition(COLUMN_1_1_ORDINALPOS) .cdbid(DATABASE_1_ID) .tid(TABLE_1_ID) - .name(COLUMN_1_NAME) - .internalName(COLUMN_1_INTERNAL_NAME) - .columnType(COLUMN_1_TYPE) - .isNullAllowed(COLUMN_1_NULL) - .isUnique(COLUMN_1_UNIQUE) - .isPrimaryKey(COLUMN_1_PRIMARY) - .enumValues(COLUMN_1_ENUM_VALUES) + .name(COLUMN_1_1_NAME) + .internalName(COLUMN_1_1_INTERNAL_NAME) + .columnType(COLUMN_1_1_TYPE) + .isNullAllowed(COLUMN_1_1_NULL) + .isUnique(COLUMN_1_1_UNIQUE) + .isPrimaryKey(COLUMN_1_1_PRIMARY) + .enumValues(COLUMN_1_1_ENUM_VALUES) .build(), TableColumn.builder() - .id(COLUMN_2_ID) - .ordinalPosition(COLUMN_2_ORDINALPOS) + .id(COLUMN_1_2_ID) + .ordinalPosition(COLUMN_1_2_ORDINALPOS) .cdbid(DATABASE_1_ID) .tid(TABLE_1_ID) - .name(COLUMN_2_NAME) - .internalName(COLUMN_2_INTERNAL_NAME) - .columnType(COLUMN_2_TYPE) - .isNullAllowed(COLUMN_2_NULL) - .isUnique(COLUMN_2_UNIQUE) - .isPrimaryKey(COLUMN_2_PRIMARY) - .enumValues(COLUMN_2_ENUM_VALUES) + .name(COLUMN_1_2_NAME) + .internalName(COLUMN_1_2_INTERNAL_NAME) + .columnType(COLUMN_1_2_TYPE) + .isNullAllowed(COLUMN_1_2_NULL) + .isUnique(COLUMN_1_2_UNIQUE) + .isPrimaryKey(COLUMN_1_2_PRIMARY) + .enumValues(COLUMN_1_2_ENUM_VALUES) .build(), TableColumn.builder() - .id(COLUMN_3_ID) - .ordinalPosition(COLUMN_3_ORDINALPOS) + .id(COLUMN_1_3_ID) + .ordinalPosition(COLUMN_1_3_ORDINALPOS) .cdbid(DATABASE_1_ID) .tid(TABLE_1_ID) - .name(COLUMN_3_NAME) - .internalName(COLUMN_3_INTERNAL_NAME) - .columnType(COLUMN_3_TYPE) - .isNullAllowed(COLUMN_3_NULL) - .isUnique(COLUMN_3_UNIQUE) - .isPrimaryKey(COLUMN_3_PRIMARY) - .enumValues(COLUMN_3_ENUM_VALUES) + .name(COLUMN_1_3_NAME) + .internalName(COLUMN_1_3_INTERNAL_NAME) + .columnType(COLUMN_1_3_TYPE) + .isNullAllowed(COLUMN_1_3_NULL) + .isUnique(COLUMN_1_3_UNIQUE) + .isPrimaryKey(COLUMN_1_3_PRIMARY) + .enumValues(COLUMN_1_3_ENUM_VALUES) .build(), TableColumn.builder() - .id(COLUMN_4_ID) - .ordinalPosition(COLUMN_4_ORDINALPOS) + .id(COLUMN_1_4_ID) + .ordinalPosition(COLUMN_1_4_ORDINALPOS) .cdbid(DATABASE_1_ID) .tid(TABLE_1_ID) - .name(COLUMN_4_NAME) - .internalName(COLUMN_4_INTERNAL_NAME) - .columnType(COLUMN_4_TYPE) - .isNullAllowed(COLUMN_4_NULL) - .isUnique(COLUMN_4_UNIQUE) - .isPrimaryKey(COLUMN_4_PRIMARY) - .enumValues(COLUMN_4_ENUM_VALUES) + .name(COLUMN_1_4_NAME) + .internalName(COLUMN_1_4_INTERNAL_NAME) + .columnType(COLUMN_1_4_TYPE) + .isNullAllowed(COLUMN_1_4_NULL) + .isUnique(COLUMN_1_4_UNIQUE) + .isPrimaryKey(COLUMN_1_4_PRIMARY) + .enumValues(COLUMN_1_4_ENUM_VALUES) .build(), TableColumn.builder() - .id(COLUMN_5_ID) - .ordinalPosition(COLUMN_5_ORDINALPOS) + .id(COLUMN_1_5_ID) + .ordinalPosition(COLUMN_1_5_ORDINALPOS) .cdbid(DATABASE_1_ID) .tid(TABLE_1_ID) - .name(COLUMN_5_NAME) - .internalName(COLUMN_5_INTERNAL_NAME) - .columnType(COLUMN_5_TYPE) - .isNullAllowed(COLUMN_5_NULL) - .isUnique(COLUMN_5_UNIQUE) - .isPrimaryKey(COLUMN_5_PRIMARY) - .enumValues(COLUMN_5_ENUM_VALUES) + .name(COLUMN_1_5_NAME) + .internalName(COLUMN_1_5_INTERNAL_NAME) + .columnType(COLUMN_1_5_TYPE) + .isNullAllowed(COLUMN_1_5_NULL) + .isUnique(COLUMN_1_5_UNIQUE) + .isPrimaryKey(COLUMN_1_5_PRIMARY) + .enumValues(COLUMN_1_5_ENUM_VALUES) .build()); public final static Table TABLE_1 = Table.builder() @@ -324,6 +431,19 @@ public abstract class BaseUnitTest extends CsvUnitTest { .topic(TABLE_2_TOPIC) .build(); + + public final static Table TABLE_3 = Table.builder() + .id(TABLE_3_ID) + .tdbid(DATABASE_3_ID) + .created(Instant.now()) + .internalName(TABLE_3_INTERNALNAME) + .description(TABLE_3_DESCRIPTION) + .name(TABLE_3_NAME) + .lastModified(Instant.now()) + .columns(TABLE_3_COLUMNS) + .topic(TABLE_3_TOPIC) + .build(); + public final static Database DATABASE_1 = Database.builder() .id(DATABASE_1_ID) .created(Instant.now().minus(1, HOURS)) @@ -343,47 +463,59 @@ public abstract class BaseUnitTest extends CsvUnitTest { .lastModified(Instant.now()) .isPublic(false) .name(DATABASE_2_NAME) - .tables(List.of()) + .tables(List.of(TABLE_2)) .container(CONTAINER_2) .internalName(DATABASE_2_INTERNALNAME) .exchange(DATABASE_2_EXCHANGE) .build(); + public final static Database DATABASE_3 = Database.builder() + .id(DATABASE_3_ID) + .created(Instant.now().minus(1, HOURS)) + .lastModified(Instant.now()) + .isPublic(false) + .name(DATABASE_3_NAME) + .container(CONTAINER_3) + .tables(List.of(TABLE_3)) + .internalName(DATABASE_3_INTERNALNAME) + .exchange(DATABASE_3_EXCHANGE) + .build(); + public final static ColumnCreateDto[] COLUMNS_CSV01 = new ColumnCreateDto[]{ ColumnCreateDto.builder() - .type(COLUMN_1_TYPE_DTO) - .name(COLUMN_1_NAME) - .nullAllowed(COLUMN_1_NULL) - .primaryKey(COLUMN_1_PRIMARY) - .unique(COLUMN_1_UNIQUE) + .type(COLUMN_1_1_TYPE_DTO) + .name(COLUMN_1_1_NAME) + .nullAllowed(COLUMN_1_1_NULL) + .primaryKey(COLUMN_1_1_PRIMARY) + .unique(COLUMN_1_1_UNIQUE) .build(), ColumnCreateDto.builder() - .type(COLUMN_2_TYPE_DTO) - .name(COLUMN_2_NAME) - .nullAllowed(COLUMN_2_NULL) - .primaryKey(COLUMN_2_PRIMARY) - .unique(COLUMN_2_UNIQUE) + .type(COLUMN_1_2_TYPE_DTO) + .name(COLUMN_1_2_NAME) + .nullAllowed(COLUMN_1_2_NULL) + .primaryKey(COLUMN_1_2_PRIMARY) + .unique(COLUMN_1_2_UNIQUE) .build(), ColumnCreateDto.builder() - .type(COLUMN_3_TYPE_DTO) - .name(COLUMN_3_NAME) - .nullAllowed(COLUMN_3_NULL) - .primaryKey(COLUMN_3_PRIMARY) - .unique(COLUMN_3_UNIQUE) + .type(COLUMN_1_3_TYPE_DTO) + .name(COLUMN_1_3_NAME) + .nullAllowed(COLUMN_1_3_NULL) + .primaryKey(COLUMN_1_3_PRIMARY) + .unique(COLUMN_1_3_UNIQUE) .build(), ColumnCreateDto.builder() - .type(COLUMN_4_TYPE_DTO) - .name(COLUMN_4_NAME) - .nullAllowed(COLUMN_4_NULL) - .primaryKey(COLUMN_4_PRIMARY) - .unique(COLUMN_4_UNIQUE) + .type(COLUMN_1_4_TYPE_DTO) + .name(COLUMN_1_4_NAME) + .nullAllowed(COLUMN_1_4_NULL) + .primaryKey(COLUMN_1_4_PRIMARY) + .unique(COLUMN_1_4_UNIQUE) .build(), ColumnCreateDto.builder() - .type(COLUMN_5_TYPE_DTO) - .name(COLUMN_5_NAME) - .nullAllowed(COLUMN_5_NULL) - .primaryKey(COLUMN_5_PRIMARY) - .unique(COLUMN_5_UNIQUE) + .type(COLUMN_1_5_TYPE_DTO) + .name(COLUMN_1_5_NAME) + .nullAllowed(COLUMN_1_5_NULL) + .primaryKey(COLUMN_1_5_PRIMARY) + .unique(COLUMN_1_5_UNIQUE) .build()}; public final static TableCreateDto TABLE_2_CREATE_DTO = TableCreateDto.builder() diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java b/fda-table-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java index 5eee346bbff3c664dca48c9859634771e049f957..222c5c1c88024ab5aa9cb0432e38c2c0783530c1 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java @@ -1,6 +1,8 @@ package at.tuwien.config; +import at.tuwien.entities.container.Container; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.RestartPolicy; import com.github.dockerjava.core.DefaultDockerClientConfig; @@ -9,6 +11,8 @@ import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; import com.github.dockerjava.transport.DockerHttpClient; +import java.util.Objects; + public class DockerConfig { private final static DockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder() @@ -27,4 +31,20 @@ public class DockerConfig { .withDockerHttpClient(dockerHttpClient) .build(); + public static void startContainer(Container container) throws InterruptedException { + final InspectContainerResponse inspect = dockerClient.inspectContainerCmd(container.getHash()) + .exec(); + if (Objects.equals(inspect.getState().getStatus(), "running")) { + return; + } + dockerClient.startContainerCmd(container.getHash()) + .exec(); + Thread.sleep(6 * 1000L); + } + + public static void stopContainer(Container container) { + dockerClient.stopContainerCmd(container.getHash()) + .exec(); + } + } diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java b/fda-table-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..c1fa1bdc90bf7a3ac6936b0064512a82b61edf16 --- /dev/null +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java @@ -0,0 +1,32 @@ +package at.tuwien.config; + +import at.tuwien.entities.database.table.Table; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.context.annotation.Bean; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; + +@Configurable +public class MariaDbConfig { + + @Bean + public Properties mariaDbProperties() { + final Properties properties = new Properties(); + properties.setProperty("MARIADB_USER", "mariadb"); + properties.setProperty("MARIADB_PASSWORD", "mariadb"); + return properties; + } + + public static void clearDatabase(Table table) throws SQLException { + final Connection connection = DriverManager.getConnection("jdbc:mariadb://" + table.getDatabase().getContainer().getInternalName() + "/" + table.getDatabase().getInternalName(), + "mariadb", "mariadb"); + final Statement statement = connection.createStatement(); + statement.execute("DELETE FROM " + table.getInternalName() + ";"); + connection.close(); + } + +} diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/config/PostgresConfig.java b/fda-table-service/rest-service/src/test/java/at/tuwien/config/PostgresConfig.java index faa45e9e15f0c26baaab0f20d34a7f6fe5128773..0e22767fb8e21810c39bbca2f944574fddaf6715 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/config/PostgresConfig.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/config/PostgresConfig.java @@ -15,15 +15,14 @@ public class PostgresConfig { final Properties properties = new Properties(); properties.setProperty("POSTGRES_USER", "postgres"); properties.setProperty("POSTGRES_PASSWORD", "postgres"); - properties.setProperty("POSTGRES_DB", "u01"); return properties; } - public static void clearDatabase() throws SQLException { - final Connection connection = DriverManager.getConnection("jdbc:postgresql://fda-userdb-u01/weather", + public static void clearDatabase(String containerHost, String databaseName, String tableName) throws SQLException { + final Connection connection = DriverManager.getConnection("jdbc:postgresql://" + containerHost + "/" + databaseName, "postgres", "postgres"); final Statement statement = connection.createStatement(); - statement.execute("DELETE FROM weather_aus;"); + statement.execute("DELETE FROM " + tableName + ";"); connection.close(); } diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/endpoint/DataEndpointIntegrationTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/endpoint/DataEndpointIntegrationTest.java index ef40a34714324c301cd6be50eed3195051d64dce..bbd6015e1ab870ccac0978c01e75aef0041d586b 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/endpoint/DataEndpointIntegrationTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/endpoint/DataEndpointIntegrationTest.java @@ -2,9 +2,12 @@ package at.tuwien.endpoint; import at.tuwien.BaseUnitTest; import at.tuwien.api.database.table.*; +import at.tuwien.config.DockerConfig; +import at.tuwien.config.MariaDbConfig; import at.tuwien.config.PostgresConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.endpoints.DataEndpoint; +import at.tuwien.entities.container.Container; import at.tuwien.exception.*; import at.tuwien.repository.jpa.DatabaseRepository; import at.tuwien.repository.jpa.ImageRepository; @@ -13,6 +16,7 @@ import at.tuwien.service.impl.MariaDataService; import at.tuwien.service.impl.TableServiceImpl; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.NotModifiedException; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.HostConfig; @@ -76,18 +80,18 @@ public class DataEndpointIntegrationTest extends BaseUnitTest { .withSubnet("172.28.0.0/16"))) .withEnableIpv6(false) .exec(); - final CreateContainerResponse request = dockerClient.createContainerCmd(IMAGE_1_REPOSITORY + ":" + IMAGE_1_TAG) + final CreateContainerResponse request = dockerClient.createContainerCmd(IMAGE_2_REPOSITORY + ":" + IMAGE_2_TAG) .withHostConfig(hostConfig.withNetworkMode("fda-userdb")) .withName(CONTAINER_1_INTERNALNAME) .withIpv4Address(CONTAINER_1_IP) .withHostName(CONTAINER_1_INTERNALNAME) - .withEnv("POSTGRES_USER=postgres", "POSTGRES_PASSWORD=postgres", "POSTGRES_DB=weather") + .withEnv("MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", + "MARIADB_DATABASE=weather") .withBinds(Bind.parse(new File("./src/test/resources/weather").toPath().toAbsolutePath() + ":/docker-entrypoint-initdb.d")) .exec(); - /* start container */ - dockerClient.startContainerCmd(request.getId()).exec(); - Thread.sleep(3000); + /* set hash */ + CONTAINER_1.setHash(request.getId()); } @Transactional @@ -126,20 +130,21 @@ public class DataEndpointIntegrationTest extends BaseUnitTest { @Test public void insertFromTuple_succeeds() throws TableNotFoundException, TableMalformedException, - DatabaseNotFoundException, ImageNotSupportedException, SQLException { + DatabaseNotFoundException, ImageNotSupportedException, SQLException, InterruptedException { final Map<String, Object> map = new LinkedHashMap<>() {{ - put(COLUMN_1_NAME, 4); - put(COLUMN_2_NAME, Instant.now()); - put(COLUMN_3_NAME, 35.2); - put(COLUMN_4_NAME, "Sydney"); - put(COLUMN_5_NAME, 10.2); + put(COLUMN_1_1_NAME, 4); + put(COLUMN_1_2_NAME, "2020-11-01"); + put(COLUMN_1_3_NAME, "Sydney"); + put(COLUMN_1_4_NAME, 35.2); + put(COLUMN_1_5_NAME, 10.2); }}; final TableCsvDto request = TableCsvDto.builder() .data(List.of(map)) .build(); /* mock */ - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ final ResponseEntity<?> response = dataEndpoint.insertFromTuple(DATABASE_1_ID, TABLE_1_ID, request); @@ -153,7 +158,7 @@ public class DataEndpointIntegrationTest extends BaseUnitTest { .build(); /* mock */ - PostgresConfig.clearDatabase(); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ assertThrows(TableMalformedException.class, () -> { @@ -162,13 +167,14 @@ public class DataEndpointIntegrationTest extends BaseUnitTest { } @Test - public void insertFromTuple_empty2_fails() throws SQLException { + public void insertFromTuple_empty2_fails() throws SQLException, InterruptedException { final TableCsvDto request = TableCsvDto.builder() .data(List.of(Map.of())) .build(); /* mock */ - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ assertThrows(TableMalformedException.class, () -> { @@ -178,7 +184,7 @@ public class DataEndpointIntegrationTest extends BaseUnitTest { @Test public void insertFromFile_succeeds() throws TableNotFoundException, TableMalformedException, - DatabaseNotFoundException, ImageNotSupportedException, FileStorageException, SQLException { + DatabaseNotFoundException, ImageNotSupportedException, FileStorageException, SQLException, InterruptedException { final TableInsertDto request = TableInsertDto.builder() .delimiter(',') .skipHeader(true) @@ -187,7 +193,8 @@ public class DataEndpointIntegrationTest extends BaseUnitTest { .build(); /* mock */ - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ final ResponseEntity<?> response = dataEndpoint.insertFromFile(DATABASE_1_ID, TABLE_1_ID, request); @@ -196,13 +203,14 @@ public class DataEndpointIntegrationTest extends BaseUnitTest { @Test public void getAll_succeeds() throws TableNotFoundException, TableMalformedException, - DatabaseNotFoundException, ImageNotSupportedException, SQLException, DatabaseConnectionException { + DatabaseNotFoundException, ImageNotSupportedException, SQLException, DatabaseConnectionException, InterruptedException { final Instant timestamp = Instant.now(); final Long page = 0L; final Long size = 1L; /* mock */ - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ final ResponseEntity<?> response = dataEndpoint.getAll(DATABASE_1_ID, TABLE_1_ID, timestamp, page, size); diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperIntegrationTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperIntegrationTest.java index 3cf73137939e4b9cc7e36097e8f2d48ef86c9725..f18a4189acf2f3cb4a641de984b017e00d55c1c3 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperIntegrationTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperIntegrationTest.java @@ -119,39 +119,39 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .description(TABLE_2_DESCRIPTION) .columns(new ColumnCreateDto[]{ ColumnCreateDto.builder() - .type(COLUMN_1_TYPE_DTO) - .name(COLUMN_1_NAME) - .nullAllowed(COLUMN_1_NULL) - .primaryKey(COLUMN_1_PRIMARY) - .unique(COLUMN_1_UNIQUE) + .type(COLUMN_1_1_TYPE_DTO) + .name(COLUMN_1_1_NAME) + .nullAllowed(COLUMN_1_1_NULL) + .primaryKey(COLUMN_1_1_PRIMARY) + .unique(COLUMN_1_1_UNIQUE) .build(), ColumnCreateDto.builder() - .type(COLUMN_2_TYPE_DTO) - .name(COLUMN_2_NAME) - .nullAllowed(COLUMN_2_NULL) - .primaryKey(COLUMN_2_PRIMARY) - .unique(COLUMN_2_UNIQUE) + .type(COLUMN_1_2_TYPE_DTO) + .name(COLUMN_1_2_NAME) + .nullAllowed(COLUMN_1_2_NULL) + .primaryKey(COLUMN_1_2_PRIMARY) + .unique(COLUMN_1_2_UNIQUE) .build(), ColumnCreateDto.builder() - .type(COLUMN_3_TYPE_DTO) - .name(COLUMN_3_NAME) - .nullAllowed(COLUMN_3_NULL) - .primaryKey(COLUMN_3_PRIMARY) - .unique(COLUMN_3_UNIQUE) + .type(COLUMN_1_3_TYPE_DTO) + .name(COLUMN_1_3_NAME) + .nullAllowed(COLUMN_1_3_NULL) + .primaryKey(COLUMN_1_3_PRIMARY) + .unique(COLUMN_1_3_UNIQUE) .build(), ColumnCreateDto.builder() - .type(COLUMN_4_TYPE_DTO) - .name(COLUMN_4_NAME) - .nullAllowed(COLUMN_4_NULL) - .primaryKey(COLUMN_4_PRIMARY) - .unique(COLUMN_4_UNIQUE) + .type(COLUMN_1_4_TYPE_DTO) + .name(COLUMN_1_4_NAME) + .nullAllowed(COLUMN_1_4_NULL) + .primaryKey(COLUMN_1_4_PRIMARY) + .unique(COLUMN_1_4_UNIQUE) .build(), ColumnCreateDto.builder() - .type(COLUMN_5_TYPE_DTO) - .name(COLUMN_5_NAME) - .nullAllowed(COLUMN_5_NULL) - .primaryKey(COLUMN_5_PRIMARY) - .unique(COLUMN_5_UNIQUE) + .type(COLUMN_1_5_TYPE_DTO) + .name(COLUMN_1_5_NAME) + .nullAllowed(COLUMN_1_5_NULL) + .primaryKey(COLUMN_1_5_PRIMARY) + .unique(COLUMN_1_5_UNIQUE) .build()}) .build(); } @@ -207,7 +207,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(Objects::nonNull) .map(Key::getFields) .map(k -> k.get(0)) - .map(f -> f.getName().matches(COLUMN_1_INTERNAL_NAME)) + .map(f -> f.getName().matches(COLUMN_1_1_INTERNAL_NAME)) .count()); assertEquals(1, context.meta() .getTables() @@ -217,7 +217,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(Objects::nonNull) .map(Key::getFields) .map(k -> k.get(0)) - .map(f -> f.getName().matches(COLUMN_2_INTERNAL_NAME)) + .map(f -> f.getName().matches(COLUMN_1_2_INTERNAL_NAME)) .count()); } @@ -245,7 +245,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(Objects::nonNull) .map(Key::getFields) .map(k -> k.get(0)) - .map(f -> f.getName().matches(COLUMN_1_INTERNAL_NAME)) + .map(f -> f.getName().matches(COLUMN_1_1_INTERNAL_NAME)) .count()); } @@ -273,7 +273,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(Objects::nonNull) .map(Key::getFields) .map(k -> k.get(0)) - .map(f -> f.getName().matches(COLUMN_1_INTERNAL_NAME)) + .map(f -> f.getName().matches(COLUMN_1_1_INTERNAL_NAME)) .count()); } @@ -301,7 +301,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(Objects::nonNull) .map(Key::getFields) .map(k -> k.get(0)) - .map(f -> f.getName().matches(COLUMN_1_INTERNAL_NAME)) + .map(f -> f.getName().matches(COLUMN_1_1_INTERNAL_NAME)) .count()); } @@ -329,7 +329,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(Objects::nonNull) .map(Key::getFields) .map(k -> k.get(0)) - .map(f -> f.getName().matches(COLUMN_1_INTERNAL_NAME)) + .map(f -> f.getName().matches(COLUMN_1_1_INTERNAL_NAME)) .count()); } @@ -390,7 +390,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(t -> t.getName().matches(TABLE_2_INTERNALNAME)) .map(Table::getKeys) .map(uniqueKeys -> uniqueKeys.get(0)) - .map(uniqueKey -> uniqueKey.constraint().getName().matches(COLUMN_1_INTERNAL_NAME)) + .map(uniqueKey -> uniqueKey.constraint().getName().matches(COLUMN_1_1_INTERNAL_NAME)) .count()); } @@ -411,7 +411,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(t -> t.getName().matches(TABLE_2_INTERNALNAME)) .map(Table::getKeys) .map(uniqueKeys -> uniqueKeys.get(0)) - .map(uniqueKey -> uniqueKey.constraint().getName().matches(COLUMN_1_INTERNAL_NAME)) + .map(uniqueKey -> uniqueKey.constraint().getName().matches(COLUMN_1_1_INTERNAL_NAME)) .count()); assertEquals(1, context.meta() .getTables() @@ -419,7 +419,7 @@ public class TableMapperIntegrationTest extends BaseUnitTest { .filter(t -> t.getName().matches(TABLE_2_INTERNALNAME)) .map(Table::getKeys) .map(uniqueKeys -> uniqueKeys.get(0)) - .map(uniqueKey -> uniqueKey.constraint().getName().matches(COLUMN_2_INTERNAL_NAME)) + .map(uniqueKey -> uniqueKey.constraint().getName().matches(COLUMN_1_2_INTERNAL_NAME)) .count()); } diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/DataServiceIntegrationTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/DataServiceIntegrationTest.java index b09e84dc22dc47e687326b45d45cd444bdc2a32d..a34a5f1c5d2607cc148692fbc57c38ccdd1d53b0 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/DataServiceIntegrationTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/DataServiceIntegrationTest.java @@ -2,11 +2,17 @@ package at.tuwien.service; import at.tuwien.BaseUnitTest; import at.tuwien.api.database.table.TableInsertDto; +import at.tuwien.config.DockerConfig; +import at.tuwien.config.MariaDbConfig; import at.tuwien.config.PostgresConfig; import at.tuwien.config.ReadyConfig; +import at.tuwien.entities.container.Container; +import at.tuwien.entities.database.Database; import at.tuwien.entities.database.table.Table; import at.tuwien.exception.*; +import at.tuwien.repository.jpa.ContainerRepository; import at.tuwien.repository.jpa.DatabaseRepository; +import at.tuwien.repository.jpa.ImageRepository; import at.tuwien.repository.jpa.TableRepository; import at.tuwien.service.impl.MariaDataService; import com.github.dockerjava.api.command.CreateContainerResponse; @@ -28,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional; import java.io.File; import java.sql.SQLException; import java.util.Arrays; +import java.util.List; import java.util.Objects; import java.util.Optional; @@ -53,6 +60,9 @@ public class DataServiceIntegrationTest extends BaseUnitTest { @Autowired private TableRepository tableRepository; + @Autowired + private ImageRepository imageRepository; + @Autowired private MariaDataService dataService; @@ -67,17 +77,27 @@ public class DataServiceIntegrationTest extends BaseUnitTest { .withSubnet("172.28.0.0/16"))) .withEnableIpv6(false) .exec(); - final CreateContainerResponse request = dockerClient.createContainerCmd(IMAGE_1_REPOSITORY + ":" + IMAGE_1_TAG) + final CreateContainerResponse request = dockerClient.createContainerCmd(IMAGE_2_REPOSITORY + ":" + IMAGE_2_TAG) .withHostConfig(hostConfig.withNetworkMode("fda-userdb")) .withName(CONTAINER_1_INTERNALNAME) .withIpv4Address(CONTAINER_1_IP) .withHostName(CONTAINER_1_INTERNALNAME) - .withEnv("POSTGRES_USER=postgres", "POSTGRES_PASSWORD=postgres", "POSTGRES_DB=weather") + .withEnv("MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=weather") .withBinds(Bind.parse(new File("./src/test/resources/weather").toPath().toAbsolutePath() + ":/docker-entrypoint-initdb.d")) .exec(); + final CreateContainerResponse request3 = dockerClient.createContainerCmd(IMAGE_2_REPOSITORY + ":" + IMAGE_2_TAG) + .withHostConfig(hostConfig.withNetworkMode("fda-userdb")) + .withName(CONTAINER_3_INTERNALNAME) + .withIpv4Address(CONTAINER_3_IP) + .withHostName(CONTAINER_3_INTERNALNAME) + .withEnv("MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=biomedical") + .withBinds(Bind.parse(new File("./src/test/resources/species").toPath().toAbsolutePath() + + ":/docker-entrypoint-initdb.d")) + .exec(); /* set hash */ CONTAINER_1.setHash(request.getId()); + CONTAINER_3.setHash(request3.getId()); } @AfterAll @@ -109,8 +129,14 @@ public class DataServiceIntegrationTest extends BaseUnitTest { @Transactional @BeforeEach public void beforeEach() { + imageRepository.save(IMAGE_1); + imageRepository.save(IMAGE_2); + TABLE_1.setDatabase(DATABASE_1); + TABLE_2.setDatabase(DATABASE_2); + TABLE_3.setDatabase(DATABASE_3); databaseRepository.save(DATABASE_1); databaseRepository.save(DATABASE_2); + databaseRepository.save(DATABASE_3); } @Test @@ -125,8 +151,8 @@ public class DataServiceIntegrationTest extends BaseUnitTest { .build(); /* mock */ - startContainer(); - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ dataService.insertCsv(DATABASE_1_ID, TABLE_1_ID, request); @@ -147,8 +173,8 @@ public class DataServiceIntegrationTest extends BaseUnitTest { .build(); /* mock */ - startContainer(); - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ dataService.insertCsv(DATABASE_1_ID, TABLE_1_ID, request); @@ -168,8 +194,8 @@ public class DataServiceIntegrationTest extends BaseUnitTest { .build(); /* mock */ - startContainer(); - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ assertThrows(TableMalformedException.class, () -> { @@ -190,8 +216,8 @@ public class DataServiceIntegrationTest extends BaseUnitTest { .build(); /* mock */ - startContainer(); - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ dataService.insertCsv(DATABASE_1_ID, TABLE_1_ID, request); @@ -210,8 +236,8 @@ public class DataServiceIntegrationTest extends BaseUnitTest { .build(); /* mock */ - startContainer(); - PostgresConfig.clearDatabase(); + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ assertThrows(TableMalformedException.class, () -> { @@ -220,7 +246,7 @@ public class DataServiceIntegrationTest extends BaseUnitTest { } @Test - public void insertFromFile_notRunning_fails() { + public void insertFromFile_notRunning_fails() throws SQLException { final TableInsertDto request = TableInsertDto.builder() .delimiter(';') .skipHeader(true) @@ -229,7 +255,7 @@ public class DataServiceIntegrationTest extends BaseUnitTest { .build(); /* mock */ - stopContainer(); + DockerConfig.stopContainer(CONTAINER_1); /* test */ assertThrows(TableMalformedException.class, () -> { @@ -237,20 +263,21 @@ public class DataServiceIntegrationTest extends BaseUnitTest { }); } - private static void startContainer() throws InterruptedException { - final InspectContainerResponse inspect = dockerClient.inspectContainerCmd(CONTAINER_1.getHash()) - .exec(); - if (Objects.equals(inspect.getState().getStatus(), "running")) { - return; - } - dockerClient.startContainerCmd(CONTAINER_1.getHash()) - .exec(); - Thread.sleep(3000L); - } + @Test + public void insertFromRemote_succeeds() throws TableNotFoundException, TableMalformedException, + DatabaseNotFoundException, ImageNotSupportedException, FileStorageException, InterruptedException, + SQLException { + final TableInsertDto request = TableInsertDto.builder() + .skipHeader(true) + .csvLocation("https://sandbox.zenodo.org/api/files/6aca3421-add3-489b-8c4a-35228fe5c683/species_id.csv") + .build(); - private static void stopContainer() { - dockerClient.stopContainerCmd(CONTAINER_1.getHash()) - .exec(); + /* mock */ + DockerConfig.startContainer(CONTAINER_3); + MariaDbConfig.clearDatabase(TABLE_3); + + /* test */ + dataService.insertCsv(DATABASE_3_ID, TABLE_3_ID, request); } } diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/DataServiceUnitTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/DataServiceUnitTest.java index e966a154e58677c6205e7fffc3eaa6fc96a8fb8c..7467baf582f0a49a0cd55ed1c9fcae74c91d2bd4 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/DataServiceUnitTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/DataServiceUnitTest.java @@ -1,8 +1,8 @@ package at.tuwien.service; import at.tuwien.BaseUnitTest; -import at.tuwien.api.container.ContainerCreateRequestDto; import at.tuwien.api.database.table.TableCsvDto; +import at.tuwien.config.DockerConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.exception.*; import at.tuwien.repository.jpa.DatabaseRepository; @@ -24,12 +24,8 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.io.File; -import java.sql.SQLException; import java.time.Instant; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import static at.tuwien.config.DockerConfig.dockerClient; import static at.tuwien.config.DockerConfig.hostConfig; @@ -41,8 +37,6 @@ import static org.mockito.Mockito.*; @Log4j2 public class DataServiceUnitTest extends BaseUnitTest { - private static CreateContainerResponse container; - @MockBean private Channel channel; @@ -58,8 +52,14 @@ public class DataServiceUnitTest extends BaseUnitTest { @MockBean private TableRepository tableRepository; + /** + * We need a container to test the CRUD operations as of now it is unfeasible to determine the correctness of the + * operations without a live container + * + * @throws InterruptedException Sleep interrupted. + */ @BeforeAll - public static void beforeAll() throws InterruptedException, SQLException { + public static void beforeAll() throws InterruptedException { afterAll(); /* create network */ dockerClient.createNetworkCmd() @@ -70,18 +70,18 @@ public class DataServiceUnitTest extends BaseUnitTest { .withEnableIpv6(false) .exec(); /* create container */ - container = dockerClient.createContainerCmd(IMAGE_1_REPOSITORY + ":" + IMAGE_1_TAG) + final CreateContainerResponse response = dockerClient.createContainerCmd(IMAGE_2_REPOSITORY + ":" + IMAGE_2_TAG) .withHostConfig(hostConfig.withNetworkMode("fda-userdb")) .withName(CONTAINER_1_INTERNALNAME) .withIpv4Address(CONTAINER_1_IP) .withHostName(CONTAINER_1_INTERNALNAME) - .withEnv("POSTGRES_USER=postgres", "POSTGRES_PASSWORD=postgres", "POSTGRES_DB=weather") + .withEnv("MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=weather") .withBinds(Bind.parse(new File("./src/test/resources/weather").toPath().toAbsolutePath() + ":/docker-entrypoint-initdb.d")) .exec(); /* start */ - dockerClient.startContainerCmd(container.getId()).exec(); - Thread.sleep(3000); + CONTAINER_1.setHash(response.getId()); + DockerConfig.startContainer(CONTAINER_1); } @AfterAll @@ -132,37 +132,6 @@ public class DataServiceUnitTest extends BaseUnitTest { dataService.selectAll(DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size); } - @Test - public void selectAll_mariaDb_succeeds() throws TableNotFoundException, DatabaseConnectionException, - DatabaseNotFoundException, ImageNotSupportedException, TableMalformedException, InterruptedException { - final Long page = 0L; - final Long size = 10L; - - - /* create container */ - final CreateContainerResponse mariaDbContainer = dockerClient.createContainerCmd(IMAGE_2_REPOSITORY + ":" + IMAGE_2_TAG) - .withHostConfig(hostConfig.withNetworkMode("fda-userdb")) - .withName(CONTAINER_2_INTERNALNAME) - .withIpv4Address(CONTAINER_2_IP) - .withHostName(CONTAINER_2_INTERNALNAME) - .withEnv("MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=weather") - .withBinds(Bind.parse(new File("./src/test/resources/weather-mariadb").toPath().toAbsolutePath() - + ":/docker-entrypoint-initdb.d")) - .exec(); - dockerClient.startContainerCmd(mariaDbContainer.getId()) - .exec(); - Thread.sleep(10 * 1000); - - /* mock */ - when(databaseRepository.findById(DATABASE_2_ID)) - .thenReturn(Optional.of(DATABASE_2)); - when(tableRepository.findByDatabaseAndId(DATABASE_2, TABLE_2_ID)) - .thenReturn(Optional.of(TABLE_2)); - - /* test */ - dataService.selectAll(DATABASE_2_ID, TABLE_2_ID, Instant.now(), page, size); - } - @Test public void selectAll_noTable_fails() { final Long page = 0L; diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/JdbcConnectorUnitTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/JdbcConnectorUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6a9e810dd04d80e6437bb0d8ecae85880ef955f0 --- /dev/null +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/JdbcConnectorUnitTest.java @@ -0,0 +1,63 @@ +package at.tuwien.service; + +import at.tuwien.BaseUnitTest; +import at.tuwien.config.ReadyConfig; +import at.tuwien.service.impl.JdbcConnector; +import at.tuwien.service.impl.MariaDataService; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.rabbitmq.client.Channel; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class JdbcConnectorUnitTest extends BaseUnitTest { + + @MockBean + private Channel channel; + + @MockBean + private ReadyConfig readyConfig; + + @Autowired + private MariaDataService mariaDataService; + + @Test + public void isReserved_succeeds() throws IOException { + assertTrue(mariaDataService.isReserved("table")); + } + + @Test + public void isReserved_uppercase_succeeds() throws IOException { + assertTrue(mariaDataService.isReserved("TABLE")); + } + + @Test + public void isReserved_mixed_succeeds() throws IOException { + assertTrue(mariaDataService.isReserved("tAbLE")); + } + + @Test + public void isReserved_inSentence_fails() throws IOException { + assertFalse(mariaDataService.isReserved("My nice table is nice")); + } + + @Test + public void isReserved_contained_fails() throws IOException { + assertFalse(mariaDataService.isReserved("My nice tableService is nice")); + } + +} + + diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java index 3dc7c185238cd28af820e30cddd1693d77c30104..c25457487645b2870e500b34caaa9c59fdc856c7 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java @@ -2,7 +2,10 @@ package at.tuwien.service; import at.tuwien.BaseUnitTest; import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.config.DockerConfig; +import at.tuwien.config.MariaDbConfig; import at.tuwien.config.ReadyConfig; +import at.tuwien.entities.container.Container; import at.tuwien.entities.database.table.Table; import at.tuwien.exception.*; import at.tuwien.repository.jpa.ContainerRepository; @@ -12,6 +15,7 @@ import at.tuwien.repository.jpa.TableRepository; import at.tuwien.service.impl.TableServiceImpl; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.NotModifiedException; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.HostConfig; @@ -30,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional; import java.io.File; import java.sql.SQLException; import java.util.Arrays; +import java.util.Objects; import static at.tuwien.config.DockerConfig.dockerClient; import static at.tuwien.config.DockerConfig.hostConfig; @@ -74,18 +79,16 @@ public class TableServiceIntegrationTest extends BaseUnitTest { .withEnableIpv6(false) .exec(); /* create container */ - final CreateContainerResponse container = dockerClient.createContainerCmd(IMAGE_1_REPOSITORY + ":" + IMAGE_1_TAG) + final CreateContainerResponse response = dockerClient.createContainerCmd(IMAGE_2_REPOSITORY + ":" + IMAGE_2_TAG) .withHostConfig(hostConfig.withNetworkMode("fda-userdb")) .withName(CONTAINER_1_INTERNALNAME) .withIpv4Address(CONTAINER_1_IP) .withHostName(CONTAINER_1_INTERNALNAME) - .withEnv("POSTGRES_USER=postgres", "POSTGRES_PASSWORD=postgres", "POSTGRES_DB=weather") + .withEnv("MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=weather") .withBinds(Bind.parse(new File("./src/test/resources/weather").toPath().toAbsolutePath() + ":/docker-entrypoint-initdb.d")) .exec(); - /* start */ - dockerClient.startContainerCmd(container.getId()).exec(); - Thread.sleep(3000); + CONTAINER_1.setHash(response.getId()); } @AfterAll @@ -124,13 +127,17 @@ public class TableServiceIntegrationTest extends BaseUnitTest { @Test public void create_table_succeeds() throws ArbitraryPrimaryKeysException, DatabaseNotFoundException, - ImageNotSupportedException, DataProcessingException, TableMalformedException { + ImageNotSupportedException, DataProcessingException, TableMalformedException, InterruptedException, SQLException { final TableCreateDto request = TableCreateDto.builder() .name(TABLE_2_NAME) .description(TABLE_2_DESCRIPTION) .columns(COLUMNS_CSV01) .build(); + /* start */ + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); + /* test */ final Table response = tableService.createTable(DATABASE_1_ID, request); assertEquals(TABLE_2_NAME, response.getName()); @@ -142,7 +149,11 @@ public class TableServiceIntegrationTest extends BaseUnitTest { @Test public void delete_succeeds() throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, - DataProcessingException { + DataProcessingException, InterruptedException, SQLException { + + /* start */ + DockerConfig.startContainer(CONTAINER_1); + MariaDbConfig.clearDatabase(TABLE_1); /* test */ tableService.deleteTable(DATABASE_1_ID, TABLE_1_ID); diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java index 4eebefd8c881f45a91a771ef9a8efb6a3c6371df..7a81cd0551dc993dba222a48d11e1311ab5cb4ef 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java @@ -171,4 +171,6 @@ public class TableServiceUnitTest extends BaseUnitTest { assertEquals(1001, response.getData().size()); } + + } diff --git a/fda-table-service/rest-service/src/test/resources/integration-test.after b/fda-table-service/rest-service/src/test/resources/integration-test.after deleted file mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..0000000000000000000000000000000000000000 --- a/fda-table-service/rest-service/src/test/resources/integration-test.after +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/fda-table-service/rest-service/src/test/resources/integration-test.before b/fda-table-service/rest-service/src/test/resources/integration-test.before deleted file mode 100755 index f6fca54b4f90896861b24e6d938b51ed5f8e2b5b..0000000000000000000000000000000000000000 --- a/fda-table-service/rest-service/src/test/resources/integration-test.before +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -docker pull mariadb:latest -docker pull mysql:latest -docker pull postgres:latest \ No newline at end of file diff --git a/fda-table-service/rest-service/src/test/resources/species/Species.sql b/fda-table-service/rest-service/src/test/resources/species/Species.sql new file mode 100644 index 0000000000000000000000000000000000000000..aaa14c1ad886b3c3cc5e16627dde327bae047af1 --- /dev/null +++ b/fda-table-service/rest-service/src/test/resources/species/Species.sql @@ -0,0 +1,7 @@ +/* https://sandbox.zenodo.org/api/files/6aca3421-add3-489b-8c4a-35228fe5c683/species_id.csv */ +CREATE TABLE maldi_ms_data +( + mdb_qu VARCHAR(255) NOT NULL, + mdb_species VARCHAR(255) NOT NULL, + mdb_score VARCHAR(255) NOT NULL +) WITH SYSTEM VERSIONING; \ No newline at end of file diff --git a/fda-table-service/rest-service/src/test/resources/weather-mariadb/WeatherAus.sql b/fda-table-service/rest-service/src/test/resources/weather-mariadb/WeatherAus.sql deleted file mode 100644 index 2b78c2210c1f63ac2d08e3b1a992633a4628e19e..0000000000000000000000000000000000000000 --- a/fda-table-service/rest-service/src/test/resources/weather-mariadb/WeatherAus.sql +++ /dev/null @@ -1,14 +0,0 @@ -/* https://www.kaggle.com/jsphyg/weather-dataset-rattle-package */ -CREATE TABLE weather_aus -( - mdb_id BIGINT NOT NULL PRIMARY KEY, - mdb_date DATE NOT NULL, - mdb_mintemp DOUBLE PRECISION NULL, - mdb_location VARCHAR(255) NULL, - mdb_rainfall DOUBLE PRECISION NULL -) WITH SYSTEM VERSIONING; - -INSERT INTO weather_aus (mdb_id, mdb_date, mdb_location, mdb_mintemp, mdb_rainfall) -VALUES (1, '2008-12-01'::DATE, 13.4, 'Albury', 0.6), - (2, '2008-12-02'::DATE, 7.4, 'Albury', 0), - (3, '2008-12-03'::DATE, 12.9, 'Albury', 0); \ No newline at end of file diff --git a/fda-table-service/rest-service/src/test/resources/weather/WeatherAus.sql b/fda-table-service/rest-service/src/test/resources/weather/WeatherAus.sql index 8382ebece49044d8f6bd14d6852f5a7f6ddd4ad0..2b78c2210c1f63ac2d08e3b1a992633a4628e19e 100644 --- a/fda-table-service/rest-service/src/test/resources/weather/WeatherAus.sql +++ b/fda-table-service/rest-service/src/test/resources/weather/WeatherAus.sql @@ -6,7 +6,7 @@ CREATE TABLE weather_aus mdb_mintemp DOUBLE PRECISION NULL, mdb_location VARCHAR(255) NULL, mdb_rainfall DOUBLE PRECISION NULL -); +) WITH SYSTEM VERSIONING; INSERT INTO weather_aus (mdb_id, mdb_date, mdb_location, mdb_mintemp, mdb_rainfall) VALUES (1, '2008-12-01'::DATE, 13.4, 'Albury', 0.6), diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/DataService.java b/fda-table-service/services/src/main/java/at/tuwien/service/DataService.java index a456ad567feb893f6745a7e09a2bd099283923b1..e1622aec4653b4c2480dd4cd16746a18fde78637 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/DataService.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/DataService.java @@ -6,9 +6,11 @@ import at.tuwien.api.database.table.TableInsertDto; import at.tuwien.entities.database.table.Table; import at.tuwien.exception.*; import lombok.NonNull; +import org.springframework.stereotype.Service; import java.time.Instant; +@Service public interface DataService { /** @@ -62,7 +64,7 @@ public interface DataService { * @throws ImageNotSupportedException The image is not supported. * @throws DatabaseConnectionException The connection to the remote database was unsuccessful. */ - QueryResultDto selectAll(@NonNull Long databaseId, @NonNull Long tableId, @NonNull Instant timestamp, - @NonNull Long page, @NonNull Long size) throws TableNotFoundException, - DatabaseNotFoundException, ImageNotSupportedException, DatabaseConnectionException, TableMalformedException; + QueryResultDto selectAll(@NonNull Long databaseId, @NonNull Long tableId, Instant timestamp, + Long page, Long size) throws TableNotFoundException, DatabaseNotFoundException, + ImageNotSupportedException, DatabaseConnectionException, TableMalformedException; } diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/DatabaseConnector.java b/fda-table-service/services/src/main/java/at/tuwien/service/DatabaseConnector.java index ff3e2da84cb607a40a87dfce34160c26f92cdb90..34bba6c8ad364a93f8881fcc0964ae9b07c31b37 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/DatabaseConnector.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/DatabaseConnector.java @@ -11,6 +11,7 @@ import at.tuwien.exception.TableMalformedException; import org.jooq.DSLContext; import org.springframework.transaction.annotation.Transactional; +import java.io.IOException; import java.sql.SQLException; import java.sql.Timestamp; @@ -36,7 +37,7 @@ public interface DatabaseConnector { * @throws TableMalformedException The resulting table by the mapper is malformed. */ void create(Database database, TableCreateDto createDto) throws SQLException, - ArbitraryPrimaryKeysException, ImageNotSupportedException, TableMalformedException; + ArbitraryPrimaryKeysException, ImageNotSupportedException, TableMalformedException, IOException; /** * Insert data inside a csv document into a table diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/impl/JdbcConnector.java b/fda-table-service/services/src/main/java/at/tuwien/service/impl/JdbcConnector.java index a62552ecced5e741d3f494289e316f5d554c34ac..073a249879b550f7997ad870dd982998d6de2f58 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/impl/JdbcConnector.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/impl/JdbcConnector.java @@ -1,6 +1,5 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableCsvDto; import at.tuwien.entities.database.Database; @@ -9,44 +8,47 @@ import at.tuwien.exception.ArbitraryPrimaryKeysException; import at.tuwien.exception.ImageNotSupportedException; import at.tuwien.exception.TableMalformedException; import at.tuwien.mapper.ImageMapper; -import at.tuwien.mapper.QueryMapper; import at.tuwien.mapper.TableMapper; import at.tuwien.service.DatabaseConnector; import lombok.extern.log4j.Log4j2; +import org.apache.commons.io.FileUtils; import org.jooq.*; import org.jooq.Record; import org.jooq.exception.DataAccessException; import org.jooq.impl.DSL; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.server.Encoding; +import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ResourceUtils; +import java.io.IOException; +import java.nio.file.Files; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import java.sql.Timestamp; import java.util.*; import java.util.stream.Collectors; import static org.jooq.impl.DSL.*; @Log4j2 +@Service public abstract class JdbcConnector implements DatabaseConnector { private final ImageMapper imageMapper; private final TableMapper tableMapper; - private final QueryMapper queryMapper; @Autowired - protected JdbcConnector(ImageMapper imageMapper, TableMapper tableMapper, QueryMapper queryMapper) { + protected JdbcConnector(ImageMapper imageMapper, TableMapper tableMapper) { this.imageMapper = imageMapper; this.tableMapper = tableMapper; - this.queryMapper = queryMapper; } @Override public DSLContext open(Database database) throws SQLException, ImageNotSupportedException { final String url = "jdbc:" + database.getContainer().getImage().getJdbcMethod() + "://" + database.getContainer().getInternalName() + "/" + database.getInternalName(); - log.info("Attempt to connect to '{}'", url); + log.trace("Attempt to connect to '{}'", url); final Properties properties = imageMapper.containerImageToProperties(database.getContainer().getImage()); final Connection connection = DriverManager.getConnection(url, properties); return DSL.using(connection, SQLDialect.valueOf(database.getContainer().getImage().getDialect())); @@ -54,7 +56,10 @@ public abstract class JdbcConnector implements DatabaseConnector { @Override public void create(Database database, TableCreateDto createDto) throws SQLException, - ArbitraryPrimaryKeysException, ImageNotSupportedException, TableMalformedException { + ArbitraryPrimaryKeysException, ImageNotSupportedException, TableMalformedException, IOException { + if (isReserved(createDto.getName())) { + throw new TableMalformedException("Table name contains reserved name"); + } final DSLContext context = open(database); CreateTableColumnStep createTableColumnStep = tableMapper.tableCreateDtoToCreateTableColumnStep(context, createDto); log.debug("Before insertion: {} ", createTableColumnStep.getSQL()); @@ -81,8 +86,8 @@ public abstract class JdbcConnector implements DatabaseConnector { throw new TableMalformedException("Provided columns differ from table columns found in metadata db."); } final List<Field<?>> headers = tableMapper.tableToFieldList(table); - log.trace("-> headers received {}", headers.stream().map(Field::getName).collect(Collectors.toList())); - log.trace("-> first row received {}", data.getData().size() > 0 ? data.getData().get(0) : null); + log.trace("headers received {}", headers.stream().map(Field::getName).collect(Collectors.toList())); + log.trace("first row received {}", data.getData().size() > 0 ? data.getData().get(0) : null); final DSLContext context = open(table.getDatabase()); final List<InsertValuesStepN<Record>> statements = new LinkedList<>(); for (List<Object> row : tableMapper.tableCsvDtoToObjectListList(data)) { @@ -93,7 +98,7 @@ public abstract class JdbcConnector implements DatabaseConnector { context.batch(statements) .execute(); } catch (DataAccessException e) { - throw new TableMalformedException("Columns seem to differ or other problem with jOOQ mapper", e); + throw new TableMalformedException("Columns seem to differ or other problem with jOOQ mapper, most commonly it is a data type issue try with type 'STRING'", e); } } @@ -103,4 +108,16 @@ public abstract class JdbcConnector implements DatabaseConnector { context.dropTable(table.getName()); } + /** + * Checks if the word is in the reserved word csv (i.e. a SQL keyword) + * + * @param word The word + * @return True if it is reserved word + */ + public Boolean isReserved(String word) throws IOException { + final List<String> reserved = FileUtils.readLines(ResourceUtils.getFile("classpath:mariadb/reserved.csv"), + Encoding.DEFAULT_CHARSET); + return reserved.contains(word.toUpperCase()); + } + } diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/impl/MariaDataService.java b/fda-table-service/services/src/main/java/at/tuwien/service/impl/MariaDataService.java index 3405b7fd2057cfb2a6b206527f03b00a9c166258..418f9ba106b9a9802442b311beb30988ce218b8c 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/impl/MariaDataService.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/impl/MariaDataService.java @@ -12,11 +12,14 @@ import at.tuwien.mapper.TableMapper; import at.tuwien.repository.jpa.DatabaseRepository; import at.tuwien.repository.jpa.TableRepository; import at.tuwien.service.DataService; +import at.tuwien.utils.FileUtils; import com.opencsv.CSVParser; import com.opencsv.CSVParserBuilder; import com.opencsv.CSVReader; import com.opencsv.CSVReaderBuilder; import com.opencsv.exceptions.CsvException; +import com.opencsv.exceptions.CsvValidationException; +import com.opencsv.validators.LineValidator; import lombok.NonNull; import lombok.extern.log4j.Log4j2; import org.jooq.DSLContext; @@ -27,9 +30,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.net.URI; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; import java.sql.SQLException; @@ -49,7 +55,7 @@ public class MariaDataService extends JdbcConnector implements DataService { @Autowired public MariaDataService(DatabaseRepository databaseRepository, TableRepository tableRepository, ImageMapper imageMapper, TableMapper tableMapper, QueryMapper queryMapper) { - super(imageMapper, tableMapper, queryMapper); + super(imageMapper, tableMapper); this.queryMapper = queryMapper; this.tableRepository = tableRepository; this.databaseRepository = databaseRepository; @@ -60,12 +66,26 @@ public class MariaDataService extends JdbcConnector implements DataService { public Table findById(Long databaseId, Long tableId) throws TableNotFoundException, DatabaseNotFoundException { final Optional<Table> table = tableRepository.findByDatabaseAndId(findDatabase(databaseId), tableId); if (table.isEmpty()) { - log.error("table {} not found in database {}", tableId, databaseId); + log.error("Table {} not found in database {}", tableId, databaseId); throw new TableNotFoundException("table not found in database"); } return table.get(); } + /** + * Only supports CSVs where the first line is either a header line or not and the remaining lines contain data. A + * comment block (e.g. {@literal https://sandbox.zenodo.org/api/files/1e8b8acb-7ef8-4437-8d96-7c15f6ef0ccc/2021-11-08T000000Z_N00009_G1_FN20ge_FRQ_WWV10.csv} + * is not supported right now + * + * @param databaseId The database. + * @param tableId The table. + * @param data The null element and delimiter. + * @throws TableNotFoundException + * @throws ImageNotSupportedException + * @throws DatabaseNotFoundException + * @throws FileStorageException + * @throws TableMalformedException + */ @Override @Transactional public void insertCsv(Long databaseId, Long tableId, TableInsertDto data) @@ -77,7 +97,7 @@ public class MariaDataService extends JdbcConnector implements DataService { values = readCsv(table, data); log.debug("read {} rows from csv", values.getData().size()); } catch (IOException | CsvException | ArrayIndexOutOfBoundsException e) { - log.error("failed to parse csv {}", e.getMessage()); + log.error("Failed to parse csv {}", e.getMessage()); throw new FileStorageException("failed to parse csv", e); } try { @@ -93,7 +113,7 @@ public class MariaDataService extends JdbcConnector implements DataService { protected Database findDatabase(Long id) throws DatabaseNotFoundException { final Optional<Database> database = databaseRepository.findById(id); if (database.isEmpty()) { - log.error("no database with this id found in metadata database"); + log.error("No database with this id found in metadata database"); throw new DatabaseNotFoundException("database not found in metadata database"); } return database.get(); @@ -103,46 +123,56 @@ public class MariaDataService extends JdbcConnector implements DataService { ArrayIndexOutOfBoundsException, TableMalformedException { log.debug("insert into table {} with params {}", table, data); if (data.getDelimiter() == null) { + log.info("No delimiter provided, using comma ','"); data.setDelimiter(','); } - if (!data.getCsvLocation().startsWith("test:")) { // todo: improve this? - data.setCsvLocation("/tmp/" + data.getCsvLocation()); + + if (!FileUtils.isTestFile(data.getCsvLocation())) { + if (!FileUtils.isUrl(data.getCsvLocation())) { + data.setCsvLocation("/tmp/" + data.getCsvLocation()); + } } else { + /* assume it is test file */ data.setCsvLocation(data.getCsvLocation().substring(5)); } final CSVParser csvParser = new CSVParserBuilder() .withSeparator(data.getDelimiter()) .build(); - final MultipartFile multipartFile = new MockMultipartFile(data.getCsvLocation(), - Files.readAllBytes(Paths.get(data.getCsvLocation()))); - final Reader fileReader = new InputStreamReader(multipartFile.getInputStream()); - final List<List<String>> cells = new LinkedList<>(); + + Reader fileReader; + if (FileUtils.isUrl(data.getCsvLocation())) { + /* source is remote file */ + fileReader = new BufferedReader(new InputStreamReader(URI.create(data.getCsvLocation()).toURL().openStream())); + } else { + /* source is local file */ + final MultipartFile multipartFile = new MockMultipartFile(data.getCsvLocation(), + Files.readAllBytes(Paths.get(data.getCsvLocation()))); + fileReader = new InputStreamReader(multipartFile.getInputStream()); + } + final CSVReader reader = new CSVReaderBuilder(fileReader) .withCSVParser(csvParser) .build(); - final List<Map<String, Object>> records = new LinkedList<>(); List<String> headers = null; + final LinkedList<List<String>> cells = new LinkedList<>(); reader.readAll() .forEach(x -> cells.add(Arrays.asList(x))); - log.trace("csv raw row size {}, cells raw size {}", reader.readAll().size(), cells.size()); + log.trace("csv rows {}", cells.size()); /* get header */ if (data.getSkipHeader()) { headers = cells.get(0); log.debug("got headers {}", headers); } if (headers != null && headers.size() != table.getColumns().size()) { + log.error("header size: {}, column size: {}", headers.size(), table.getColumns().size()); throw new TableMalformedException("Header size is not the same as cell size, maybe wrong delimiter?"); } + final List<Map<String, Object>> records = new LinkedList<>(); /* map to the map-list structure */ for (int i = (data.getSkipHeader() ? 1 : 0); i < cells.size(); i++) { - final Map<String, Object> record = new HashMap<>(); + final Map<String, Object> record = new LinkedHashMap<>(); final List<String> row = cells.get(i); for (int j = 0; j < table.getColumns().size(); j++) { - /* when no headers are available we cannot make safeness check */ - /* detect if order is correct, we depend on the CsvParser library */ - if (headers != null && table.getColumns().get(j).getInternalName().equals(headers.get(j))) { - log.error("header out of sync, actual: {} but expected: {}", headers.get(j), table.getColumns().get(j).getInternalName()); - } record.put(table.getColumns().get(j).getInternalName(), row.get(j)); } /* when the nullElement itself is null, nothing to do */ @@ -165,7 +195,7 @@ public class MariaDataService extends JdbcConnector implements DataService { try { insertCsv(table, data); } catch (SQLException e) { - log.error("could not insert data {}", e.getMessage()); + log.error("Could not insert data {}", e.getMessage()); throw new TableMalformedException("could not insert data", e); } } diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/fda-table-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java index 53572592bd2b55b3ec4c9e0cc907275de6cd400c..1b1f6cbb82eef0bc1deec256a4b94c0fb6d98be4 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java @@ -9,12 +9,10 @@ import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.exception.*; import at.tuwien.mapper.AmqpMapper; import at.tuwien.mapper.ImageMapper; -import at.tuwien.mapper.QueryMapper; import at.tuwien.mapper.TableMapper; import at.tuwien.repository.jpa.DatabaseRepository; import at.tuwien.repository.jpa.TableRepository; import at.tuwien.service.TableService; -import at.tuwien.service.impl.JdbcConnector; import com.opencsv.CSVParser; import com.opencsv.CSVParserBuilder; import com.opencsv.CSVReader; @@ -42,9 +40,8 @@ public class TableServiceImpl extends JdbcConnector implements TableService { @Autowired public TableServiceImpl(TableRepository tableRepository, DatabaseRepository databaseRepository, - ImageMapper imageMapper, TableMapper tableMapper, QueryMapper queryMapper, - AmqpMapper amqpMapper) { - super(imageMapper, tableMapper, queryMapper); + ImageMapper imageMapper, TableMapper tableMapper, AmqpMapper amqpMapper) { + super(imageMapper, tableMapper); this.tableRepository = tableRepository; this.databaseRepository = databaseRepository; this.tableMapper = tableMapper; @@ -110,7 +107,7 @@ public class TableServiceImpl extends JdbcConnector implements TableService { /* create database in container */ try { create(database, createDto); - } catch (SQLException e) { + } catch (SQLException | IOException e) { log.error("Could not create table via JDBC: {}", e.getMessage()); throw new DataProcessingException("could not create table", e); } diff --git a/fda-table-service/services/src/main/java/at/tuwien/utils/FileUtils.java b/fda-table-service/services/src/main/java/at/tuwien/utils/FileUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..74d3acee53fab6865c3564eb21b2b5a63fee9fee --- /dev/null +++ b/fda-table-service/services/src/main/java/at/tuwien/utils/FileUtils.java @@ -0,0 +1,12 @@ +package at.tuwien.utils; + +public class FileUtils { + + public static boolean isUrl(String data) { + return data.startsWith("http") || data.startsWith("https"); + } + + public static boolean isTestFile(String data) { + return data.startsWith("test:"); + } +} diff --git a/fda-ui/.gitignore b/fda-ui/.gitignore index 569f82cd2193eb684d173a120a35f2b2d87dfda8..9464986da15476fc16fac8486b0882c04e37fcce 100644 --- a/fda-ui/.gitignore +++ b/fda-ui/.gitignore @@ -6,6 +6,7 @@ yarn-debug.log* yarn-error.log* # Runtime data +ready pids *.pid *.seed diff --git a/fda-ui/.prod/default.conf b/fda-ui/.prod/default.conf new file mode 100644 index 0000000000000000000000000000000000000000..43a88f37d85a14ad680cfe0e2c2d483b8ba3bafc --- /dev/null +++ b/fda-ui/.prod/default.conf @@ -0,0 +1,30 @@ +server { + listen 3000 default_server; + server_name dbrepo.local; + proxy_set_header Host dbrepo.local; + + root /usr/share/nginx/html; + index index.html index.htm; + + location /api { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://fda-gateway-service:9095; + } + + location / { + root /usr/share/nginx/html; + try_files $uri $uri/ /index.html; + index index.html index.htm; + } + + # allow post on static pages + error_page 405 =200 $uri; + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + +} diff --git a/fda-ui/.prod/secure.conf b/fda-ui/.prod/secure.conf new file mode 100644 index 0000000000000000000000000000000000000000..402ce356e6f69ac6a322b36c7f3fe78672d6264f --- /dev/null +++ b/fda-ui/.prod/secure.conf @@ -0,0 +1,38 @@ +server { + listen 443 default_server; + server_name dbrepo.ossdip.at; + proxy_set_header Host dbrepo.ossdip.at; + + root /usr/share/nginx/html; + + index index.html; + location / { + root /usr/share/nginx/html; + try_files $uri $uri/ /index.html; + index index.html index.htm; + } + + location /api { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://fda-gateway-service:9095; + } + + location /server-middleware { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass https://fda-ui:443; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + ssl on; + ssl_certificate /etc/nginx/conf.d/cert.pem; + ssl_certificate_key /etc/nginx/conf.d/privkey.pem; + +} diff --git a/fda-ui/Dockerfile b/fda-ui/Dockerfile index 2f42c92b0c4e067746dd985ecb43491c15cd6750..09ab5071ecb34b90570661fd73283dc57853b254 100644 --- a/fda-ui/Dockerfile +++ b/fda-ui/Dockerfile @@ -26,11 +26,6 @@ COPY ./static ./static COPY ./store ./store COPY ./yarn.lock ./ -RUN yarn build - -# Minimize image & cleanup -RUN rm -rf /tmp/* - -EXPOSE 3000 +RUN yarn build > /dev/null ENTRYPOINT ["yarn", "start"] diff --git a/fda-ui/README.md b/fda-ui/README.md index fad6a2b81c2a6578cae10fcc485391a313589ad0..50b0454feff6ccb71ec382367fbd49de9cc863b1 100644 --- a/fda-ui/README.md +++ b/fda-ui/README.md @@ -41,7 +41,17 @@ See https://nuxtjs.org/ ## Prepare -Configure the `.env` file for the IP and port running. +Configure the `.env` file for the IP and port running or run through terminal: + +```bash +API=http://fda-gateway-service:9095 npm --prefix ./fda-ui run dev +``` + +Of course you need to add `fda-gateway-service` to your `/etc/hosts` file for Docker "DNS" to your containers: + +```bash +172.29.0.6 fda-gateway-service +``` ## Build Setup diff --git a/fda-ui/assets/img/zenodo-logo.png b/fda-ui/assets/img/zenodo-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d84adb8ed7016dfbfc297eb71cc24afbbf174693 Binary files /dev/null and b/fda-ui/assets/img/zenodo-logo.png differ diff --git a/fda-ui/components/.gitkeep b/fda-ui/components/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/fda-ui/components/DBToolbar.vue b/fda-ui/components/DBToolbar.vue index cd0a5769e97a0577ff06d4ca449b347258a11dc0..66189719a86373daad7b7965274899709360afc2 100644 --- a/fda-ui/components/DBToolbar.vue +++ b/fda-ui/components/DBToolbar.vue @@ -1,50 +1,80 @@ <template> - <v-toolbar v-if="db" flat> - <img id="engine-logo" :alt="`${db.image.repository}`" :src="`data:image/png;base64,${db.image.logo}`"> - <v-toolbar-title> - {{ db.name }} - </v-toolbar-title> - <v-spacer /> - <v-toolbar-title> - <v-btn :to="`/databases/${$route.params.database_id}/tables/import`" class="mr-2"> - <v-icon left>mdi-cloud-upload</v-icon> Import CSV - </v-btn> - <v-btn color="blue-grey" :to="`/databases/${$route.params.database_id}/queries/create`" class="mr-2 white--text"> - <v-icon left>mdi-wrench</v-icon> Query Builder - </v-btn> - <v-btn color="primary" :to="`/databases/${$route.params.database_id}/tables/create`"> - <v-icon left>mdi-table-large-plus</v-icon> Create Table - </v-btn> - </v-toolbar-title> - <template v-slot:extension> - <v-tabs v-model="tab" color="primary"> - <v-tab :to="`/databases/${$route.params.database_id}/info`"> - Info - </v-tab> - <v-tab :to="`/databases/${$route.params.database_id}/tables/`"> - Tables - </v-tab> - <v-tab :to="`/databases/${$route.params.database_id}/queries/`"> - Queries - </v-tab> - <v-tab :to="`/databases/${$route.params.database_id}/admin/`"> - Admin - </v-tab> - </v-tabs> - </template> - </v-toolbar> + <div> + <v-progress-linear v-if="loading" :color="loadingColor" :indeterminate="!error" /> + <v-toolbar v-if="db" flat> + <img id="engine-logo" :alt="`${db.image.repository}`" :src="`data:image/png;base64,${db.image.logo}`"> + <v-toolbar-title> + {{ db.name }} + </v-toolbar-title> + <v-spacer /> + <v-toolbar-title> + <v-btn :to="`/databases/${databaseId}/tables/import`" class="mr-2"> + <v-icon left>mdi-cloud-upload</v-icon> Import CSV + </v-btn> + <v-btn color="blue-grey" :to="`/databases/${databaseId}/queries/create`" class="mr-2 white--text"> + <v-icon left>mdi-wrench</v-icon> Query Builder + </v-btn> + <v-btn color="primary" :to="`/databases/${databaseId}/tables/create`"> + <v-icon left>mdi-table-large-plus</v-icon> Create Table + </v-btn> + </v-toolbar-title> + <template v-slot:extension> + <v-tabs v-model="tab" color="primary"> + <v-tab :to="`/databases/${databaseId}/info`"> + Info + </v-tab> + <v-tab :to="`/databases/${databaseId}/tables`"> + Tables + </v-tab> + <v-tab :to="`/databases/${databaseId}/queries`"> + Queries + </v-tab> + <v-tab :to="`/databases/${databaseId}/admin`"> + Admin + </v-tab> + </v-tabs> + </template> + </v-toolbar> + </div> </template> <script> export default { data () { return { - tab: null + tab: null, + loading: false } }, computed: { db () { return this.$store.state.db + }, + databaseId () { + return this.$route.params.database_id + }, + loadingColor () { + return this.error ? 'red lighten-2' : 'primary' + } + }, + mounted () { + this.init() + }, + methods: { + async init () { + if (this.db != null) { + return + } + try { + this.loading = true + const res = await this.$axios.get(`/api/database/${this.$route.params.database_id}`) + console.debug('database', res.data) + this.$store.commit('SET_DATABASE', res.data) + this.loading = false + } catch (err) { + this.$toast.error('Could not load database.') + this.loading = false + } } } } diff --git a/fda-ui/components/QueryList.vue b/fda-ui/components/QueryList.vue index c2a5759d2abe15c1c54f0348c01ca8ac246a3392..85b2ed0fa92f707f3ace53c91ba5de0b25f41235 100644 --- a/fda-ui/components/QueryList.vue +++ b/fda-ui/components/QueryList.vue @@ -1,86 +1,88 @@ <template> <div> - <v-card v-if="queries.length === 0" flat> - <v-card-title> - (no queries) - </v-card-title> - </v-card> - <v-expansion-panels v-if="queries.length > 0" accordion> - <v-expansion-panel v-for="(item, i) in queries" :key="i" @click="details(item)"> - <v-expansion-panel-header> - {{ item.query }} - </v-expansion-panel-header> - <v-expansion-panel-content> - <v-row dense> - <v-col> - <v-list dense> - <v-list-item> - <v-list-item-icon> - <v-icon>mdi-information-variant</v-icon> - </v-list-item-icon> - <v-list-item-content> - <v-list-item-title> - ID: {{ queryDetails.id }} - </v-list-item-title> - </v-list-item-content> - </v-list-item> - <v-list-item> - <v-list-item-icon> - <v-icon>mdi-fingerprint</v-icon> - </v-list-item-icon> - <v-list-item-content> - <v-list-item-title> - DOI: <code v-if="queryDetails.doi">{{ queryDetails.doi }}</code> - <span v-if="!queryDetails.doi">(no identifier issued)</span> - </v-list-item-title> - </v-list-item-content> - </v-list-item> - <v-list-item> - <v-list-item-icon> - <v-icon>mdi-api</v-icon> - </v-list-item-icon> - <v-list-item-content> - <v-list-item-title> - Query Hash: <code>{{ queryDetails.queryHash }}</code> - </v-list-item-title> - </v-list-item-content> - </v-list-item> - <v-list-item> - <v-list-item-icon> - <v-icon>mdi-clock-outline</v-icon> - </v-list-item-icon> - <v-list-item-content> - <v-list-item-title> - Execution Timestamp: {{ queryDetails.executionTimestamp }} - </v-list-item-title> - </v-list-item-content> - </v-list-item> - <v-list-item> - <v-list-item-icon> - <v-icon>mdi-content-save</v-icon> - </v-list-item-icon> - <v-list-item-content> - <v-list-item-title> - Query: <code>{{ queryDetails.query }}</code> - </v-list-item-title> - </v-list-item-content> - </v-list-item> - </v-list> - </v-col> - </v-row> - <v-row dense> - <v-col> - <v-btn color="primary" :to="`/databases/${$route.params.database_id}/queries/${item.id}`"> - <v-icon left>mdi-run</v-icon> Execute Again - </v-btn> - <v-btn color="primary" :to="`/databases/${$route.params.database_id}/queries/${item.id}/metadata`"> - <v-icon left>mdi-doi</v-icon> Issue DOI - </v-btn> - </v-col> - </v-row> - </v-expansion-panel-content> - </v-expansion-panel> - </v-expansion-panels> + <v-tabs-items> + <v-card v-if="!loading && queries.length === 0" flat> + <v-card-title> + (no queries) + </v-card-title> + </v-card> + <v-expansion-panels v-if="!loading && queries.length > 0" accordion> + <v-expansion-panel v-for="(item, i) in queries" :key="i" @click="details(item)"> + <v-expansion-panel-header> + {{ item.title }} + </v-expansion-panel-header> + <v-expansion-panel-content> + <v-row dense> + <v-col> + <v-list dense> + <v-list-item> + <v-list-item-icon> + <v-icon>mdi-information-variant</v-icon> + </v-list-item-icon> + <v-list-item-content> + <v-list-item-title> + ID: {{ queryDetails.id }} + </v-list-item-title> + </v-list-item-content> + </v-list-item> + <v-list-item> + <v-list-item-icon> + <v-icon>mdi-fingerprint</v-icon> + </v-list-item-icon> + <v-list-item-content> + <v-list-item-title> + DOI: <code v-if="queryDetails.doi">{{ queryDetails.doi }}</code> + <span v-if="!queryDetails.doi">(no identifier issued)</span> + </v-list-item-title> + </v-list-item-content> + </v-list-item> + <v-list-item> + <v-list-item-icon> + <v-icon>mdi-api</v-icon> + </v-list-item-icon> + <v-list-item-content> + <v-list-item-title> + Query Hash: <code>{{ queryDetails.queryHash }}</code> + </v-list-item-title> + </v-list-item-content> + </v-list-item> + <v-list-item> + <v-list-item-icon> + <v-icon>mdi-clock-outline</v-icon> + </v-list-item-icon> + <v-list-item-content> + <v-list-item-title> + Execution Timestamp: {{ queryDetails.executionTimestamp }} + </v-list-item-title> + </v-list-item-content> + </v-list-item> + <v-list-item> + <v-list-item-icon> + <v-icon>mdi-content-save</v-icon> + </v-list-item-icon> + <v-list-item-content> + <v-list-item-title> + Query: <code>{{ queryDetails.query }}</code> + </v-list-item-title> + </v-list-item-content> + </v-list-item> + </v-list> + </v-col> + </v-row> + <v-row dense> + <v-col> + <v-btn color="primary" :to="`/databases/${databaseId}/queries/${item.id}`"> + <v-icon left>mdi-run</v-icon> Execute Again + </v-btn> + <v-btn :disabled="queryDetails.doi" :to="`/databases/${databaseId}/queries/${item.id}/metadata`"> + <v-icon left>mdi-fingerprint</v-icon> Cite Dataset + </v-btn> + </v-col> + </v-row> + </v-expansion-panel-content> + </v-expansion-panel> + </v-expansion-panels> + </v-tabs-items> </div> </template> @@ -88,6 +90,7 @@ export default { data () { return { + loading: false, queries: [], queryDetails: { id: null, @@ -98,6 +101,11 @@ export default { } } }, + computed: { + databaseId () { + return this.$route.params.database_id + } + }, mounted () { this.$root.$on('query-create', this.refresh) this.refresh() @@ -107,9 +115,11 @@ export default { // XXX same as in QueryBuilder let res try { - res = await this.$axios.get(`/api/database/${this.$route.params.database_id}/querystore`) + this.loading = true + res = await this.$axios.get(`/api/database/${this.databaseId}/metadata/query`) console.debug('queries', res) this.queries = res.data + this.loading = false } catch (err) { this.$toast.error('Could not list queries.') } diff --git a/fda-ui/components/TableList.vue b/fda-ui/components/TableList.vue index 644075390dd114ec852688142ff2c4492a4b81b4..748234ed0323edf4f8d7039ba26b1825c11d9673 100644 --- a/fda-ui/components/TableList.vue +++ b/fda-ui/components/TableList.vue @@ -1,11 +1,11 @@ <template> <div> - <v-card v-if="tables.length === 0" flat> + <v-card v-if="!loading && tables.length === 0" flat> <v-card-title> (no tables) </v-card-title> </v-card> - <v-expansion-panels v-if="tables.length > 0" accordion> + <v-expansion-panels v-if="!loading && tables.length > 0" accordion> <v-expansion-panel v-for="(item,i) in tables" :key="i" @click="details(item)"> <v-expansion-panel-header> {{ item.name }} @@ -135,6 +135,7 @@ export default { data () { return { + loading: false, tables: [], tableDetails: { id: 0 }, dialogDelete: false @@ -162,15 +163,19 @@ export default { // XXX same as in QueryBuilder let res try { + this.loading = true res = await this.$axios.get(`/api/database/${this.$route.params.database_id}/table`) this.tables = res.data + this.loading = false } catch (err) { this.$toast.error('Could not list table.') } }, async deleteTable () { try { + this.loading = true await this.$axios.delete(`/api/database/${this.$route.params.database_id}/table/${this.deleteTableId}`) + this.loading = false this.refresh() } catch (err) { this.$toast.error('Could not delete table.') diff --git a/fda-ui/components/dialogs/CreateDB.vue b/fda-ui/components/dialogs/CreateDB.vue index 44dc2864750d752e9609420c92713d59b1c40b44..93beb9d4393c565574bbcd502764c324718f6c80 100644 --- a/fda-ui/components/dialogs/CreateDB.vue +++ b/fda-ui/components/dialogs/CreateDB.vue @@ -1,66 +1,68 @@ <template> - <v-card> - <v-card-title> - Create Database - </v-card-title> - <v-card-text> - <v-alert - border="left" - color="amber lighten-4"> - Choose an expressive database name and select a database engine. - </v-alert> - <v-form v-model="formValid" autocomplete="off"> - <v-text-field - id="database" - v-model="database" - name="database" - label="Database Name" - :rules="[v => !!v || $t('Required')]" - required /> - <v-textarea - id="description" - v-model="description" - name="description" - rows="2" - label="Database Description" - :rules="[v => !!v || $t('Required')]" - required /> - <v-select - id="engine" - v-model="engine" - name="engine" - label="Database Engine" - :items="engines" - item-text="label" - :rules="[v => !!v || $t('Required')]" - return-object - required /> - <v-checkbox - id="public" - v-model="isPublic" - name="public" - disabled - label="Public" /> - </v-form> - </v-card-text> - <v-card-actions> - <v-spacer /> - <v-btn - class="mb-2" - @click="cancel"> - Cancel - </v-btn> - <v-btn - id="createDB" - class="mb-2" - :disabled="!formValid" - :loading="loading" - color="primary" - @click="createDB"> - Create - </v-btn> - </v-card-actions> - </v-card> + <div> + <v-progress-linear v-if="loading" :color="loadingColor" :indeterminate="!error" /> + <v-card> + <v-card-title> + Create Database + </v-card-title> + <v-card-text> + <v-alert + border="left" + color="amber lighten-4"> + Choose an expressive database name and select a database engine. + </v-alert> + <v-form v-model="formValid" autocomplete="off"> + <v-text-field + id="database" + v-model="database" + name="database" + label="Database Name" + :rules="[v => !!v || $t('Required')]" + required /> + <v-textarea + id="description" + v-model="description" + name="description" + rows="2" + label="Database Description" + :rules="[v => !!v || $t('Required')]" + required /> + <v-select + id="engine" + v-model="engine" + name="engine" + label="Database Engine" + :items="engines" + item-text="label" + :rules="[v => !!v || $t('Required')]" + return-object + required /> + <v-checkbox + id="public" + v-model="isPublic" + name="public" + disabled + label="Public" /> + </v-form> + </v-card-text> + <v-card-actions> + <v-spacer /> + <v-btn + class="mb-2" + @click="cancel"> + Cancel + </v-btn> + <v-btn + id="createDB" + class="mb-2" + :disabled="!formValid || loading" + color="primary" + @click="createDB"> + Create + </v-btn> + </v-card-actions> + </v-card> + </div> </template> <script> @@ -69,6 +71,7 @@ export default { return { formValid: false, loading: false, + error: false, database: null, description: null, isPublic: true, @@ -77,6 +80,11 @@ export default { container: null } }, + computed: { + loadingColor () { + return this.error ? 'red lighten-2' : 'primary' + } + }, beforeMount () { this.getImages() }, @@ -85,16 +93,19 @@ export default { this.$parent.$parent.$parent.$parent.createDbDialog = false }, async getImages () { - this.loading = true let res try { + this.loading = true + this.error = false res = await this.$axios.get('/api/image/') this.engines = res.data.map((e) => { e.disabled = (e.id !== 3) return e }) console.debug('engines', this.engines) + this.loading = false } catch (err) { + this.error = true this.$toast.error('Failed to fetch supported engines. Try reload the page.') } this.loading = false @@ -105,12 +116,13 @@ export default { }) }, async createDB () { - this.loading = true let res // create a container let containerId console.debug('model', this.engine) try { + this.loading = true + this.error = false res = await this.$axios.post('/api/container/', { name: this.database, description: this.description, @@ -119,20 +131,23 @@ export default { }) containerId = res.data.id console.debug('created container', res.data) + this.loading = false } catch (err) { + this.error = true this.$toast.error('Could not create container. Try another name.') - this.loading = false return } // start the container try { + this.loading = true + this.error = false res = await this.$axios.put(`/api/container/${containerId}`, { action: 'START' }) console.debug('started container', res.data) } catch (err) { - this.loading = false + this.error = true this.$toast.error('Could not start container.') return } @@ -141,7 +156,9 @@ export default { // DB fails to create when container has not started up yet await new Promise(resolve => setTimeout(resolve, 2000)) - // create the DB + // wait for it to finish + this.loading = true + this.error = false for (let i = 0; i < 30; i++) { try { res = await this.$axios.post('/api/database/', { @@ -153,16 +170,18 @@ export default { i = 31 } catch (err) { console.debug('wait', res) - await this.sleep(1000) + await this.sleep(3000) } } - this.loading = false if (res.status !== 201) { + this.error = true this.$toast.error('Could not create database.') return } + this.loading = false this.$toast.success(`Database "${res.data.name}" created.`) - this.$emit('refresh') + // this.$emit('refresh') + await this.$router.push(`/databases/${containerId}/info`) } } } diff --git a/fda-ui/components/query/Builder.vue b/fda-ui/components/query/Builder.vue index e6d01bf97093b84dc442b6014104d1e698ec1dff..f52bfb2d7010dc20c3f96d8c3882e04f03513057 100644 --- a/fda-ui/components/query/Builder.vue +++ b/fda-ui/components/query/Builder.vue @@ -1,53 +1,89 @@ <template> <div> - <v-row dense> - <v-col cols="6"> - <v-select - v-model="table" - :items="tables" - item-text="name" - return-object - label="Table" - @change="loadColumns" /> - </v-col> - <v-col cols="6"> - <v-select - v-model="select" - item-text="name" - :disabled="!table" - :items="selectItems" - label="Columns" - return-object - multiple - @change="buildQuery" /> - </v-col> - </v-row> - <!-- <QueryFilters--> - <!-- v-if="table"--> - <!-- v-model="clauses"--> - <!-- :columns="columnNames" />--> - <v-row v-if="query.formatted"> - <v-col> - <highlightjs autodetect :code="query.formatted" /> - </v-col> - <v-col cols="3" class="actions"> - <v-btn class="execute" color="primary" @click="execute"> - <v-icon>mdi-refresh</v-icon> - Execute - </v-btn> - </v-col> - </v-row> - <v-row> - <v-col> - <p>Results</p> - <v-data-table - :headers="result.headers" - :items="result.rows" - :loading="loading" - :items-per-page="30" - class="elevation-1" /> - </v-col> - </v-row> + <v-form + ref="form" + v-model="valid" + lazy-validation> + <v-toolbar flat> + <v-toolbar-title>Create Query</v-toolbar-title> + <v-spacer /> + <v-toolbar-title> + <v-btn :disabled="!valid" @click="save"> + Save without execution + </v-btn> + <v-btn :disabled="!valid" color="primary" @click="execute"> + <v-icon left>mdi-run</v-icon> + Execute + </v-btn> + </v-toolbar-title> + </v-toolbar> + <v-card flat> + <v-card-text> + <v-row class="mt-2"> + <v-col cols="6"> + <v-text-field + v-model="title" + :rules="[rules.required, rules.titleMin]" + class="pa-0" + label="Query Title" + required /> + </v-col> + </v-row> + <v-row class="mt-2"> + <v-col cols="6"> + <v-select + v-model="table" + :rules="[rules.required]" + :items="tables" + item-text="name" + return-object + label="Table" + @change="loadColumns" /> + </v-col> + <v-col cols="6"> + <v-select + v-model="select" + :rules="[rules.required]" + item-text="name" + :disabled="!table" + :items="selectItems" + label="Columns" + return-object + multiple + @change="buildQuery" /> + </v-col> + </v-row> + <!-- <QueryFilters--> + <!-- v-if="table"--> + <!-- v-model="clauses"--> + <!-- :columns="columnNames" />--> + <v-row v-if="query.formatted"> + <v-col> + <highlightjs autodetect :code="query.formatted" /> + </v-col> + </v-row> + <v-row> + <v-col> + <p>Results</p> + <v-data-table + :headers="result.headers" + :items="result.rows" + :loading="loading" + :items-per-page="30" + class="elevation-1" /> + </v-col> + </v-row> + <v-row> + <v-col> + <v-btn v-if="queryId" color="primary" :to="`/databases/${databaseId}/queries/${queryId}`"> + <v-icon left>mdi-fingerprint</v-icon> + Obtain Query DOI + </v-btn> + </v-col> + </v-row> + </v-card-text> + </v-card> + </v-form> </div> </template> @@ -55,16 +91,25 @@ export default { data () { return { + valid: false, table: null, tables: [], + title: null, tableDetails: null, - query: {}, + queryId: null, + query: { + sql: '' + }, select: [], clauses: [], result: { headers: [], rows: [] }, + rules: { + required: value => !!value || 'Required', + titleMin: value => (value || '').length >= 10 || 'Minimum 10 characters' + }, loading: false } }, @@ -75,6 +120,12 @@ export default { }, columnNames () { return this.selectItems && this.selectItems.map(s => s.name) + }, + databaseId () { + return this.$route.params.database_id + }, + tableId () { + return this.table.id } }, watch: { @@ -89,23 +140,27 @@ export default { // XXX same as in TableList try { const res = await this.$axios.get( - `/api/database/${this.$route.params.database_id}/table`) + `/api/database/${this.databaseId}/table`) this.tables = res.data + console.debug('tables', this.tables) } catch (err) { this.$toast.error('Could not list table.') } }, methods: { async execute () { + this.$refs.form.validate() const query = this.query.sql.replaceAll('`', '') this.loading = true try { - const res = await this.$axios.put(`/api/database/${this.$route.params.database_id}/query`, { - Query: query + const res = await this.$axios.put(`/api/database/${this.databaseId}/store/table/${this.tableId}/execute`, { + title: this.title, + query }) console.debug('query result', res) this.$toast.success('Successfully executed query') this.loading = false + this.queryId = res.data.id this.result.headers = this.select.map((s) => { return { text: s.name, value: 'mdb_' + s.name, sortable: false } }) @@ -116,6 +171,24 @@ export default { this.loading = false } }, + async save () { + this.$refs.form.validate() + const query = this.query.sql.replaceAll('`', '') + this.loading = true + try { + const res = await this.$axios.put(`/api/database/${this.databaseId}/store/table/${this.tableId}/save`, { + Query: query + }) + console.debug('query result', res) + this.$toast.success('Successfully saved query') + this.loading = false + this.queryId = res.data.id + } catch (err) { + console.error('query save', err) + this.$toast.error('Could not save query') + this.loading = false + } + }, async buildQuery () { if (!this.table) { return @@ -138,7 +211,7 @@ export default { async loadColumns () { const tableId = this.table.id try { - const res = await this.$axios.get(`/api/database/${this.$route.params.database_id}/table/${tableId}`) + const res = await this.$axios.get(`/api/database/${this.databaseId}/table/${tableId}`) this.tableDetails = res.data this.buildQuery() } catch (err) { @@ -157,9 +230,4 @@ main.scss file from vuetify, because it paints it red */ color: #657b83; } -.actions { - align-items: center; - display: flex; - justify-content: center; -} </style> diff --git a/fda-ui/layouts/default.vue b/fda-ui/layouts/default.vue index 242fbdd34ff9615ed6bf6a3dcb62e62f37c0b08f..049bed75995c0ae5d27ea3f91b076910e3b42b64 100644 --- a/fda-ui/layouts/default.vue +++ b/fda-ui/layouts/default.vue @@ -6,8 +6,7 @@ v-for="(item, i) in filteredItems" :key="i" :to="item.to" - router - exact> + router> <v-list-item-action> <v-icon>{{ item.icon }}</v-icon> </v-list-item-action> @@ -21,6 +20,12 @@ <v-app-bar-nav-icon @click.stop="drawer = !drawer" /> <v-toolbar-title v-text="title" /> <v-spacer /> + <v-btn + color="blue-grey" + @click="authenticate" + class="mr-2 white--text"> + <v-icon left>mdi-login</v-icon> Login + </v-btn> <v-menu bottom offset-y left> <template v-slot:activator="{ on, attrs }"> <v-btn @@ -30,7 +35,6 @@ <v-icon>mdi-dots-vertical</v-icon> </v-btn> </template> - <v-list> <v-list-item v-for="locale in availableLocales" @@ -46,6 +50,17 @@ <nuxt /> </v-container> </v-main> + <v-footer padless v-if="sandbox"> + <v-card + flat + tile + width="100%" + class="amber lighten-3 text-center"> + <v-card-text> + <strong>Sandbox Environment</strong> — Reset in {{ timer }} — <a href="//github.com/fair-data-austria/dbrepo/issues/new">Report a bug</a> + </v-card-text> + </v-card> + </v-footer> </v-app> </template> @@ -63,6 +78,7 @@ export default { data () { return { drawer: false, + countDown: 1, items: [ { icon: mdiHome, @@ -100,6 +116,9 @@ export default { availableLocales () { return this.$i18n.locales.filter(i => i.code !== this.$i18n.locale) }, + sandbox () { + return true + }, container () { return this.$store.state.container }, @@ -111,6 +130,12 @@ export default { }, db () { return this.$store.state.db + }, + timer () { + const hours = Math.floor(this.countDown / 3600) + const minutes = Math.floor((this.countDown - hours * 3600) / 60) + const seconds = (this.countDown - hours * 3600 - minutes * 60) + return `${hours}h${minutes}m${seconds}s` } }, watch: { @@ -120,8 +145,27 @@ export default { }, mounted () { this.loadDB() + this.countDownTimer() + this.initDownTimer() }, methods: { + authenticate () { + window.location.href = '/api/auth' + }, + initDownTimer () { + const two = new Date() + two.setDate(new Date().getDate() + 1) + two.setHours(2, 0, 0, 0) + this.countDown = Math.floor((two - new Date()) / 1000) + }, + countDownTimer () { + if (this.countDown > 0) { + setTimeout(() => { + this.countDown -= 1 + this.countDownTimer() + }, 1000) + } + }, async loadDB () { if (this.$route.params.db_id && !this.db) { try { @@ -135,3 +179,5 @@ export default { } } </script> +<style scoped> +</style> diff --git a/fda-ui/nuxt.config.js b/fda-ui/nuxt.config.js index 4d8d1c33b78e3298a68d2b682cd3029c81a26669..2f06eef8cef5ce0a8ea3b795cfee66a733913791 100644 --- a/fda-ui/nuxt.config.js +++ b/fda-ui/nuxt.config.js @@ -1,3 +1,4 @@ +import fs from 'fs' import path from 'path' import colors from 'vuetify/es5/util/colors' @@ -5,19 +6,35 @@ import colors from 'vuetify/es5/util/colors' require('dotenv').config() if (!process.env.API) { - throw new Error(`Environment variable API_CONTAINER not defined. + throw new Error(`Environment variable API not defined. Have you passed env vars from docker-compose or defined them in your .env file?`) } +let serv = { + port: 3000, + host: '0.0.0.0', + timing: false +} +if (process.env.SECURE) { + serv = { + https: { + key: fs.readFileSync('/certs/privkey.pem'), + cert: fs.readFileSync('/certs/cert.pem') + } + } +} + export default { target: 'server', telemetry: false, + server: serv, + head: { - titleTemplate: '%s - fda-ui', - title: 'fda-ui', + titleTemplate: '%s - Database Repository (Sandbox)', + title: 'FAIR Data Austria', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, diff --git a/fda-ui/pages/databases/_database_id/admin.vue b/fda-ui/pages/databases/_database_id/admin.vue index 073de41676f1e2aaa8417573368308e9f35abbf7..04fd981323c7b078847ba705283da30e355cb768 100644 --- a/fda-ui/pages/databases/_database_id/admin.vue +++ b/fda-ui/pages/databases/_database_id/admin.vue @@ -1,14 +1,16 @@ <template> <div v-if="db"> <DBToolbar /> - <v-card> - <v-card-title> - Database Administration - </v-card-title> - <v-card-text> - <v-btn outlined color="error" @click="dialogDelete = true">Delete</v-btn> - </v-card-text> - </v-card> + <v-tabs-items v-model="tab"> + <v-card flat> + <v-card-title> + Database Administration + </v-card-title> + <v-card-text> + <v-btn outlined color="error" @click="dialogDelete = true">Delete</v-btn> + </v-card-text> + </v-card> + </v-tabs-items> <v-dialog v-model="dialogDelete" max-width="500"> <v-card> <v-card-title class="headline"> @@ -47,6 +49,9 @@ export default { } }, computed: { + tab () { + return 3 + }, db () { return this.$store.state.db }, @@ -57,6 +62,9 @@ export default { return this.confirm !== this.db.internalName } }, + mounted () { + this.init() + }, methods: { async deleteDatabase () { try { @@ -67,6 +75,21 @@ export default { this.$toast.error('Could not delete database.') } this.dialogDelete = false + }, + async init () { + if (this.db != null) { + return + } + try { + this.loading = true + const res = await this.$axios.get(`/api/database/${this.$route.params.database_id}`) + console.debug('database', res.data) + this.$store.commit('SET_DATABASE', res.data) + this.loading = false + } catch (err) { + this.$toast.error('Could not load database.') + this.loading = false + } } } } diff --git a/fda-ui/pages/databases/_database_id/index.vue b/fda-ui/pages/databases/_database_id/index.vue deleted file mode 100644 index 0ddfdbebe745a4c9ec3348985a8d36f11cc05f14..0000000000000000000000000000000000000000 --- a/fda-ui/pages/databases/_database_id/index.vue +++ /dev/null @@ -1,3 +0,0 @@ -<template> - <nuxt-link :to="`/databases/${this.$route.params.database_id}/info`">Info</nuxt-link> -</template> diff --git a/fda-ui/pages/databases/_database_id/info.vue b/fda-ui/pages/databases/_database_id/info.vue index 79546f24e45f31d9575437286fc9c6cf2e624146..ebe17517db3b69a97921d402bbdad71cf1b61494 100644 --- a/fda-ui/pages/databases/_database_id/info.vue +++ b/fda-ui/pages/databases/_database_id/info.vue @@ -5,7 +5,8 @@ <v-tab-item> <v-card flat> <v-card-title> - {{ db.internalName }} + <span>{{ db.internalName }}</span> + <v-progress-circular v-if="loading" :size="20" :width="3" indeterminate color="primary" /> </v-card-title> <v-card-subtitle> {{ publisher }}, {{ db.image.repository }}:{{ db.image.tag }} @@ -14,9 +15,9 @@ <blockquote> <p>{{ description }}</p> </blockquote> - <p> + <span> Created {{ db.created }} - </p> + </span> </v-card-text> </v-card> </v-tab-item> @@ -33,10 +34,13 @@ export default { }, data () { return { - tab: 0 + loading: false } }, computed: { + tab () { + return 0 + }, db () { return this.$store.state.db }, @@ -47,13 +51,24 @@ export default { return this.db.publisher === null ? '(no publisher)' : this.db.publisher } }, - async mounted () { - try { - const res = await this.$axios.get(`/api/database/${this.$route.params.database_id}`) - console.debug('database', res.data) - this.$store.commit('SET_DATABASE', res.data) - } catch (err) { - this.$toast.error('Could not load database.') + mounted () { + this.init() + }, + methods: { + async init () { + if (this.db != null) { + return + } + try { + this.loading = true + const res = await this.$axios.get(`/api/database/${this.$route.params.database_id}`) + console.debug('database', res.data) + this.$store.commit('SET_DATABASE', res.data) + this.loading = false + } catch (err) { + this.$toast.error('Could not load database.') + this.loading = false + } } } } diff --git a/fda-ui/pages/databases/_database_id/queries/_query_id/metadata.vue b/fda-ui/pages/databases/_database_id/queries/_query_id/metadata.vue index c9caf90e8e0d78048c68130740bc2da4650f54d9..a4693e0b98ba79f1c6b8c1e49ac2a5049aa40d69 100644 --- a/fda-ui/pages/databases/_database_id/queries/_query_id/metadata.vue +++ b/fda-ui/pages/databases/_database_id/queries/_query_id/metadata.vue @@ -1,34 +1,238 @@ <template> <div> - <v-card> - <v-card-title v-if="!loading"> - Metadata - </v-card-title> - <v-card-subtitle v-if="!loading"> - Subtitle - </v-card-subtitle> - <div> - aaa - </div> - </v-card> + <v-progress-linear v-if="loading" :color="loadingColor" :indeterminate="!error" /> + <v-toolbar flat> + <v-btn id="zenodo-logo" class="mr-2" :style="`background-image:url(${zenodoLogo});`" disabled /> + <v-toolbar-title>Cite Query No. {{ queryId }}</v-toolbar-title> + <v-spacer /> + <v-toolbar-title> + <v-btn color="primary" :disabled="!valid" @click="submit()"> + <v-icon left>mdi-publish</v-icon> + Publish + </v-btn> + </v-toolbar-title> + </v-toolbar> + <v-form + ref="form" + v-model="valid" + lazy-validation> + <v-card flat> + <v-card-subtitle v-if="!loading"> + Executed {{ query.execution_timestamp }} + </v-card-subtitle> + <v-card-text> + <v-alert + v-if="query.query" + border="left" + class="mb-6" + color="amber lighten-4"> + <pre>{{ query.query }}</pre> + </v-alert> + <v-select + v-model="data.metadata.access_right" + :items="accessRights" + item-text="name" + item-value="value" + class="col-lg-6 col-md-8 pa-0" + label="Access Right" /> + <v-text-field + v-model="data.metadata.title" + class="pa-0" + :rules="[rules.required]" + disabled + label="Query Title" + required /> + <v-textarea + v-model="data.metadata.description" + class="pa-0 mt-4" + :rules="[rules.required, rules.descriptionMin]" + label="Query Description" + counter + rows="4" + hint="Minimum 100 Characters" + required /> + </v-card-text> + </v-card> + <v-card class="space mt-4" flat> + <v-card-text> + <v-row v-for="(author,i) in data.metadata.creators" :key="i"> + <v-col + cols="12" + md="4"> + <v-text-field + v-model="author.name" + :rules="[rules.required]" + class="pa-0" + label="Firstname Surname" + required /> + </v-col> + <v-col + cols="12" + md="4"> + <v-text-field + v-model="author.affiliation" + :rules="[rules.required]" + class="pa-0" + label="Affiliation" + required /> + </v-col> + <v-col + cols="12" + :md="i !== 0 ? 3 : 4"> + <v-text-field + v-model="author.orcid" + class="pa-0" + label="ORCiD" + required /> + </v-col> + <v-col + v-if="i !== 0" + cols="12" + md="1"> + <v-btn @click="removeAuthor(i)">Remove</v-btn> + </v-col> + </v-row> + </v-card-text> + </v-card> + <v-btn color="blue-grey" class="mt-4 mb-4 white--text" @click="addAuthor()"> + <v-icon left>mdi-plus</v-icon> + Add Author + </v-btn> + </v-form> </div> </template> <script> export default { name: 'QueryDoiMetadata', - components: { - }, + components: {}, data () { return { - loading: false + loading: false, + error: false, + valid: false, + data: { + metadata: { + access_right: 'open', + creators: [{ + name: null, + affiliation: null, + orcid: null + }], + title: null, + description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', + upload_type: 'dataset' + } + }, + query: { + hash: null, + query: null, + execution_timestamp: null, + result_hash: null, + result_number: null, + doi: null + }, + rules: { + required: value => !!value || 'Required', + descriptionMin: value => (value || '').length >= 100 || 'Minimum 100 characters' + } + } + }, + computed: { + databaseId () { + return this.$route.params.database_id + }, + queryId () { + return this.$route.params.query_id + }, + accessRights () { + return [ + { name: 'Open', value: 'open', disabled: false }, + { name: 'Closed', value: 'closed', disabled: true }, + { name: 'Restricted', value: 'restricted', disabled: true }, + { name: 'Embargoed', value: 'embargoed', disabled: true } + ] + }, + zenodoLogo () { + return require('assets/img/zenodo-logo.png') + }, + loadingColor () { + return this.error ? 'red lighten-2' : 'primary' } }, mounted () { + this.loadData() }, methods: { + async loadData () { + try { + this.loading = true + const res = await this.$axios.get(`/api/database/${this.databaseId}/metadata/query/${this.queryId}`) + this.query = res.data + console.debug('query data', res.data) + this.data.metadata.title = res.data.title + this.loading = false + } catch (err) { + this.error = true + this.$toast.error('Could not load table data.') + } + }, + async submit () { + this.$refs.form.validate() + console.debug('form', this.data) + try { + this.loading = true + this.error = false + const res = await this.$axios.post(`/api/database/${this.databaseId}/cite/metadata`) + console.debug('create deposit', res.data) + this.loading = false + } catch (err) { + this.error = true + console.error('create deposit', err) + } + try { + this.loading = true + this.error = false + const res = await this.$axios.put(`/api/database/${this.databaseId}/cite/metadata/${this.queryId}`, { + metadata: this.data.metadata + }) + console.debug('update deposit', res.data) + this.loading = false + } catch (err) { + this.error = true + console.error('update deposit', err) + } + }, + addAuthor () { + this.data.metadata.creators.push({ + name: null, + affiliation: null, + orcid: null + }) + }, + removeAuthor (index) { + this.data.metadata.creators.splice(index, 1) + } } } </script> -<style> +<style lang="scss" scoped> +/* these are taked from solarized-light (plugins/vendors.js), to override the +main.scss file from vuetify, because it paints it red */ +::v-deep code { + background: #fdf6e3; + color: #657b83; +} + +.spacer { + display: flex; + flex: 0 1; +} + +#zenodo-logo { + background-size: cover; + background-position: center center; + background-color: #0656b4; + width: 5rem; +} </style> diff --git a/fda-ui/pages/databases/_database_id/queries/create.vue b/fda-ui/pages/databases/_database_id/queries/create.vue index c2390fb100fc31aae393c887670de537524e16b0..bc5d5868674b101da06512d55e4bd96509f6dfde 100644 --- a/fda-ui/pages/databases/_database_id/queries/create.vue +++ b/fda-ui/pages/databases/_database_id/queries/create.vue @@ -1,20 +1,22 @@ <template> <div> - <v-card class="pb-2"> - <v-card-title class="pb-0"> - Query Builder - </v-card-title> - <v-card-text> - <QueryBuilder /> - </v-card-text> - </v-card> + <QueryBuilder /> + <v-breadcrumbs :items="items" class="pa-0 mt-2" /> </div> </template> <script> export default { data () { - return {} + return { + items: [ + { text: 'Databases', href: '/databases' }, + { text: `${this.$route.params.database_id}`, href: `/databases/${this.$route.params.database_id}` }, + { text: 'Tables', href: `/databases/${this.$route.params.database_id}/tables` } + ] + } + }, + computed: { } } </script> diff --git a/fda-ui/pages/databases/_database_id/tables/_table_id/import.vue b/fda-ui/pages/databases/_database_id/tables/_table_id/import.vue index 94015f57d633ce1598c40f8a01e1e8ac9ab69df5..d199c99dcaccd08c83e0ab0ab5a1efa4323f87eb 100644 --- a/fda-ui/pages/databases/_database_id/tables/_table_id/import.vue +++ b/fda-ui/pages/databases/_database_id/tables/_table_id/import.vue @@ -2,13 +2,13 @@ <div> <v-card> <v-card-title v-if="!loading"> - Import CSV + Import Data </v-card-title> - <v-card-subtitle>Table xxx</v-card-subtitle> + <v-card-subtitle>{{ table.name }} ({{ table.internal_name }})</v-card-subtitle> <v-card-text> <v-checkbox v-model="tableInsert.skipHeader" - label="Skip first row" /> + label="First row contains headers" /> <v-text-field v-model="tableInsert.nullElement" placeholder="e.g. NA or leave empty" @@ -16,6 +16,8 @@ <v-text-field v-model="tableInsert.delimiter" label="Delimiter" + hint="Only 1 character" + maxlength="1" placeholder="e.g. ;" /> <v-file-input v-model="file" @@ -24,7 +26,9 @@ label="CSV File" /> </v-card-text> <v-card-actions> - <v-btn :disabled="!file" :loading="loading" color="primary" @click="upload">Next</v-btn> + <v-col> + <v-btn :disabled="!file" :loading="loading" color="primary" @click="upload">Next</v-btn> + </v-col> </v-card-actions> </v-card> </div> @@ -37,18 +41,42 @@ export default { data () { return { loading: false, + table: { + name: null, + internal_name: null + }, tableInsert: { skipHeader: false, nullElement: null, - delimiter: null, + delimiter: ',', csvLocation: null }, file: null } }, + computed: { + tableId () { + return this.$route.params.table_id + }, + databaseId () { + return this.$route.params.database_id + } + }, mounted () { + this.info() }, methods: { + async info () { + this.loading = true + const infoUrl = `/api/database/${this.databaseId}/table/${this.tableId}` + try { + const res = await this.$axios.get(infoUrl) + console.debug('got table', res.data) + this.table = res.data + } catch (err) { + console.error('Could not insert data.', err) + } + }, async upload () { this.loading = true const url = '/server-middleware/table_from_csv' @@ -63,15 +91,13 @@ export default { console.debug('upload csv', res.data) } else { console.error('Could not upload CSV data', res.data) - this.loading = false return } } catch (err) { console.error('Could not upload data.', err) - this.loading = false return } - const insertUrl = `/api/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data` + const insertUrl = `/api/database/${this.databaseId}/table/${this.tableId}/data` let insertResult try { insertResult = await this.$axios.post(insertUrl, this.tableInsert) diff --git a/fda-ui/pages/databases/_database_id/tables/create.vue b/fda-ui/pages/databases/_database_id/tables/create.vue index 4707864a0cbc58b33e3471db2fa4db405b2c2145..f4e1733caeba0bc66fc1470a143e323119f4fefa 100644 --- a/fda-ui/pages/databases/_database_id/tables/create.vue +++ b/fda-ui/pages/databases/_database_id/tables/create.vue @@ -1,9 +1,18 @@ <template> <form id="create_table" action="/" method="post" @submit="checkForm"> - <v-card class="pb-2"> - <v-card-title class="pb-0"> - Create Table - </v-card-title> + <v-progress-linear v-if="loading" :color="loadingColor" :indeterminate="!error" /> + <v-toolbar flat> + <v-toolbar-title> + <span>Create Table</span> + </v-toolbar-title> + <v-spacer /> + <v-toolbar-title> + <v-btn :disabled="!canCreateTable" color="primary" @click="createTable"> + Create Table + </v-btn> + </v-toolbar-title> + </v-toolbar> + <v-card flat> <v-card-text> <v-text-field v-model="name" @@ -14,8 +23,8 @@ v-model="description" label="Description" /> </v-card-text> - <v-card-text v-for="(c, idx) in columns" :key="idx" class="pa-3 mb-2"> - <v-row class="column pa-2 ml-1 mr-1"> + <v-card-text> + <v-row v-for="(c, idx) in columns" :key="idx" class="row-border mt-2"> <v-col cols="3"> <v-text-field v-model="c.name" required label="Name" /> </v-col> @@ -53,16 +62,14 @@ <v-icon>mdi-minus</v-icon> </v-btn> </v-row> + <v-row> + <v-col> + <v-btn @click="addColumn"> + Add Column + </v-btn> + </v-col> + </v-row> </v-card-text> - <v-card-actions> - <v-spacer /> - <v-btn @click="addColumn"> - Add Column - </v-btn> - <v-btn :disabled="!canCreateTable" color="primary" @click="createTable"> - Create Table - </v-btn> - </v-card-actions> </v-card> </form> </template> @@ -74,6 +81,8 @@ export default { columns: [], name: null, description: null, + loading: false, + error: false, columnTypes: [ { value: 'ENUM', text: 'ENUM' }, { value: 'BOOLEAN', text: 'BOOLEAN' }, @@ -85,6 +94,14 @@ export default { ] } }, + computed: { + databaseId () { + return this.$route.params.database_id + }, + loadingColor () { + return this.error ? 'red lighten-2' : 'primary' + } + }, mounted () { this.addColumn() }, @@ -140,14 +157,20 @@ export default { columns: this.columns } try { - const res = await this.$axios.post(`/api/database/${this.$route.params.database_id}/table`, data) + this.loading = true + const res = await this.$axios.post(`/api/database/${this.databaseId}/table`, data) if (res.status === 201) { + this.error = false this.$toast.success('Table created.') - this.$root.$emit('table-create', res.data) + // this.$root.$emit('table-create', res.data) + const tableId = res.data.id + await this.$router.push(`/databases/${this.databaseId}/tables/${tableId}/import`) } else { + this.error = true this.$toast.error(`Could not create table: status ${res.status}`) } } catch (err) { + this.error = true this.$toast.error('Could not create table.') } } @@ -156,8 +179,9 @@ export default { </script> <style> -.column { +.row-border { border: 1px solid #ccc; border-radius: 3px; + margin: 0 !important; } </style> diff --git a/fda-ui/pages/databases/_database_id/tables/import.vue b/fda-ui/pages/databases/_database_id/tables/import.vue index cd458c37220fac34557c7ff3901f0e1cf321f7bb..3d40e0cd902f5b65b21d1e59ccb81905df4a1e83 100644 --- a/fda-ui/pages/databases/_database_id/tables/import.vue +++ b/fda-ui/pages/databases/_database_id/tables/import.vue @@ -183,10 +183,12 @@ export default { this.fileLocation = res.data.file.filename this.tableInsert.csvLocation = this.fileLocation this.step = 3 + this.loading = false console.debug('upload csv', res.data) } else { console.error('Upload failed. Try from docker container, not with yarn dev', res) this.$toast.error('Could not upload CSV data') + this.loading = false return } } catch (err) { diff --git a/fda-ui/pages/databases/_database_id/tables/index.vue b/fda-ui/pages/databases/_database_id/tables/index.vue index 2458e88c18ca0a7c211287d8912366bc7ce7d14f..f1bb967f814045c19c407576947fe4e74837d2b1 100644 --- a/fda-ui/pages/databases/_database_id/tables/index.vue +++ b/fda-ui/pages/databases/_database_id/tables/index.vue @@ -1,7 +1,9 @@ <template> <div> - <DBToolbar v-model="db" /> - <TableList /> + <DBToolbar /> + <v-tabs-items v-model="tab"> + <TableList /> + </v-tabs-items> </div> </template> <script> @@ -19,6 +21,11 @@ export default { db: null } }, + computed: { + tab () { + return 1 + } + }, mounted () { }, methods: { diff --git a/fda-ui/pages/databases/index.vue b/fda-ui/pages/databases/index.vue index 2998e293fd4f062fd347db29427267eab0fa19ea..84d7eb82d3ad5ceb986e20f4eaed8246ac3fdf74 100644 --- a/fda-ui/pages/databases/index.vue +++ b/fda-ui/pages/databases/index.vue @@ -1,63 +1,58 @@ <template> - <v-card> - <v-card-title> - <span>Databases</span> - <v-progress-circular v-if="loading" :size="20" :width="3" indeterminate color="primary" /> - </v-card-title> - <v-card-subtitle> - All public databases found in the metadata database. - </v-card-subtitle> - <v-simple-table> - <template v-slot:default> - <thead> - <tr> - <th>Name</th> - <th>Description</th> - <th>Engine</th> - <th>Created</th> - </tr> - </thead> - <tbody> - <tr v-if="databases.length === 0" aria-readonly="true"> - <td colspan="4"> - <span v-if="!loading">(no databases)</span> - </td> - </tr> - <tr - v-for="item in databases" - :key="item.id"> - <td> - <v-btn :to="`/databases/${item.id}/info`" icon> - <v-icon>{{ iconSelect }}</v-icon> - </v-btn> - {{ item.name }} - </td> - <!-- <td> - {{ formatDate(item.Created) }}<br> - <span class="color-grey"> - ({{ relativeDate(item.Created) }}) - </span> - </td> --> - <td>{{ item.description }}</td> - <td>{{ item.engine }}</td> - <td>{{ item.created }}</td> - </tr> - </tbody> - </template> - </v-simple-table> - <v-btn class="float-right mt-3" color="primary" @click.stop="createDbDialog = true"> - <v-icon class="mr-1"> - mdi-plus - </v-icon> - Create Database - </v-btn> - <v-dialog - v-model="createDbDialog" - persistent - max-width="640"> - <CreateDB @refresh="refresh" /> - </v-dialog> - </v-card> + <div> + <v-progress-linear v-if="loading" :color="loadingColor" :indeterminate="!error" /> + <v-toolbar flat> + <v-toolbar-title> + <span>Databases</span> + </v-toolbar-title> + <v-spacer /> + <v-toolbar-title> + <v-btn color="primary" @click.stop="createDbDialog = true"> + <v-icon left>mdi-plus</v-icon> Database + </v-btn> + </v-toolbar-title> + </v-toolbar> + <v-card flat> + <v-simple-table> + <template v-slot:default> + <thead> + <tr> + <th>Name</th> + <th>Description</th> + <th>Engine</th> + <th>Created</th> + </tr> + </thead> + <tbody> + <tr v-if="databases.length === 0" aria-readonly="true"> + <td colspan="4"> + <span v-if="!loading">(no databases)</span> + </td> + </tr> + <tr + v-for="item in databases" + :key="item.id"> + <td> + <v-btn :to="`/databases/${item.id}/info`" icon> + <v-icon>{{ iconSelect }}</v-icon> + </v-btn> + {{ item.name }} + </td> + <td>{{ item.description }}</td> + <td>{{ item.engine }}</td> + <td>{{ item.created }}</td> + </tr> + </tbody> + </template> + </v-simple-table> + <v-dialog + v-model="createDbDialog" + persistent + max-width="640"> + <CreateDB @refresh="refresh" /> + </v-dialog> + </v-card> + </div> </template> <script> import { mdiDatabaseArrowRightOutline } from '@mdi/js' @@ -74,20 +69,32 @@ export default { createDbDialog: false, databases: [], loading: true, + error: false, iconSelect: mdiDatabaseArrowRightOutline } }, + computed: { + loadingColor () { + return this.error ? 'red lighten-2' : 'primary' + } + }, mounted () { this.refresh() }, methods: { async refresh () { this.createDbDialog = false - this.loading = true - const res = await this.$axios.get('/api/database/') - this.databases = res.data - this.loading = false - console.debug('databases', res.data) + try { + this.loading = true + const res = await this.$axios.get('/api/database/') + this.databases = res.data + this.loading = false + this.error = false + console.debug('databases', res.data) + } catch (err) { + console.error('databases', err) + this.error = true + } }, trim (s) { return s.slice(0, 12) diff --git a/fda-ui/pages/index.vue b/fda-ui/pages/index.vue index ba736fe46d9de9f8373dab7a5b5796fc076e7453..34eaae9bde767c6c94d8cc6a9c3f056c7fecb224 100644 --- a/fda-ui/pages/index.vue +++ b/fda-ui/pages/index.vue @@ -1,9 +1,18 @@ <template> - <v-row justify="center" align="center"> - <v-col cols="12" sm="8" md="6"> - Welcome - </v-col> - </v-row> + <div> + <v-toolbar flat> + <v-toolbar-title>Welcome</v-toolbar-title> + </v-toolbar> + <v-card flat> + <v-card-title>FAIR Data</v-card-title> + <v-card-subtitle> + Findable, Accessible, Interoperable, Reusable + </v-card-subtitle> + <v-card-text> + text + </v-card-text> + </v-card> + </div> </template> <script> diff --git a/fda-ui/server-middleware/index.js b/fda-ui/server-middleware/index.js index 7e760972f52bfc4b1338d10a2c6bc36e3398d2e7..08ccd859f6d5da5d2180d075d9eadae114f9fb0e 100644 --- a/fda-ui/server-middleware/index.js +++ b/fda-ui/server-middleware/index.js @@ -26,15 +26,19 @@ app.post('/table_from_csv', upload.single('file'), async (req, res) => { // send path to analyse service let analysis try { - analysis = await fetch(`${process.env.API_ANALYSE}/determinedt`, { + analysis = await fetch(`${process.env.API}/api/analyse/determinedt`, { method: 'post', body: JSON.stringify({ filepath: path }), headers: { 'Content-Type': 'application/json' } }) analysis = await analysis.json() - analysis = JSON.parse(analysis) - console.debug('analyzed', analysis) + if (!analysis.success) { + console.error('Failed to determine datatypes', analysis.message) + return res.json({ success: false, message: analysis.message }) + } + // analysis = JSON.parse(analysis) } catch (error) { + console.error('failed to analyze', error) return res.json({ success: false, error }) } diff --git a/fda-ui/server-middleware/ready.js b/fda-ui/server-middleware/ready.js new file mode 100644 index 0000000000000000000000000000000000000000..cfa20be3239b5ecd4e8a81c090e97880c84bd7bb --- /dev/null +++ b/fda-ui/server-middleware/ready.js @@ -0,0 +1,10 @@ +import path from 'path' +const fs = require('fs') + +fs.closeSync(fs.openSync(path.resolve(__dirname, '../ready'), 'w')) + +// Since we are a serverMiddleware, we have to return a handler, even if this it does nothing +// I think this is really ugly... +export default function (req, res, next) { + next() +} diff --git a/fda-ui/test/e2e/database.js b/fda-ui/test/e2e/database.js index 8e117f37d687492ff695ea8cb9a051976e2ba689..1fc468e4c9d8e492f43029c7c9ec7e682126d82b 100644 --- a/fda-ui/test/e2e/database.js +++ b/fda-ui/test/e2e/database.js @@ -11,7 +11,7 @@ test('create database', pageMacro, async (t, page) => { await page.go('/databases') // Click create new button - await page.click('button:has-text("Create Database")') + await page.click('button:has-text("Database")') // Fill database name await page.fill('input[name="database"]', database)